mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 08:26:30 +00:00
make tdcall and tdvmcall public and polish code
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
12fc074f56
commit
d7710207bb
@ -8,18 +8,18 @@ pub mod asm;
|
|||||||
pub mod tdcall;
|
pub mod tdcall;
|
||||||
pub mod tdvmcall;
|
pub mod tdvmcall;
|
||||||
|
|
||||||
pub use self::tdcall::{deadloop, tdg_vp_veinfo_get, TdxVirtualExceptionType};
|
pub use self::tdcall::{get_veinfo, TdxVirtualExceptionType};
|
||||||
pub use self::tdvmcall::print;
|
pub use self::tdvmcall::print;
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
use raw_cpuid::{native_cpuid::cpuid_count, CpuIdResult};
|
use raw_cpuid::{native_cpuid::cpuid_count, CpuIdResult};
|
||||||
use tdcall::{tdg_vp_vmcall, InitError, TdgVeInfo, TdgVpInfo};
|
use tdcall::{InitError, TdgVeInfo, TdgVpInfo};
|
||||||
|
use tdvmcall::*;
|
||||||
|
|
||||||
const TDX_CPUID_LEAF_ID: u64 = 0x21;
|
const TDX_CPUID_LEAF_ID: u64 = 0x21;
|
||||||
|
|
||||||
pub fn tdx_early_init() -> Result<TdgVpInfo, InitError> {
|
pub fn tdx_early_init() -> Result<TdgVpInfo, InitError> {
|
||||||
match is_tdx_guest() {
|
match is_tdx_guest() {
|
||||||
Ok(_) => Ok(tdcall::tdg_vp_info()?),
|
Ok(_) => Ok(tdcall::get_tdinfo()?),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,9 +30,9 @@ fn is_tdx_guest() -> Result<(), InitError> {
|
|||||||
return Err(InitError::TdxCpuLeafIdError);
|
return Err(InitError::TdxCpuLeafIdError);
|
||||||
}
|
}
|
||||||
let cpuid_result: CpuIdResult = cpuid_count(TDX_CPUID_LEAF_ID as u32, 0);
|
let cpuid_result: CpuIdResult = cpuid_count(TDX_CPUID_LEAF_ID as u32, 0);
|
||||||
if convert_ascii(cpuid_result.ebx) == "Inte"
|
if &cpuid_result.ebx.to_ne_bytes() == b"Inte"
|
||||||
&& convert_ascii(cpuid_result.edx) == "lTDX"
|
&& &cpuid_result.ebx.to_ne_bytes() == b"lTDX"
|
||||||
&& convert_ascii(cpuid_result.ecx) == " "
|
&& &cpuid_result.ecx.to_ne_bytes() == b" "
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -40,16 +40,6 @@ fn is_tdx_guest() -> Result<(), InitError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_ascii(reg: u32) -> String {
|
|
||||||
let bytes = [
|
|
||||||
(reg & 0xFF) as u8,
|
|
||||||
((reg >> 8) & 0xFF) as u8,
|
|
||||||
((reg >> 16) & 0xFF) as u8,
|
|
||||||
((reg >> 24) & 0xFF) as u8,
|
|
||||||
];
|
|
||||||
String::from_utf8_lossy(&bytes).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TdxTrapFrame {
|
pub trait TdxTrapFrame {
|
||||||
fn rax(&self) -> usize;
|
fn rax(&self) -> usize;
|
||||||
fn set_rax(&mut self, rax: usize);
|
fn set_rax(&mut self, rax: usize);
|
||||||
@ -69,13 +59,35 @@ pub trait TdxTrapFrame {
|
|||||||
|
|
||||||
pub fn virtual_exception_handler(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) {
|
pub fn virtual_exception_handler(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) {
|
||||||
match ve_info.exit_reason.into() {
|
match ve_info.exit_reason.into() {
|
||||||
TdxVirtualExceptionType::Hlt
|
TdxVirtualExceptionType::Hlt => {
|
||||||
| TdxVirtualExceptionType::Io
|
serial_println!("Ready to halt");
|
||||||
| TdxVirtualExceptionType::MsrRead
|
hlt();
|
||||||
| TdxVirtualExceptionType::MsrWrite
|
}
|
||||||
| TdxVirtualExceptionType::CpuId => tdg_vp_vmcall(trapframe, ve_info),
|
TdxVirtualExceptionType::Io => {
|
||||||
|
if !handle_io(trapframe, ve_info) {
|
||||||
|
serial_println!("Handle tdx ioexit errors, ready to halt");
|
||||||
|
hlt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::MsrRead => {
|
||||||
|
let msr = rdmsr(trapframe.rcx() as u32).unwrap();
|
||||||
|
trapframe.set_rax((msr as u32 & u32::MAX) as usize);
|
||||||
|
trapframe.set_rdx(((msr >> 32) as u32 & u32::MAX) as usize);
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::MsrWrite => {
|
||||||
|
let data = trapframe.rax() as u64 | ((trapframe.rdx() as u64) << 32);
|
||||||
|
wrmsr(trapframe.rcx() as u32, data).unwrap();
|
||||||
|
}
|
||||||
|
TdxVirtualExceptionType::CpuId => {
|
||||||
|
let cpuid_info = cpuid(trapframe.rax() as u32, trapframe.rcx() as u32).unwrap();
|
||||||
|
let mask = 0xFFFF_FFFF_0000_0000_usize;
|
||||||
|
trapframe.set_rax((trapframe.rax() & mask) | cpuid_info.eax);
|
||||||
|
trapframe.set_rbx((trapframe.rbx() & mask) | cpuid_info.ebx);
|
||||||
|
trapframe.set_rcx((trapframe.rcx() & mask) | cpuid_info.ecx);
|
||||||
|
trapframe.set_rdx((trapframe.rdx() & mask) | cpuid_info.edx);
|
||||||
|
}
|
||||||
TdxVirtualExceptionType::Other => panic!("Unknown TDX vitrual exception type"),
|
TdxVirtualExceptionType::Other => panic!("Unknown TDX vitrual exception type"),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
}
|
||||||
trapframe.set_rip(trapframe.rip() + ve_info.exit_instruction_length as usize);
|
trapframe.set_rip(trapframe.rip() + ve_info.exit_instruction_length as usize);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,34 @@
|
|||||||
use super::tdvmcall::*;
|
//! The TDCALL instruction causes a VM exit to the Intel TDX module.
|
||||||
use crate::{asm::asm_td_call, serial_println, TdxTrapFrame};
|
//! It is used to call guest-side Intel TDX functions. For more information about
|
||||||
|
//! TDCALL, please refer to the [Intel® TDX Module v1.5 ABI Specification](https://cdrdv2.intel.com/v1/dl/getContent/733579)
|
||||||
|
|
||||||
|
use crate::asm::asm_td_call;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
const TDCALL_VP_INFO: u64 = 1;
|
/// TDCALL Instruction Leaf Numbers Definition.
|
||||||
const TDCALL_MR_RTMR_EXTEND: u64 = 2;
|
#[repr(u64)]
|
||||||
const TDCALL_VP_VEINFO_GET: u64 = 3;
|
pub enum TdcallNum {
|
||||||
const TDCALL_MR_REPORT: u64 = 4;
|
VpInfo = 1,
|
||||||
const TDCALL_VP_CPUIDVE_SET: u64 = 5;
|
MrRtmrExtend = 2,
|
||||||
const TDCALL_MEM_PAGE_ACCEPT: u64 = 6;
|
VpVeinfoGet = 3,
|
||||||
const TDCALL_VM_RD: u64 = 7;
|
MrReport = 4,
|
||||||
const TDCALL_VM_WR: u64 = 8;
|
VpCpuidveSet = 5,
|
||||||
const TDCALL_MR_VERIFYREPORT: u64 = 22;
|
MemPageAccept = 6,
|
||||||
const TDCALL_MEM_PAGE_ATTR_RD: u64 = 23;
|
VmRd = 7,
|
||||||
const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24;
|
VmWr = 8,
|
||||||
|
MrVerifyreport = 22,
|
||||||
|
MemPageAttrRd = 23,
|
||||||
|
MemPageAttrWr = 24,
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct Attributes: u64 {
|
/// GuestTdAttributes is defined as a 64b field that specifies various guest TD attributes.
|
||||||
|
/// It is reported to the guest TD by TDG.VP.INFO and as part of TDREPORT_STRUCT returned by TDG.MR.REPORT.
|
||||||
|
pub struct GuestTdAttributes: u64 {
|
||||||
/// Guest TD runs in off-TD debug mode.
|
/// Guest TD runs in off-TD debug mode.
|
||||||
/// Its VCPU state and private memory are accessible by the host VMM.
|
/// Its VCPU state and private memory are accessible by the host VMM.
|
||||||
const DEBUG = 1;
|
const DEBUG = 1 << 0;
|
||||||
/// TD is migratable (using a Migration TD).
|
/// TD is migratable (using a Migration TD).
|
||||||
const MIGRATABLE = 1 << 29;
|
const MIGRATABLE = 1 << 29;
|
||||||
/// TD is allowed to use Supervisor Protection Keys.
|
/// TD is allowed to use Supervisor Protection Keys.
|
||||||
@ -36,7 +45,7 @@ bitflags! {
|
|||||||
struct CpuidveFlag: u64 {
|
struct CpuidveFlag: u64 {
|
||||||
/// Flags that when CPL is 0, a CPUID executed
|
/// Flags that when CPL is 0, a CPUID executed
|
||||||
/// by the guest TD will cause a #VE unconditionally.
|
/// by the guest TD will cause a #VE unconditionally.
|
||||||
const SUPERVISOR = 1;
|
const SUPERVISOR = 1 << 0;
|
||||||
/// Flags that when CPL > 0, a CPUID executed
|
/// Flags that when CPL > 0, a CPUID executed
|
||||||
/// by the guest TD will cause a #VE unconditionally.
|
/// by the guest TD will cause a #VE unconditionally.
|
||||||
const USER = 1 << 1;
|
const USER = 1 << 1;
|
||||||
@ -254,7 +263,7 @@ pub struct TdgVpInfo {
|
|||||||
/// Only GPAW values 48 and 52 are possible.
|
/// Only GPAW values 48 and 52 are possible.
|
||||||
pub gpaw: Gpaw,
|
pub gpaw: Gpaw,
|
||||||
/// The TD's ATTRIBUTES (provided as input to TDH.MNG.INIT)
|
/// The TD's ATTRIBUTES (provided as input to TDH.MNG.INIT)
|
||||||
pub attributes: Attributes,
|
pub attributes: GuestTdAttributes,
|
||||||
pub num_vcpus: u32,
|
pub num_vcpus: u32,
|
||||||
pub max_vcpus: u32,
|
pub max_vcpus: u32,
|
||||||
pub vcpu_index: u32,
|
pub vcpu_index: u32,
|
||||||
@ -350,16 +359,16 @@ impl From<TdCallError> for InitError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get guest TD execution environment information.
|
/// Get guest TD execution environment information.
|
||||||
pub(crate) fn tdg_vp_info() -> Result<TdgVpInfo, TdCallError> {
|
pub fn get_tdinfo() -> Result<TdgVpInfo, TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_VP_INFO,
|
rax: TdcallNum::VpInfo as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
match td_call(&mut args) {
|
match td_call(&mut args) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
let td_info = TdgVpInfo {
|
let td_info = TdgVpInfo {
|
||||||
gpaw: Gpaw::from(args.rcx),
|
gpaw: Gpaw::from(args.rcx),
|
||||||
attributes: Attributes::from_bits_truncate(args.rdx),
|
attributes: GuestTdAttributes::from_bits_truncate(args.rdx),
|
||||||
num_vcpus: args.r8 as u32,
|
num_vcpus: args.r8 as u32,
|
||||||
max_vcpus: (args.r8 >> 32) as u32,
|
max_vcpus: (args.r8 >> 32) as u32,
|
||||||
vcpu_index: args.r9 as u32,
|
vcpu_index: args.r9 as u32,
|
||||||
@ -372,9 +381,9 @@ pub(crate) fn tdg_vp_info() -> Result<TdgVpInfo, TdCallError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get Virtualization Exception Information for the recent #VE exception.
|
/// Get Virtualization Exception Information for the recent #VE exception.
|
||||||
pub fn tdg_vp_veinfo_get() -> Result<TdgVeInfo, TdCallError> {
|
pub fn get_veinfo() -> Result<TdgVeInfo, TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_VP_VEINFO_GET,
|
rax: TdcallNum::VpVeinfoGet as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
match td_call(&mut args) {
|
match td_call(&mut args) {
|
||||||
@ -393,64 +402,10 @@ pub fn tdg_vp_veinfo_get() -> Result<TdgVeInfo, TdCallError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a TD Exit to the host VMM.
|
|
||||||
pub(crate) fn tdg_vp_vmcall(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) {
|
|
||||||
match ve_info.exit_reason.into() {
|
|
||||||
TdxVirtualExceptionType::Hlt => {
|
|
||||||
serial_println!("Ready to halt");
|
|
||||||
tdvmcall_hlt();
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::Io => {
|
|
||||||
if !tdvmcall_io(trapframe, ve_info) {
|
|
||||||
serial_println!("Handle tdx ioexit errors, ready to halt");
|
|
||||||
tdvmcall_hlt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::MsrRead => {
|
|
||||||
let msr = tdvmcall_rdmsr(trapframe.rcx() as u32).unwrap();
|
|
||||||
trapframe.set_rax((msr as u32 & u32::MAX) as usize);
|
|
||||||
trapframe.set_rdx(((msr >> 32) as u32 & u32::MAX) as usize);
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::MsrWrite => {
|
|
||||||
let data = trapframe.rax() as u64 | ((trapframe.rdx() as u64) << 32);
|
|
||||||
tdvmcall_wrmsr(trapframe.rcx() as u32, data).unwrap();
|
|
||||||
}
|
|
||||||
TdxVirtualExceptionType::CpuId => {
|
|
||||||
let cpuid = tdvmcall_cpuid(trapframe.rax() as u32, trapframe.rcx() as u32).unwrap();
|
|
||||||
let mask = 0xFFFF_FFFF_0000_0000_usize;
|
|
||||||
trapframe.set_rax((trapframe.rax() & mask) | cpuid.eax);
|
|
||||||
trapframe.set_rbx((trapframe.rbx() & mask) | cpuid.ebx);
|
|
||||||
trapframe.set_rcx((trapframe.rcx() & mask) | cpuid.ecx);
|
|
||||||
trapframe.set_rdx((trapframe.rdx() & mask) | cpuid.edx);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn deadloop() {
|
|
||||||
#[allow(clippy::empty_loop)]
|
|
||||||
loop {
|
|
||||||
x86_64::instructions::interrupts::enable();
|
|
||||||
x86_64::instructions::hlt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn td_call(args: &mut TdcallArgs) -> Result<(), TdCallError> {
|
|
||||||
let td_call_result = unsafe { asm_td_call(args) };
|
|
||||||
if td_call_result == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(td_call_result.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extend a TDCS.RTMR measurement register.
|
/// Extend a TDCS.RTMR measurement register.
|
||||||
fn tdg_mr_rtmr_extend() -> Result<(), TdCallError> {
|
pub fn extend_rtmr() -> Result<(), TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_MR_RTMR_EXTEND,
|
rax: TdcallNum::MrRtmrExtend as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
match td_call(&mut args) {
|
match td_call(&mut args) {
|
||||||
@ -462,9 +417,9 @@ fn tdg_mr_rtmr_extend() -> Result<(), TdCallError> {
|
|||||||
/// TDG.MR.REPORT creates a TDREPORT_STRUCT structure that contains the measurements/configuration
|
/// TDG.MR.REPORT creates a TDREPORT_STRUCT structure that contains the measurements/configuration
|
||||||
/// information of the guest TD that called the function, measurements/configuration information
|
/// information of the guest TD that called the function, measurements/configuration information
|
||||||
/// of the Intel TDX module and a REPORTMACSTRUCT.
|
/// of the Intel TDX module and a REPORTMACSTRUCT.
|
||||||
fn tdg_mr_report(report_addr: u64, data_addr: u64) -> Result<(), TdCallError> {
|
pub fn get_report(report_addr: u64, data_addr: u64) -> Result<(), TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_MR_REPORT,
|
rax: TdcallNum::MrReport as u64,
|
||||||
rcx: report_addr,
|
rcx: report_addr,
|
||||||
rdx: data_addr,
|
rdx: data_addr,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -477,9 +432,9 @@ fn tdg_mr_report(report_addr: u64, data_addr: u64) -> Result<(), TdCallError> {
|
|||||||
|
|
||||||
/// Verify a cryptographic REPORTMACSTRUCT that describes the contents of a TD,
|
/// Verify a cryptographic REPORTMACSTRUCT that describes the contents of a TD,
|
||||||
/// to determine that it was created on the current TEE on the current platform.
|
/// to determine that it was created on the current TEE on the current platform.
|
||||||
fn tdg_mr_verifyreport(report_mac_addr: u64) -> Result<(), TdCallError> {
|
pub fn verify_report(report_mac_addr: u64) -> Result<(), TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_MR_VERIFYREPORT,
|
rax: TdcallNum::MrVerifyreport as u64,
|
||||||
rcx: report_mac_addr,
|
rcx: report_mac_addr,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -490,9 +445,9 @@ fn tdg_mr_verifyreport(report_mac_addr: u64) -> Result<(), TdCallError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Accept a pending private page and initialize it to all-0 using the TD ephemeral private key.
|
/// Accept a pending private page and initialize it to all-0 using the TD ephemeral private key.
|
||||||
fn tdg_mem_page_accept(sept_level: u64, addr: u64) -> Result<(), TdCallError> {
|
pub fn accept_page(sept_level: u64, addr: u64) -> Result<(), TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_MEM_PAGE_ACCEPT,
|
rax: TdcallNum::MemPageAccept as u64,
|
||||||
rcx: sept_level | (addr << 12),
|
rcx: sept_level | (addr << 12),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -503,9 +458,9 @@ fn tdg_mem_page_accept(sept_level: u64, addr: u64) -> Result<(), TdCallError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read the GPA mapping and attributes of a TD private page.
|
/// Read the GPA mapping and attributes of a TD private page.
|
||||||
fn tdg_mem_page_attr_rd(phy_addr: u64) -> Result<PageAttr, TdCallError> {
|
pub fn read_page_attr(phy_addr: u64) -> Result<PageAttr, TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_MEM_PAGE_ATTR_RD,
|
rax: TdcallNum::MemPageAttrRd as u64,
|
||||||
rcx: phy_addr,
|
rcx: phy_addr,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -522,9 +477,9 @@ fn tdg_mem_page_attr_rd(phy_addr: u64) -> Result<PageAttr, TdCallError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write the attributes of a private page. Create or remove L2 page aliases as required.
|
/// Write the attributes of a private page. Create or remove L2 page aliases as required.
|
||||||
fn tdg_mem_page_attr_wr(page_attr: PageAttr, attr_flags: u64) -> Result<PageAttr, TdCallError> {
|
pub fn write_page_attr(page_attr: PageAttr, attr_flags: u64) -> Result<PageAttr, TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_MEM_PAGE_ATTR_WR,
|
rax: TdcallNum::MemPageAttrWr as u64,
|
||||||
rcx: page_attr.gpa_mapping,
|
rcx: page_attr.gpa_mapping,
|
||||||
rdx: u64::from(page_attr.gpa_attr),
|
rdx: u64::from(page_attr.gpa_attr),
|
||||||
r8: attr_flags,
|
r8: attr_flags,
|
||||||
@ -543,9 +498,9 @@ fn tdg_mem_page_attr_wr(page_attr: PageAttr, attr_flags: u64) -> Result<PageAttr
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a TD-scope metadata field (control structure field) of a TD.
|
/// Read a TD-scope metadata field (control structure field) of a TD.
|
||||||
fn tdg_vm_rd(field_identifier: u64) -> Result<u64, TdCallError> {
|
pub fn read_td_metadata(field_identifier: u64) -> Result<u64, TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_VM_RD,
|
rax: TdcallNum::VmRd as u64,
|
||||||
rdx: field_identifier,
|
rdx: field_identifier,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -563,18 +518,19 @@ fn tdg_vm_rd(field_identifier: u64) -> Result<u64, TdCallError> {
|
|||||||
/// in R8 are to be written to the field.
|
/// in R8 are to be written to the field.
|
||||||
///
|
///
|
||||||
/// It returns previous contents of the field.
|
/// It returns previous contents of the field.
|
||||||
fn tdg_vm_wr(field_identifier: u64, data: u64, write_mask: u64) -> Result<u64, TdCallError> {
|
pub fn write_td_metadata(
|
||||||
|
field_identifier: u64,
|
||||||
|
data: u64,
|
||||||
|
write_mask: u64,
|
||||||
|
) -> Result<u64, TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_VM_WR,
|
rax: TdcallNum::VmWr as u64,
|
||||||
rdx: field_identifier,
|
rdx: field_identifier,
|
||||||
r8: data,
|
r8: data,
|
||||||
r9: write_mask,
|
r9: write_mask,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
match td_call(&mut args) {
|
td_call(&mut args).map(|_| args.r8)
|
||||||
Ok(()) => Ok(args.r8),
|
|
||||||
Err(res) => Err(res),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TDG.VP.CPUIDVE.SET controls unconditional #VE on CPUID execution by the guest TD.
|
/// TDG.VP.CPUIDVE.SET controls unconditional #VE on CPUID execution by the guest TD.
|
||||||
@ -583,9 +539,9 @@ fn tdg_vm_wr(field_identifier: u64, data: u64, write_mask: u64) -> Result<u64, T
|
|||||||
///
|
///
|
||||||
/// The guest TD may control the same settings by writing to the
|
/// The guest TD may control the same settings by writing to the
|
||||||
/// VCPU-scope metadata fields CPUID_SUPERVISOR_VE and CPUID_USER_VE using TDG.VP.WR.
|
/// VCPU-scope metadata fields CPUID_SUPERVISOR_VE and CPUID_USER_VE using TDG.VP.WR.
|
||||||
fn tdg_vp_cpuidve_set(cpuidve_flag: u64) -> Result<(), TdCallError> {
|
pub fn set_cpuidve(cpuidve_flag: u64) -> Result<(), TdCallError> {
|
||||||
let mut args = TdcallArgs {
|
let mut args = TdcallArgs {
|
||||||
rax: TDCALL_VP_CPUIDVE_SET,
|
rax: TdcallNum::VpCpuidveSet as u64,
|
||||||
rcx: cpuidve_flag,
|
rcx: cpuidve_flag,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -594,3 +550,12 @@ fn tdg_vp_cpuidve_set(cpuidve_flag: u64) -> Result<(), TdCallError> {
|
|||||||
Err(res) => Err(res),
|
Err(res) => Err(res),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn td_call(args: &mut TdcallArgs) -> Result<(), TdCallError> {
|
||||||
|
let td_call_result = unsafe { asm_td_call(args) };
|
||||||
|
if td_call_result == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(td_call_result.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
//! The TDVMCALL helps invoke services from the host VMM. From the perspective of the host VMM, the TDVMCALL is a trap-like, VM exit into
|
||||||
|
//! the host VMM, reported via the SEAMRET instruction flow.
|
||||||
|
//! By design, after the SEAMRET, the host VMM services the request specified in the parameters
|
||||||
|
//! passed by the TD during the TDG.VP.VMCALL (that are passed via SEAMRET to the VMM), then
|
||||||
|
//! resumes the TD via a SEAMCALL [TDH.VP.ENTER] invocation.
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use crate::{asm::asm_td_vmcall, tdcall::TdgVeInfo, TdxTrapFrame};
|
use crate::{asm::asm_td_vmcall, tdcall::TdgVeInfo, TdxTrapFrame};
|
||||||
@ -9,15 +14,19 @@ use x86_64::{
|
|||||||
structures::port::PortRead,
|
structures::port::PortRead,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TDVMCALL_CPUID: u64 = 0x0000a;
|
/// TDVMCALL Instruction Leaf Numbers Definition.
|
||||||
const TDVMCALL_HLT: u64 = 0x0000c;
|
#[repr(u64)]
|
||||||
const TDVMCALL_IO: u64 = 0x0001e;
|
pub enum TdvmcallNum {
|
||||||
const TDVMCALL_RDMSR: u64 = 0x0001f;
|
Cpuid = 0x0000a,
|
||||||
const TDVMCALL_WRMSR: u64 = 0x00020;
|
Hlt = 0x0000c,
|
||||||
const TDVMCALL_REQUEST_MMIO: u64 = 0x00030;
|
Io = 0x0001e,
|
||||||
const TDVMCALL_WBINVD: u64 = 0x00036;
|
Rdmsr = 0x0001f,
|
||||||
const TDVMCALL_PCONFIG: u64 = 0x00041;
|
Wrmsr = 0x00020,
|
||||||
const TDVMCALL_MAPGPA: u64 = 0x10001;
|
RequestMmio = 0x00030,
|
||||||
|
Wbinvd = 0x00036,
|
||||||
|
Pconfig = 0x00041,
|
||||||
|
Mapgpa = 0x10001,
|
||||||
|
}
|
||||||
|
|
||||||
const SERIAL_IO_PORT: u16 = 0x3F8;
|
const SERIAL_IO_PORT: u16 = 0x3F8;
|
||||||
const SERIAL_LINE_STS: u16 = 0x3FD;
|
const SERIAL_LINE_STS: u16 = 0x3FD;
|
||||||
@ -62,26 +71,26 @@ pub(crate) struct TdVmcallArgs {
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct CpuIdInfo {
|
pub struct CpuIdInfo {
|
||||||
pub eax: usize,
|
pub eax: usize,
|
||||||
pub ebx: usize,
|
pub ebx: usize,
|
||||||
pub ecx: usize,
|
pub ecx: usize,
|
||||||
pub edx: usize,
|
pub edx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Direction {
|
pub enum Direction {
|
||||||
In,
|
In,
|
||||||
Out,
|
Out,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Operand {
|
pub enum Operand {
|
||||||
Dx,
|
Dx,
|
||||||
Immediate,
|
Immediate,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_cpuid(eax: u32, ecx: u32) -> Result<CpuIdInfo, TdVmcallError> {
|
pub fn cpuid(eax: u32, ecx: u32) -> Result<CpuIdInfo, TdVmcallError> {
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_CPUID,
|
r11: TdvmcallNum::Cpuid as u64,
|
||||||
r12: eax as u64,
|
r12: eax as u64,
|
||||||
r13: ecx as u64,
|
r13: ecx as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -97,19 +106,19 @@ pub(crate) fn tdvmcall_cpuid(eax: u32, ecx: u32) -> Result<CpuIdInfo, TdVmcallEr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_hlt() {
|
pub fn hlt() {
|
||||||
let interrupt_blocked = !rflags::read().contains(RFlags::INTERRUPT_FLAG);
|
let interrupt_blocked = !rflags::read().contains(RFlags::INTERRUPT_FLAG);
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_HLT,
|
r11: TdvmcallNum::Hlt as u64,
|
||||||
r12: interrupt_blocked as u64,
|
r12: interrupt_blocked as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let _ = td_vmcall(&mut args);
|
let _ = td_vmcall(&mut args);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_rdmsr(index: u32) -> Result<u64, TdVmcallError> {
|
pub fn rdmsr(index: u32) -> Result<u64, TdVmcallError> {
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_RDMSR,
|
r11: TdvmcallNum::Rdmsr as u64,
|
||||||
r12: index as u64,
|
r12: index as u64,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -119,9 +128,9 @@ pub(crate) fn tdvmcall_rdmsr(index: u32) -> Result<u64, TdVmcallError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> {
|
pub fn wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> {
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_WRMSR,
|
r11: TdvmcallNum::Wrmsr as u64,
|
||||||
r12: index as u64,
|
r12: index as u64,
|
||||||
r13: value,
|
r13: value,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -133,9 +142,9 @@ pub(crate) fn tdvmcall_wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Used to help perform WBINVD operation.
|
/// Used to help perform WBINVD operation.
|
||||||
pub(crate) fn tdvmcall_wbinvd(wbinvd: u64) -> Result<(), TdVmcallError> {
|
pub fn wbinvd(wbinvd: u64) -> Result<(), TdVmcallError> {
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_WBINVD,
|
r11: TdvmcallNum::Wbinvd as u64,
|
||||||
r12: wbinvd,
|
r12: wbinvd,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -145,13 +154,13 @@ pub(crate) fn tdvmcall_wbinvd(wbinvd: u64) -> Result<(), TdVmcallError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_read_mmio(size: u64, mmio_addr: u64) -> Result<u64, TdVmcallError> {
|
pub fn read_mmio(size: u64, mmio_addr: u64) -> Result<u64, TdVmcallError> {
|
||||||
match size {
|
match size {
|
||||||
1 | 2 | 4 | 8 => {}
|
1 | 2 | 4 | 8 => {}
|
||||||
_ => return Err(TdVmcallError::TdxInvalidOperand),
|
_ => return Err(TdVmcallError::TdxInvalidOperand),
|
||||||
}
|
}
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_REQUEST_MMIO,
|
r11: TdvmcallNum::RequestMmio as u64,
|
||||||
r12: size,
|
r12: size,
|
||||||
r13: 0,
|
r13: 0,
|
||||||
r14: mmio_addr,
|
r14: mmio_addr,
|
||||||
@ -163,11 +172,7 @@ pub(crate) fn tdvmcall_read_mmio(size: u64, mmio_addr: u64) -> Result<u64, TdVmc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_write_mmio(
|
pub fn write_mmio(size: u64, mmio_addr: u64, data: u64) -> Result<(), TdVmcallError> {
|
||||||
size: u64,
|
|
||||||
mmio_addr: u64,
|
|
||||||
data: u64,
|
|
||||||
) -> Result<(), TdVmcallError> {
|
|
||||||
match size {
|
match size {
|
||||||
1 | 2 | 4 | 8 => {}
|
1 | 2 | 4 | 8 => {}
|
||||||
_ => {
|
_ => {
|
||||||
@ -175,7 +180,7 @@ pub(crate) fn tdvmcall_write_mmio(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_REQUEST_MMIO,
|
r11: TdvmcallNum::RequestMmio as u64,
|
||||||
r12: size,
|
r12: size,
|
||||||
r13: 1,
|
r13: 1,
|
||||||
r14: mmio_addr,
|
r14: mmio_addr,
|
||||||
@ -188,7 +193,7 @@ pub(crate) fn tdvmcall_write_mmio(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tdvmcall_io(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) -> bool {
|
pub fn handle_io(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo) -> bool {
|
||||||
let size = match ve_info.exit_qualification & 0x3 {
|
let size = match ve_info.exit_qualification & 0x3 {
|
||||||
0 => 1,
|
0 => 1,
|
||||||
1 => 2,
|
1 => 2,
|
||||||
@ -220,10 +225,10 @@ pub(crate) fn tdvmcall_io(trapframe: &mut impl TdxTrapFrame, ve_info: &TdgVeInfo
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! tdvmcall_io_read {
|
macro_rules! io_read {
|
||||||
($port:expr, $ty:ty) => {{
|
($port:expr, $ty:ty) => {{
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_IO,
|
r11: TdvmcallNum::Io as u64,
|
||||||
r12: core::mem::size_of::<$ty>() as u64,
|
r12: core::mem::size_of::<$ty>() as u64,
|
||||||
r13: IO_READ,
|
r13: IO_READ,
|
||||||
r14: $port as u64,
|
r14: $port as u64,
|
||||||
@ -236,19 +241,19 @@ macro_rules! tdvmcall_io_read {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn io_read(size: usize, port: u16) -> Result<u32, TdVmcallError> {
|
pub fn io_read(size: usize, port: u16) -> Result<u32, TdVmcallError> {
|
||||||
match size {
|
match size {
|
||||||
1 => tdvmcall_io_read!(port, u8),
|
1 => io_read!(port, u8),
|
||||||
2 => tdvmcall_io_read!(port, u16),
|
2 => io_read!(port, u16),
|
||||||
4 => tdvmcall_io_read!(port, u32),
|
4 => io_read!(port, u32),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! tdvmcall_io_write {
|
macro_rules! io_write {
|
||||||
($port:expr, $byte:expr, $size:expr) => {{
|
($port:expr, $byte:expr, $size:expr) => {{
|
||||||
let mut args = TdVmcallArgs {
|
let mut args = TdVmcallArgs {
|
||||||
r11: TDVMCALL_IO,
|
r11: TdvmcallNum::Io as u64,
|
||||||
r12: core::mem::size_of_val(&$byte) as u64,
|
r12: core::mem::size_of_val(&$byte) as u64,
|
||||||
r13: IO_WRITE,
|
r13: IO_WRITE,
|
||||||
r14: $port as u64,
|
r14: $port as u64,
|
||||||
@ -262,11 +267,11 @@ macro_rules! tdvmcall_io_write {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn io_write(size: usize, port: u16, byte: u32) -> Result<(), TdVmcallError> {
|
pub fn io_write(size: usize, port: u16, byte: u32) -> Result<(), TdVmcallError> {
|
||||||
match size {
|
match size {
|
||||||
1 => tdvmcall_io_write!(port, byte, u8),
|
1 => io_write!(port, byte, u8),
|
||||||
2 => tdvmcall_io_write!(port, byte, u16),
|
2 => io_write!(port, byte, u16),
|
||||||
4 => tdvmcall_io_write!(port, byte, u32),
|
4 => io_write!(port, byte, u32),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,15 +317,15 @@ fn serial_write_byte(byte: u8) {
|
|||||||
match byte {
|
match byte {
|
||||||
8 | 0x7F => {
|
8 | 0x7F => {
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
tdvmcall_io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
tdvmcall_io_write!(SERIAL_IO_PORT, b' ', u8).unwrap();
|
io_write!(SERIAL_IO_PORT, b' ', u8).unwrap();
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
tdvmcall_io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
io_write!(SERIAL_IO_PORT, 8, u8).unwrap();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
while !line_sts().contains(LineSts::OUTPUT_EMPTY) {}
|
||||||
tdvmcall_io_write!(SERIAL_IO_PORT, byte, u8).unwrap();
|
io_write!(SERIAL_IO_PORT, byte, u8).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user