From 6d6116c50b19ec4a177b42545cc00cb8172aafe9 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 14:53:47 +0100 Subject: [PATCH 01/31] tdx-tdcall: Add a feature and separate tdvmcall to a dedicated file Signed-off-by: Stanislaw Grams --- tdx-tdcall/Cargo.toml | 1 + tdx-tdcall/src/lib.rs | 90 ++----------------------------------- tdx-tdcall/src/tdvmcall.rs | 92 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 87 deletions(-) create mode 100644 tdx-tdcall/src/tdvmcall.rs diff --git a/tdx-tdcall/Cargo.toml b/tdx-tdcall/Cargo.toml index ff6fe2d4..27283d43 100644 --- a/tdx-tdcall/Cargo.toml +++ b/tdx-tdcall/Cargo.toml @@ -20,3 +20,4 @@ x86_64 = { version = "0.14.9", default-features = false, features = ["instructio [features] default = [] use_tdx_emulation = [] +tdvmcall = [] diff --git a/tdx-tdcall/src/lib.rs b/tdx-tdcall/src/lib.rs index a4b572e6..f7b8bdac 100644 --- a/tdx-tdcall/src/lib.rs +++ b/tdx-tdcall/src/lib.rs @@ -31,6 +31,8 @@ pub const USE_TDX_EMULATION: bool = false; pub mod asm; pub mod tdreport; pub mod tdx; +#[cfg(feature = "tdvmcall")] +pub mod tdvmcall; // Guest-Side (TDCALL) interface functions leaf numbers const TDCALL_TDINFO: u64 = 1; @@ -50,18 +52,6 @@ const TDCALL_VP_ENTER: u64 = 25; const TDCALL_VP_INVEPT: u64 = 26; const TDCALL_VP_INVVPID: u64 = 27; -// GTDG.VP.VMCALL leaf sub-function numbers -const TDVMCALL_CPUID: u64 = 0x0000a; -const TDVMCALL_HALT: u64 = 0x0000c; -const TDVMCALL_IO: u64 = 0x0001e; -const TDVMCALL_RDMSR: u64 = 0x0001f; -const TDVMCALL_WRMSR: u64 = 0x00020; -const TDVMCALL_MMIO: u64 = 0x00030; -const TDVMCALL_MAPGPA: u64 = 0x10001; -const TDVMCALL_GETQUOTE: u64 = 0x10002; -const TDVMCALL_SETUPEVENTNOTIFY: u64 = 0x10004; -const TDVMCALL_SERVICE: u64 = 0x10005; - // TDCALL completion status code const TDCALL_STATUS_SUCCESS: u64 = 0; @@ -69,32 +59,6 @@ const TDCALL_STATUS_SUCCESS: u64 = 0; pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000; pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001; -// TDVMCALL completion status code -const TDVMCALL_STATUS_SUCCESS: u64 = 0; -const TDVMCALL_STATUS_RETRY: u64 = 1; - -// A public wrapper for use of asm_td_vmcall, this function takes a mutable reference of a -// TdcallArgs structure to ensure the input is valid -// -// ## TDVMCALL ABI -// Defined in GHCI Spec section 'TDCALL [TDG.VP.VMCALL] leaf' -// -// ### Input Operands: -// * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL) -// * RCX - A bitmap that controls which part of guest TD GPR is exposed to VMM. -// * R10 - Set to 0 indicates leaf-function used in R11 is defined in standard GHCI Spec. -// * R11 - TDG.VP.VMCALL sub-function is R10 is zero -// * RBX, RBP, RDI, RSI, R8-R10, R12-R15 - Used to pass values to VMM in sub-functions. -// -// ### Output Operands: -// * RAX - TDCALL instruction return code, always return Success(0). -// * R10 - TDG.VP.VMCALL sub-function return value -// * R11 - Correspond to each TDG.VP.VMCALL. -// * R8-R9, R12-R15, RBX, RBP, RDI, RSI - Correspond to each TDG.VP.VMCALL sub-function. -// -pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 { - unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) } -} // An extended public wrapper for use of asm_td_vmcall. // @@ -121,7 +85,7 @@ pub fn td_call(args: &mut TdcallArgs) -> u64 { unsafe { asm::asm_td_call(args as *mut TdcallArgs as *mut c_void) } } -// Used to pass the values of input/output register when performing TDVMCALL +// Used to pass the values of input/output register when performing TDCALL // instruction #[repr(C)] #[derive(Default)] @@ -137,21 +101,6 @@ pub struct TdcallArgs { pub r13: u64, } -// Used to pass the values of input/output register when performing TDVMCALL -// instruction -#[repr(C)] -#[derive(Default)] -pub struct TdVmcallArgs { - // Input: Always 0 for (standard VMCALL) - // Output: Sub-function - pub r10: u64, - pub r11: u64, - pub r12: u64, - pub r13: u64, - pub r14: u64, - pub r15: u64, -} - /// TDCALL instruction return error code /// /// Refer to Intel TDX Module 1.0 Specifiction section 'TDCALL Instruction (Common)' @@ -180,36 +129,3 @@ impl From for TdCallError { } } } - -/// TDVMCALL sub-function return error code -/// -/// Refer to Guest-Host-Communication-Interface(GHCI) for Intel TDX -/// table 'TDCALL[TDG.VP.VMCALL]- Sub-function Completion-Status Codes' -#[derive(Debug, PartialEq)] -pub enum TdVmcallError { - // TDCALL[TDG.VP.VMCALL] sub-function invocation must be retried - VmcallRetry, - - // Invalid operand to TDG.VP.VMCALL sub-function - VmcallOperandInvalid, - - // GPA already mapped - VmcallGpaInuse, - - // Operand (address) alignment error - VmcallAlignError, - - Other, -} - -impl From for TdVmcallError { - fn from(val: u64) -> Self { - match val { - 0x1 => TdVmcallError::VmcallRetry, - 0x8000_0000_0000_0000 => TdVmcallError::VmcallOperandInvalid, - 0x8000_0000_0000_0001 => TdVmcallError::VmcallGpaInuse, - 0x8000_0000_0000_0002 => TdVmcallError::VmcallAlignError, - _ => TdVmcallError::Other, - } - } -} diff --git a/tdx-tdcall/src/tdvmcall.rs b/tdx-tdcall/src/tdvmcall.rs new file mode 100644 index 00000000..1babe8e4 --- /dev/null +++ b/tdx-tdcall/src/tdvmcall.rs @@ -0,0 +1,92 @@ +// Copyright (c) 2025 Intel Corporation +// +// SPDX-License-Identifier: BSD-2-Clause-Patent + +use crate::*; + +// GTDG.VP.VMCALL leaf sub-function numbers +const TDVMCALL_CPUID: u64 = 0x0000a; +const TDVMCALL_HALT: u64 = 0x0000c; +const TDVMCALL_IO: u64 = 0x0001e; +const TDVMCALL_RDMSR: u64 = 0x0001f; +const TDVMCALL_WRMSR: u64 = 0x00020; +const TDVMCALL_MMIO: u64 = 0x00030; +const TDVMCALL_MAPGPA: u64 = 0x10001; +const TDVMCALL_GETQUOTE: u64 = 0x10002; +const TDVMCALL_SETUPEVENTNOTIFY: u64 = 0x10004; +const TDVMCALL_SERVICE: u64 = 0x10005; + +// TDVMCALL completion status code +const TDVMCALL_STATUS_SUCCESS: u64 = 0; +const TDVMCALL_STATUS_RETRY: u64 = 1; + +// Used to pass the values of input/output register when performing TDVMCALL +// instruction +#[repr(C)] +#[derive(Default)] +pub struct TdVmcallArgs { + // Input: Always 0 for (standard VMCALL) + // Output: Sub-function + pub r10: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, + pub r14: u64, + pub r15: u64, +} + +/// TDVMCALL sub-function return error code +/// +/// Refer to Guest-Host-Communication-Interface(GHCI) for Intel TDX +/// table 'TDCALL[TDG.VP.VMCALL]- Sub-function Completion-Status Codes' +#[derive(Debug, PartialEq)] +pub enum TdVmcallError { + // TDCALL[TDG.VP.VMCALL] sub-function invocation must be retried + VmcallRetry, + + // Invalid operand to TDG.VP.VMCALL sub-function + VmcallOperandInvalid, + + // GPA already mapped + VmcallGpaInuse, + + // Operand (address) alignment error + VmcallAlignError, + + Other, +} + +impl From for TdVmcallError { + fn from(val: u64) -> Self { + match val { + 0x1 => TdVmcallError::VmcallRetry, + 0x8000_0000_0000_0000 => TdVmcallError::VmcallOperandInvalid, + 0x8000_0000_0000_0001 => TdVmcallError::VmcallGpaInuse, + 0x8000_0000_0000_0002 => TdVmcallError::VmcallAlignError, + _ => TdVmcallError::Other, + } + } +} + +// A public wrapper for use of asm_td_vmcall, this function takes a mutable reference of a +// TdcallArgs structure to ensure the input is valid +// +// ## TDVMCALL ABI +// Defined in GHCI Spec section 'TDCALL [TDG.VP.VMCALL] leaf' +// +// ### Input Operands: +// * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL) +// * RCX - A bitmap that controls which part of guest TD GPR is exposed to VMM. +// * R10 - Set to 0 indicates leaf-function used in R11 is defined in standard GHCI Spec. +// * R11 - TDG.VP.VMCALL sub-function is R10 is zero +// * RBX, RBP, RDI, RSI, R8-R10, R12-R15 - Used to pass values to VMM in sub-functions. +// +// ### Output Operands: +// * RAX - TDCALL instruction return code, always return Success(0). +// * R10 - TDG.VP.VMCALL sub-function return value +// * R11 - Correspond to each TDG.VP.VMCALL. +// * R8-R9, R12-R15, RBX, RBP, RDI, RSI - Correspond to each TDG.VP.VMCALL sub-function. +// +pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 { + unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) } +} From c85adc3cf9a1efce872ddb717285878f163b19c7 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:07:01 +0100 Subject: [PATCH 02/31] tdx-tdcall: Split tdx.rs into tdcall.rs and tdvmcall.rs No functional changes Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/lib.rs | 2 + tdx-tdcall/src/tdcall.rs | 538 +++++++++++++++++++++ tdx-tdcall/src/tdvmcall.rs | 439 ++++++++++++++++- tdx-tdcall/src/tdx.rs | 965 ------------------------------------- 4 files changed, 978 insertions(+), 966 deletions(-) create mode 100644 tdx-tdcall/src/tdcall.rs diff --git a/tdx-tdcall/src/lib.rs b/tdx-tdcall/src/lib.rs index f7b8bdac..f41fb664 100644 --- a/tdx-tdcall/src/lib.rs +++ b/tdx-tdcall/src/lib.rs @@ -33,6 +33,8 @@ pub mod tdreport; pub mod tdx; #[cfg(feature = "tdvmcall")] pub mod tdvmcall; +#[cfg(feature = "tdcall")] +pub mod tdcall; // Guest-Side (TDCALL) interface functions leaf numbers const TDCALL_TDINFO: u64 = 1; diff --git a/tdx-tdcall/src/tdcall.rs b/tdx-tdcall/src/tdcall.rs new file mode 100644 index 00000000..d8eac3a3 --- /dev/null +++ b/tdx-tdcall/src/tdcall.rs @@ -0,0 +1,538 @@ +// Copyright (c) 2020-2022, 2025 Intel Corporation +// +// SPDX-License-Identifier: BSD-2-Clause-Patent + +//! Implemention of a subset of TDCALL functions defined in +//! Intel TDX Module v1.0 and v1.5 Spec. +//! +//! The TDCALL instruction causes a VM exit to the Intel TDX Module. It is used to call +//! guest-side Intel TDX functions, either local or a TD exit to the host VMM. + +use core::result::Result; +use crate::*; + +pub const PAGE_SIZE_4K: u64 = 0x1000; +pub const PAGE_SIZE_2M: u64 = 0x200000; +const TARGET_TD_UUID_NUM: usize = 4; + +/// SHA384 digest value extended to RTMR +/// Both alignment and size are 64 bytes. +#[repr(C, align(64))] +pub struct TdxDigest { + pub data: [u8; 48], +} + +/// Guest TD execution evironment returned from TDG.VP.INFO leaf +#[repr(C)] +#[derive(Debug, Default)] +pub struct TdInfo { + pub gpaw: u64, + pub attributes: u64, + pub max_vcpus: u32, + pub num_vcpus: u32, + pub vcpu_index: u32, + pub rsvd: [u32; 5], +} + +/// Virtualization exception information returned from TDG.VP.VEINFO.GET leaf +#[repr(C)] +#[derive(Debug, Default)] +pub struct TdVeInfo { + pub exit_reason: u32, + pub rsvd: u32, + pub exit_qualification: u64, + pub guest_la: u64, + pub guest_pa: u64, + pub exit_instruction_length: u32, + pub exit_instruction_info: u32, + pub rsvd1: u64, +} + +#[derive(Debug, Default)] +#[repr(C)] +pub struct ServtdRWResult { + pub content: u64, + pub uuid: [u64; 4], +} + + +/// Get guest TD execution environment information +/// +/// Details can be found in TDX Module ABI spec section 'TDG.VP.INFO Leaf' +pub fn tdcall_get_td_info() -> Result { + let mut args = TdcallArgs { + rax: TDCALL_TDINFO, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + let td_info = TdInfo { + gpaw: args.rcx & 0x3f, + attributes: args.rdx, + max_vcpus: (args.r8 >> 32) as u32, + num_vcpus: args.r8 as u32, + vcpu_index: args.r9 as u32, + ..Default::default() + }; + + Ok(td_info) +} + +/// Extend a TDCS.RTMR measurement register +/// +/// Details can be found in TDX Module ABI spec section 'TDG.VP.INFO Leaf' +pub fn tdcall_extend_rtmr(digest: &TdxDigest, mr_index: u32) -> Result<(), TdCallError> { + let buffer: u64 = core::ptr::addr_of!(digest.data) as u64; + + let mut args = TdcallArgs { + rax: TDCALL_TDEXTENDRTMR, + rcx: buffer, + rdx: mr_index as u64, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(()) +} + +/// Get virtualization exception information for the recent #VE +/// +/// Details can be found in TDX Module ABI spec section 'TDG.VP.VEINFO.GET Leaf' +pub fn tdcall_get_ve_info() -> Result { + let mut args = TdcallArgs { + rax: TDCALL_TDGETVEINFO, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + let ve_info = TdVeInfo { + exit_reason: args.rcx as u32, + exit_qualification: args.rdx, + guest_la: args.r8, + guest_pa: args.r9, + exit_instruction_length: args.r10 as u32, + exit_instruction_info: (args.r10 >> 32) as u32, + ..Default::default() + }; + + Ok(ve_info) +} + +/// Accept a pending private page, and initialize the page to zeros using the TD ephemeral +/// private key +/// +/// Details can be found in TDX Module ABI spec section 'TDG.MEM.PAGE.Accept Leaf' +pub fn tdcall_accept_page(address: u64) -> Result<(), TdCallError> { + let mut args = TdcallArgs { + rax: TDCALL_TDACCEPTPAGE, + rcx: address, + ..Default::default() + }; + + const MAX_RETRIES_ACCEPT_PAGE: usize = 5; + let mut retry_counter = 0; + let mut ret = 0; + + while retry_counter < MAX_RETRIES_ACCEPT_PAGE { + ret = td_call(&mut args); + + if ret == TDCALL_STATUS_SUCCESS { + return Ok(()); + } else { + match TdCallError::from(ret) { + TdCallError::TdxExitReasonOperandBusy(_) => retry_counter += 1, + e => return Err(e), + } + } + } + + return Err(ret.into()); +} + +/// Accept a range of private pages and initialize the pages to zeros using the TD ephemeral +/// private key. +/// +/// This function is a wrapper to `tdcall_accept_page()`. +pub fn td_accept_pages(address: u64, pages: u64, page_size: u64) { + for i in 0..pages { + let accept_addr = address + i * page_size; + let accept_level = if page_size == PAGE_SIZE_2M { 1 } else { 0 }; + match tdcall_accept_page(accept_addr | accept_level) { + Ok(()) => {} + Err(e) => { + if let TdCallError::LeafSpecific(error_code) = e { + if error_code == TDCALL_STATUS_PAGE_SIZE_MISMATCH { + if page_size == PAGE_SIZE_2M { + td_accept_pages(accept_addr, 512, PAGE_SIZE_4K); + continue; + } + } else if error_code == TDCALL_STATUS_PAGE_ALREADY_ACCEPTED { + continue; + } + } + panic!( + "Accept Page Error: 0x{:x}, page_size: {}, err {:x?}\n", + accept_addr, page_size, e + ); + } + } + } +} + +/// Accept a range of either 4K normal pages or 2M huge pages. This is basically a wrapper over +/// td_accept_pages and initializes the pages to zero using the TD ephemeral private key. +pub fn td_accept_memory(address: u64, len: u64) { + let mut start = address; + let end = address + len; + + while start < end { + let remaining = end - start; + + // Try larger accepts first to keep 1G/2M Secure EPT entries + // where possible and speeds up process by cutting number of + // tdcalls (if successful). + if remaining >= PAGE_SIZE_2M && (start & (PAGE_SIZE_2M - 1)) == 0 { + let npages = remaining >> 21; + td_accept_pages(start, npages, PAGE_SIZE_2M); + start += npages << 21; + } else if remaining >= PAGE_SIZE_4K && (start & (PAGE_SIZE_4K - 1)) == 0 { + let mut npages = remaining >> 12; + // Try to consume in 4K chunks until 2M aligned. + if remaining >= PAGE_SIZE_2M { + npages = (PAGE_SIZE_2M - (start & (PAGE_SIZE_2M - 1))) >> 12; + } + td_accept_pages(start, npages, PAGE_SIZE_4K); + start += npages << 12; + } else { + panic!("Accept Memory Error: 0x{:x}, length: {}\n", address, len); + } + } +} + +/// Get the guest physical address (GPA) width via TDG.VP.INFO +/// The GPA width can be used to determine the shared-bit of GPA +pub fn td_shared_mask() -> Option { + let td_info = tdcall_get_td_info().ok()?; + let gpaw = (td_info.gpaw & 0x3f) as u8; + + // Detail can be found in TDX Module v1.5 ABI spec section 'TDVPS(excluding TD VMCS)'. + if gpaw == 48 || gpaw == 52 { + Some(1u64 << (gpaw - 1)) + } else { + None + } +} + +/// Used by a service TD to read a metadata field (control structure field) of +/// a target TD. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SERVTD.RD Leaf'. +pub fn tdcall_servtd_rd( + binding_handle: u64, + field_identifier: u64, + target_td_uuid: &[u64], +) -> Result { + if target_td_uuid.len() != TARGET_TD_UUID_NUM { + return Err(TdCallError::TdxExitInvalidParameters); + } + + let mut args = TdcallArgs { + rax: TDCALL_SERVTD_RD, + rcx: binding_handle, + rdx: field_identifier, + r10: target_td_uuid[0], + r11: target_td_uuid[1], + r12: target_td_uuid[2], + r13: target_td_uuid[3], + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + let sertd_rw_result = ServtdRWResult { + content: args.r8, + uuid: [args.r10, args.r11, args.r12, args.r13], + }; + + Ok(sertd_rw_result) +} + +/// Used by a service TD to write a metadata field (control structure field) of +/// a target TD. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SERVTD.RD Leaf'. +pub fn tdcall_servtd_wr( + binding_handle: u64, + field_identifier: u64, + data: u64, + target_td_uuid: &[u64], +) -> Result { + if target_td_uuid.len() != TARGET_TD_UUID_NUM { + return Err(TdCallError::TdxExitInvalidParameters); + } + + let mut args = TdcallArgs { + rax: TDCALL_SERVTD_WR, + rcx: binding_handle, + rdx: field_identifier, + r8: data, + r9: u64::MAX, + r10: target_td_uuid[0], + r11: target_td_uuid[1], + r12: target_td_uuid[2], + r13: target_td_uuid[3], + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + let result = ServtdRWResult { + content: args.r8, + uuid: [args.r10, args.r11, args.r12, args.r13], + }; + + Ok(result) +} + +/// Used to read a TDX Module global-scope metadata field. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SYS.RD Leaf'. +pub fn tdcall_sys_rd(field_identifier: u64) -> core::result::Result<(u64, u64), TdCallError> { + let mut args = TdcallArgs { + rax: TDCALL_SYS_RD, + rdx: field_identifier, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok((args.rdx, args.r8)) +} + +/// Read a VCPU-scope metadata field (control structure field) of a TD. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.RD Leaf'. +pub fn tdcall_vp_read(field: u64) -> Result<(u64, u64), TdCallError> { + let mut args = TdcallArgs { + rax: TDCALL_VP_RD, + rdx: field, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok((args.rdx, args.r8)) +} + +/// Write a VCPU-scope metadata field (control structure field) of a TD. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.WR Leaf'. +pub fn tdcall_vp_write(field: u64, value: u64, mask: u64) -> Result { + let mut args = TdcallArgs { + rax: TDCALL_VP_WR, + rdx: field, + r8: value, + r9: mask, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(args.r8) +} + +/// Invalidate mappings in the translation lookaside buffers (TLBs) and paging-structure caches +/// for a specified L2 VM and a specified list of 4KB page linear addresses. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.INVVPID Leaf'. +pub fn tdcall_vp_invvpid(flags: u64, gla: u64) -> Result { + let mut args = TdcallArgs { + rax: TDCALL_VP_INVVPID, + rcx: flags, + rdx: gla, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(args.rdx) +} + +/// Invalidate cached EPT translations for selected L2 VM. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.INVEPT Leaf'. +pub fn tdcall_vp_invept(vm_flags: u64) -> Result<(), TdCallError> { + let mut args = TdcallArgs { + rax: TDCALL_VP_INVEPT, + rcx: vm_flags, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(()) +} + +/// Enter L2 VCPU operation. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.ENTER Leaf'. +pub fn tdcall_vp_enter(vm_flags: u64, gpa: u64) -> TdcallArgs { + let mut args = TdcallArgs { + rax: TDCALL_VP_ENTER, + rcx: vm_flags, + rdx: gpa, + ..Default::default() + }; + + td_call(&mut args); + + args +} + +/// Read a TD-scope metadata field (control structure field) of a TD. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VM.RD Leaf'. +pub fn tdcall_vm_read(field: u64, version: u8) -> Result<(u64, u64), TdCallError> { + let mut args = TdcallArgs { + rax: TDCALL_VM_RD | (version as u64) << 16, + rdx: field, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok((args.rdx, args.r8)) +} + +/// Write a TD-scope metadata field (control structure field) of a TD. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VM.WR Leaf'. +pub fn tdcall_vm_write(field: u64, value: u64, mask: u64) -> Result { + let mut args = TdcallArgs { + rax: TDCALL_VM_WR, + rdx: field, + r8: value, + r9: mask, + ..Default::default() + }; + + let ret = td_call(&mut args); + + if ret != TDCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(args.r8) +} + +/// Write the attributes of a private page. Create or remove L2 page aliases as required. +/// +/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.MEM.PAGE.ATTR.WR Leaf'. +pub fn tdcall_mem_page_attr_wr( + gpa_mapping: u64, + gpa_attr: u64, + attr_flags: u64, +) -> Result<(u64, u64), TdCallError> { + let mut args = TdcallArgs { + rax: TDCALL_MEM_PAGE_ATTR_WR, + rcx: gpa_mapping, + rdx: gpa_attr, + r8: attr_flags, + ..Default::default() + }; + + const MAX_RETRIES_ATTR_WR: usize = 5; + let mut retry_counter = 0; + let mut ret = 0; + + while retry_counter < MAX_RETRIES_ATTR_WR { + ret = td_call(&mut args); + + if ret == TDCALL_STATUS_SUCCESS { + return Ok((args.rcx, args.rdx)); + } else { + match TdCallError::from(ret) { + TdCallError::TdxExitReasonOperandBusy(_) => retry_counter += 1, + e => return Err(e), + } + } + } + + return Err(ret.into()); +} + +#[cfg(test)] +mod tests { + use super::*; + use core::mem::{align_of, size_of}; + + #[test] + fn test_struct_size_alignment() { + assert_eq!(align_of::(), 64); + assert_eq!(size_of::(), 64); + assert_eq!(size_of::(), 48); + assert_eq!(size_of::(), 48); + } + + #[test] + fn test_tdcall_servtd_rd() { + let uuid: [u64; 3] = [0; 3]; + let ret = tdcall_servtd_rd(0x0, 0x0, &uuid); + + assert!(ret.is_err()); + } + + #[test] + fn test_tdcall_servtd_wr() { + let uuid: [u64; 3] = [0; 3]; + let ret = tdcall_servtd_wr(0x0, 0x0, 0x0, &uuid); + + assert!(ret.is_err()); + } +} diff --git a/tdx-tdcall/src/tdvmcall.rs b/tdx-tdcall/src/tdvmcall.rs index 1babe8e4..b2c7a33b 100644 --- a/tdx-tdcall/src/tdvmcall.rs +++ b/tdx-tdcall/src/tdvmcall.rs @@ -1,9 +1,22 @@ -// Copyright (c) 2025 Intel Corporation +// Copyright (c) 2020-2022, 2025 Intel Corporation // // SPDX-License-Identifier: BSD-2-Clause-Patent +//! Implemention of a subset of TDVMCALL sub-functions defined in TDX GHCI Spec. +//! +//! TDVMCALL (TDG.VP.VMCALL) is a leaf function 0 for TDCALL. It helps invoke services from +//! the host VMM. + +use core::result::Result; +use x86_64::registers::rflags::{self, RFlags}; +use core::sync::atomic::{fence, Ordering}; +use lazy_static::lazy_static; use crate::*; +lazy_static! { + static ref SHARED_MASK: u64 = td_shared_mask().expect("Fail to get the shared mask of TD"); +} + // GTDG.VP.VMCALL leaf sub-function numbers const TDVMCALL_CPUID: u64 = 0x0000a; const TDVMCALL_HALT: u64 = 0x0000c; @@ -35,6 +48,16 @@ pub struct TdVmcallArgs { pub r15: u64, } +/// Emulated CPUID values returned from TDG.VP.VMCALL +#[repr(C)] +#[derive(Debug, Default)] +pub struct CpuIdInfo { + pub eax: u32, + pub ebx: u32, + pub ecx: u32, + pub edx: u32, +} + /// TDVMCALL sub-function return error code /// /// Refer to Guest-Host-Communication-Interface(GHCI) for Intel TDX @@ -90,3 +113,417 @@ impl From for TdVmcallError { pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 { unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) } } + +/// Used to help perform HLT operation. +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_halt() { + let interrupt_blocked = !rflags::read().contains(RFlags::INTERRUPT_FLAG); + + let mut args = TdVmcallArgs { + r11: TDVMCALL_HALT, + r12: interrupt_blocked as u64, + ..Default::default() + }; + + let _ = td_vmcall(&mut args); +} + +/// Executing `hlt` instruction will cause a #VE to emulate the instruction. Safe halt operation +/// `sti;hlt` which typically used for idle is not working in this case since `hlt` instruction +/// must be the instruction next to `sti`. To use safe halt, `sti` must be executed just before +/// `tdcall` instruction. +pub fn tdvmcall_sti_halt() { + let mut args = TdVmcallArgs { + r11: TDVMCALL_HALT, + ..Default::default() + }; + + // Set the `do_sti` flag to execute `sti` before `tdcall` instruction + // Result is always `TDG.VP.VMCALL_SUCCESS` + let _ = td_vmcall_ex(&mut args, true); +} + +const IO_READ: u64 = 0; +const IO_WRITE: u64 = 1; + +/// Request the VMM perform single byte IO read operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_io_read_8(port: u16) -> u8 { + let mut args = TdVmcallArgs { + r11: TDVMCALL_IO, + r12: core::mem::size_of::() as u64, + r13: IO_READ, + r14: port as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } + + (args.r11 & 0xff) as u8 +} + +/// Request the VMM perform 2-bytes byte IO read operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_io_read_16(port: u16) -> u16 { + let mut args = TdVmcallArgs { + r11: TDVMCALL_IO, + r12: core::mem::size_of::() as u64, + r13: IO_READ, + r14: port as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } + + (args.r11 & 0xffff) as u16 +} + +/// Request the VMM perform 4-bytes byte IO read operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_io_read_32(port: u16) -> u32 { + let mut args = TdVmcallArgs { + r11: TDVMCALL_IO, + r12: core::mem::size_of::() as u64, + r13: IO_READ, + r14: port as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } + + (args.r11 & 0xffff_ffff) as u32 +} + +/// Request the VMM perform single byte IO write operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_io_write_8(port: u16, byte: u8) { + let mut args = TdVmcallArgs { + r11: TDVMCALL_IO, + r12: core::mem::size_of::() as u64, + r13: IO_WRITE, + r14: port as u64, + r15: byte as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } +} + +/// Request the VMM perform 2-bytes IO write operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_io_write_16(port: u16, byte: u16) { + let mut args = TdVmcallArgs { + r11: TDVMCALL_IO, + r12: core::mem::size_of::() as u64, + r13: IO_WRITE, + r14: port as u64, + r15: byte as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } +} + +/// Request the VMM perform 4-bytes IO write operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_io_write_32(port: u16, byte: u32) { + let mut args = TdVmcallArgs { + r11: TDVMCALL_IO, + r12: core::mem::size_of::() as u64, + r13: IO_WRITE, + r14: port as u64, + r15: byte as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } +} + +/// Used to help request the VMM perform emulated-MMIO-write operation. +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<#VE.RequestMMIO>' +pub fn tdvmcall_mmio_write(address: *const T, value: T) { + let address = address as u64 | *SHARED_MASK; + fence(Ordering::SeqCst); + let val = unsafe { *(core::ptr::addr_of!(value) as *const u64) }; + + let mut args = TdVmcallArgs { + r11: TDVMCALL_MMIO, + r12: core::mem::size_of::() as u64, + r13: IO_WRITE, + r14: address, + r15: val, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } +} + +/// Used to help request the VMM perform emulated-MMIO-read operation. +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<#VE.RequestMMIO>' +pub fn tdvmcall_mmio_read(address: usize) -> T { + let address = address as u64 | *SHARED_MASK; + fence(Ordering::SeqCst); + + let mut args = TdVmcallArgs { + r11: TDVMCALL_MMIO, + r12: core::mem::size_of::() as u64, + r13: IO_READ, + r14: address, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } + + unsafe { *(core::ptr::addr_of!(args.r11) as *const T) } +} + +/// Used to request the host VMM to map a GPA range as a private or shared memory mappings. +/// It can be used to convert page mappings from private to shared or vice versa +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_mapgpa(shared: bool, paddr: u64, length: usize) -> Result<(), TdVmcallError> { + let share_bit = *SHARED_MASK; + let mut map_start = if shared { + paddr | share_bit + } else { + paddr & (!share_bit) + }; + let map_end = map_start + .checked_add(length as u64) + .ok_or(TdVmcallError::Other)?; + + const MAX_RETRIES_PER_PAGE: usize = 3; + let mut retry_counter = 0; + + while retry_counter < MAX_RETRIES_PER_PAGE { + log::trace!( + "tdvmcall mapgpa - start: {:x}, length: {:x}\n", + map_start, + map_end - map_start, + ); + let mut args = TdVmcallArgs { + r11: TDVMCALL_MAPGPA, + r12: map_start, + r13: map_end - map_start, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + if ret == TDVMCALL_STATUS_SUCCESS { + return Ok(()); + } else if ret != TDVMCALL_STATUS_RETRY { + return Err(ret.into()); + } + + let retry_addr = args.r11; + if retry_addr < map_start || retry_addr >= map_end { + return Err(TdVmcallError::Other); + } + + // Increase the retry count for the current page + if retry_addr == map_start { + retry_counter += 1; + continue; + } + + // Failed in a new address, update the `map_start` and reset counter + map_start = retry_addr; + retry_counter = 0; + } + + Err(TdVmcallError::Other) +} + +/// Used to help perform RDMSR operation. +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_rdmsr(index: u32) -> Result { + let mut args = TdVmcallArgs { + r11: TDVMCALL_RDMSR, + r12: index as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(args.r11) +} + +/// Used to help perform WRMSR operation. +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> { + let mut args = TdVmcallArgs { + r11: TDVMCALL_WRMSR, + r12: index as u64, + r13: value, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(()) +} + +/// Used to enable the TD-guest to request the VMM to emulate the CPUID operation +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_cpuid(eax: u32, ecx: u32) -> CpuIdInfo { + let mut args = TdVmcallArgs { + r11: TDVMCALL_CPUID, + r12: eax as u64, + r13: ecx as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + tdvmcall_halt(); + } + + CpuIdInfo { + eax: (args.r12 & 0xffff_ffff) as u32, + ebx: (args.r13 & 0xffff_ffff) as u32, + ecx: (args.r14 & 0xffff_ffff) as u32, + edx: (args.r15 & 0xffff_ffff) as u32, + } +} + +/// Used to request the host VMM specify which interrupt vector to use as an event-notify +/// vector. +/// +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +pub fn tdvmcall_setup_event_notify(vector: u64) -> Result<(), TdVmcallError> { + let mut args = TdVmcallArgs { + r11: TDVMCALL_SETUPEVENTNOTIFY, + r12: vector, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(()) +} + +/// Used to invoke a request to generate a TD-Quote signing by a TD-Quoting Enclave +/// operating in the host environment. +/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' +/// +/// * buffer: a piece of 4KB-aligned shared memory +pub fn tdvmcall_get_quote(buffer: &mut [u8]) -> Result<(), TdVmcallError> { + let addr = buffer.as_mut_ptr() as u64 | *SHARED_MASK; + + let mut args = TdVmcallArgs { + r11: TDVMCALL_GETQUOTE, + r12: addr, + r13: buffer.len() as u64, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(()) +} + +/// TDG.VP.VMCALL defines an interface for the command/response that +/// may have long latency. +/// Details can be found in TDX GHCI v1.5 spec section 'TDG.VP.VMCALL' +/// +/// * command: a piece of 4KB-aligned shared memory as input +/// * response: a piece of 4KB-aligned shared memory as ouput +/// * interrupt: event notification interrupt vector, valid values [32-255] +/// * wait_time: Maximum wait time for the command and response +pub fn tdvmcall_service( + command: &[u8], + response: &mut [u8], + interrupt: u64, + wait_time: u64, +) -> Result<(), TdVmcallError> { + let command = command.as_ptr() as u64 | *SHARED_MASK; + let response = response.as_mut_ptr() as u64 | *SHARED_MASK; + + // Ensure the address is aligned to 4K bytes + if (command & 0xfff) != 0 || (response & 0xfff) != 0 { + return Err(TdVmcallError::VmcallAlignError); + } + + // Ensure that the interrupt vector is in a valid range + if (1..32).contains(&interrupt) { + return Err(TdVmcallError::VmcallOperandInvalid); + } + + let mut args = TdVmcallArgs { + r11: TDVMCALL_SERVICE, + r12: command, + r13: response, + r14: interrupt, + r15: wait_time, + ..Default::default() + }; + + let ret = td_vmcall(&mut args); + + if ret != TDVMCALL_STATUS_SUCCESS { + return Err(ret.into()); + } + + Ok(()) +} diff --git a/tdx-tdcall/src/tdx.rs b/tdx-tdcall/src/tdx.rs index 522d62a7..db8a6bf1 100644 --- a/tdx-tdcall/src/tdx.rs +++ b/tdx-tdcall/src/tdx.rs @@ -2,970 +2,5 @@ // // SPDX-License-Identifier: BSD-2-Clause-Patent -//! Implemention of a subset of TDCALL functions defined in Intel TDX Module v1.0 and v1.5 -//! Spec and TDVMCALL sub-functions defined in TDX GHCI Spec. -//! -//! The TDCALL instruction causes a VM exit to the Intel TDX Module. It is used to call -//! guest-side Intel TDX functions, either local or a TD exit to the host VMM. -//! -//! TDVMCALL (TDG.VP.VMCALL) is a leaf function 0 for TDCALL. It helps invoke services from -//! the host VMM. - -use core::result::Result; -use core::sync::atomic::{fence, Ordering}; -use lazy_static::lazy_static; -use x86_64::registers::rflags::{self, RFlags}; use crate::*; - -const IO_READ: u64 = 0; -const IO_WRITE: u64 = 1; -const TARGET_TD_UUID_NUM: usize = 4; -pub const PAGE_SIZE_4K: u64 = 0x1000; -pub const PAGE_SIZE_2M: u64 = 0x200000; - -/// SHA384 digest value extended to RTMR -/// Both alignment and size are 64 bytes. -#[repr(C, align(64))] -pub struct TdxDigest { - pub data: [u8; 48], -} - -/// Guest TD execution evironment returned from TDG.VP.INFO leaf -#[repr(C)] -#[derive(Debug, Default)] -pub struct TdInfo { - pub gpaw: u64, - pub attributes: u64, - pub max_vcpus: u32, - pub num_vcpus: u32, - pub vcpu_index: u32, - pub rsvd: [u32; 5], -} - -/// Virtualization exception information returned from TDG.VP.VEINFO.GET leaf -#[repr(C)] -#[derive(Debug, Default)] -pub struct TdVeInfo { - pub exit_reason: u32, - pub rsvd: u32, - pub exit_qualification: u64, - pub guest_la: u64, - pub guest_pa: u64, - pub exit_instruction_length: u32, - pub exit_instruction_info: u32, - pub rsvd1: u64, -} - -/// Emulated CPUID values returned from TDG.VP.VMCALL -#[repr(C)] -#[derive(Debug, Default)] -pub struct CpuIdInfo { - pub eax: u32, - pub ebx: u32, - pub ecx: u32, - pub edx: u32, -} - -#[derive(Debug, Default)] -#[repr(C)] -pub struct ServtdRWResult { - pub content: u64, - pub uuid: [u64; 4], -} - -lazy_static! { - static ref SHARED_MASK: u64 = td_shared_mask().expect("Fail to get the shared mask of TD"); -} - -/// Used to help perform HLT operation. -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_halt() { - let interrupt_blocked = !rflags::read().contains(RFlags::INTERRUPT_FLAG); - - let mut args = TdVmcallArgs { - r11: TDVMCALL_HALT, - r12: interrupt_blocked as u64, - ..Default::default() - }; - - let _ = td_vmcall(&mut args); -} - -/// Executing `hlt` instruction will cause a #VE to emulate the instruction. Safe halt operation -/// `sti;hlt` which typically used for idle is not working in this case since `hlt` instruction -/// must be the instruction next to `sti`. To use safe halt, `sti` must be executed just before -/// `tdcall` instruction. -pub fn tdvmcall_sti_halt() { - let mut args = TdVmcallArgs { - r11: TDVMCALL_HALT, - ..Default::default() - }; - - // Set the `do_sti` flag to execute `sti` before `tdcall` instruction - // Result is always `TDG.VP.VMCALL_SUCCESS` - let _ = td_vmcall_ex(&mut args, true); -} - -/// Request the VMM perform single byte IO read operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_read_8(port: u16) -> u8 { - let mut args = TdVmcallArgs { - r11: TDVMCALL_IO, - r12: core::mem::size_of::() as u64, - r13: IO_READ, - r14: port as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } - - (args.r11 & 0xff) as u8 -} - -/// Request the VMM perform 2-bytes byte IO read operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_read_16(port: u16) -> u16 { - let mut args = TdVmcallArgs { - r11: TDVMCALL_IO, - r12: core::mem::size_of::() as u64, - r13: IO_READ, - r14: port as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } - - (args.r11 & 0xffff) as u16 -} - -/// Request the VMM perform 4-bytes byte IO read operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_read_32(port: u16) -> u32 { - let mut args = TdVmcallArgs { - r11: TDVMCALL_IO, - r12: core::mem::size_of::() as u64, - r13: IO_READ, - r14: port as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } - - (args.r11 & 0xffff_ffff) as u32 -} - -/// Request the VMM perform single byte IO write operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_write_8(port: u16, byte: u8) { - let mut args = TdVmcallArgs { - r11: TDVMCALL_IO, - r12: core::mem::size_of::() as u64, - r13: IO_WRITE, - r14: port as u64, - r15: byte as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } -} - -/// Request the VMM perform 2-bytes IO write operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_write_16(port: u16, byte: u16) { - let mut args = TdVmcallArgs { - r11: TDVMCALL_IO, - r12: core::mem::size_of::() as u64, - r13: IO_WRITE, - r14: port as u64, - r15: byte as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } -} - -/// Request the VMM perform 4-bytes IO write operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_write_32(port: u16, byte: u32) { - let mut args = TdVmcallArgs { - r11: TDVMCALL_IO, - r12: core::mem::size_of::() as u64, - r13: IO_WRITE, - r14: port as u64, - r15: byte as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } -} - -/// Used to help request the VMM perform emulated-MMIO-write operation. -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<#VE.RequestMMIO>' -pub fn tdvmcall_mmio_write(address: *const T, value: T) { - let address = address as u64 | *SHARED_MASK; - fence(Ordering::SeqCst); - let val = unsafe { *(core::ptr::addr_of!(value) as *const u64) }; - - let mut args = TdVmcallArgs { - r11: TDVMCALL_MMIO, - r12: core::mem::size_of::() as u64, - r13: IO_WRITE, - r14: address, - r15: val, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } -} - -/// Used to help request the VMM perform emulated-MMIO-read operation. -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<#VE.RequestMMIO>' -pub fn tdvmcall_mmio_read(address: usize) -> T { - let address = address as u64 | *SHARED_MASK; - fence(Ordering::SeqCst); - - let mut args = TdVmcallArgs { - r11: TDVMCALL_MMIO, - r12: core::mem::size_of::() as u64, - r13: IO_READ, - r14: address, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } - - unsafe { *(core::ptr::addr_of!(args.r11) as *const T) } -} - -/// Used to request the host VMM to map a GPA range as a private or shared memory mappings. -/// It can be used to convert page mappings from private to shared or vice versa -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_mapgpa(shared: bool, paddr: u64, length: usize) -> Result<(), TdVmcallError> { - let share_bit = *SHARED_MASK; - let mut map_start = if shared { - paddr | share_bit - } else { - paddr & (!share_bit) - }; - let map_end = map_start - .checked_add(length as u64) - .ok_or(TdVmcallError::Other)?; - - const MAX_RETRIES_PER_PAGE: usize = 3; - let mut retry_counter = 0; - - while retry_counter < MAX_RETRIES_PER_PAGE { - log::trace!( - "tdvmcall mapgpa - start: {:x}, length: {:x}\n", - map_start, - map_end - map_start, - ); - let mut args = TdVmcallArgs { - r11: TDVMCALL_MAPGPA, - r12: map_start, - r13: map_end - map_start, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - if ret == TDVMCALL_STATUS_SUCCESS { - return Ok(()); - } else if ret != TDVMCALL_STATUS_RETRY { - return Err(ret.into()); - } - - let retry_addr = args.r11; - if retry_addr < map_start || retry_addr >= map_end { - return Err(TdVmcallError::Other); - } - - // Increase the retry count for the current page - if retry_addr == map_start { - retry_counter += 1; - continue; - } - - // Failed in a new address, update the `map_start` and reset counter - map_start = retry_addr; - retry_counter = 0; - } - - Err(TdVmcallError::Other) -} - -/// Used to help perform RDMSR operation. -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_rdmsr(index: u32) -> Result { - let mut args = TdVmcallArgs { - r11: TDVMCALL_RDMSR, - r12: index as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(args.r11) -} - -/// Used to help perform WRMSR operation. -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> { - let mut args = TdVmcallArgs { - r11: TDVMCALL_WRMSR, - r12: index as u64, - r13: value, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(()) -} - -/// Used to enable the TD-guest to request the VMM to emulate the CPUID operation -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_cpuid(eax: u32, ecx: u32) -> CpuIdInfo { - let mut args = TdVmcallArgs { - r11: TDVMCALL_CPUID, - r12: eax as u64, - r13: ecx as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); - } - - CpuIdInfo { - eax: (args.r12 & 0xffff_ffff) as u32, - ebx: (args.r13 & 0xffff_ffff) as u32, - ecx: (args.r14 & 0xffff_ffff) as u32, - edx: (args.r15 & 0xffff_ffff) as u32, - } -} - -/// Used to request the host VMM specify which interrupt vector to use as an event-notify -/// vector. -/// -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_setup_event_notify(vector: u64) -> Result<(), TdVmcallError> { - let mut args = TdVmcallArgs { - r11: TDVMCALL_SETUPEVENTNOTIFY, - r12: vector, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(()) -} - -/// Used to invoke a request to generate a TD-Quote signing by a TD-Quoting Enclave -/// operating in the host environment. -/// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -/// -/// * buffer: a piece of 4KB-aligned shared memory -pub fn tdvmcall_get_quote(buffer: &mut [u8]) -> Result<(), TdVmcallError> { - let addr = buffer.as_mut_ptr() as u64 | *SHARED_MASK; - - let mut args = TdVmcallArgs { - r11: TDVMCALL_GETQUOTE, - r12: addr, - r13: buffer.len() as u64, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(()) -} - -/// TDG.VP.VMCALL defines an interface for the command/response that -/// may have long latency. -/// Details can be found in TDX GHCI v1.5 spec section 'TDG.VP.VMCALL' -/// -/// * command: a piece of 4KB-aligned shared memory as input -/// * response: a piece of 4KB-aligned shared memory as ouput -/// * interrupt: event notification interrupt vector, valid values [32-255] -/// * wait_time: Maximum wait time for the command and response -pub fn tdvmcall_service( - command: &[u8], - response: &mut [u8], - interrupt: u64, - wait_time: u64, -) -> Result<(), TdVmcallError> { - let command = command.as_ptr() as u64 | *SHARED_MASK; - let response = response.as_mut_ptr() as u64 | *SHARED_MASK; - - // Ensure the address is aligned to 4K bytes - if (command & 0xfff) != 0 || (response & 0xfff) != 0 { - return Err(TdVmcallError::VmcallAlignError); - } - - // Ensure that the interrupt vector is in a valid range - if (1..32).contains(&interrupt) { - return Err(TdVmcallError::VmcallOperandInvalid); - } - - let mut args = TdVmcallArgs { - r11: TDVMCALL_SERVICE, - r12: command, - r13: response, - r14: interrupt, - r15: wait_time, - ..Default::default() - }; - - let ret = td_vmcall(&mut args); - - if ret != TDVMCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(()) -} - -/// Get guest TD execution environment information -/// -/// Details can be found in TDX Module ABI spec section 'TDG.VP.INFO Leaf' -pub fn tdcall_get_td_info() -> Result { - let mut args = TdcallArgs { - rax: TDCALL_TDINFO, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - let td_info = TdInfo { - gpaw: args.rcx & 0x3f, - attributes: args.rdx, - max_vcpus: (args.r8 >> 32) as u32, - num_vcpus: args.r8 as u32, - vcpu_index: args.r9 as u32, - ..Default::default() - }; - - Ok(td_info) -} - -/// Extend a TDCS.RTMR measurement register -/// -/// Details can be found in TDX Module ABI spec section 'TDG.VP.INFO Leaf' -pub fn tdcall_extend_rtmr(digest: &TdxDigest, mr_index: u32) -> Result<(), TdCallError> { - let buffer: u64 = core::ptr::addr_of!(digest.data) as u64; - - let mut args = TdcallArgs { - rax: TDCALL_TDEXTENDRTMR, - rcx: buffer, - rdx: mr_index as u64, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(()) -} - -/// Get virtualization exception information for the recent #VE -/// -/// Details can be found in TDX Module ABI spec section 'TDG.VP.VEINFO.GET Leaf' -pub fn tdcall_get_ve_info() -> Result { - let mut args = TdcallArgs { - rax: TDCALL_TDGETVEINFO, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - let ve_info = TdVeInfo { - exit_reason: args.rcx as u32, - exit_qualification: args.rdx, - guest_la: args.r8, - guest_pa: args.r9, - exit_instruction_length: args.r10 as u32, - exit_instruction_info: (args.r10 >> 32) as u32, - ..Default::default() - }; - - Ok(ve_info) -} - -/// Accept a pending private page, and initialize the page to zeros using the TD ephemeral -/// private key -/// -/// Details can be found in TDX Module ABI spec section 'TDG.MEM.PAGE.Accept Leaf' -pub fn tdcall_accept_page(address: u64) -> Result<(), TdCallError> { - let mut args = TdcallArgs { - rax: TDCALL_TDACCEPTPAGE, - rcx: address, - ..Default::default() - }; - - const MAX_RETRIES_ACCEPT_PAGE: usize = 5; - let mut retry_counter = 0; - let mut ret = 0; - - while retry_counter < MAX_RETRIES_ACCEPT_PAGE { - ret = td_call(&mut args); - - if ret == TDCALL_STATUS_SUCCESS { - return Ok(()); - } else { - match TdCallError::from(ret) { - TdCallError::TdxExitReasonOperandBusy(_) => retry_counter += 1, - e => return Err(e), - } - } - } - - return Err(ret.into()); -} - -/// Accept a range of private pages and initialize the pages to zeros using the TD ephemeral -/// private key. -/// -/// This function is a wrapper to `tdcall_accept_page()`. -pub fn td_accept_pages(address: u64, pages: u64, page_size: u64) { - for i in 0..pages { - let accept_addr = address + i * page_size; - let accept_level = if page_size == PAGE_SIZE_2M { 1 } else { 0 }; - match tdcall_accept_page(accept_addr | accept_level) { - Ok(()) => {} - Err(e) => { - if let TdCallError::LeafSpecific(error_code) = e { - if error_code == TDCALL_STATUS_PAGE_SIZE_MISMATCH { - if page_size == PAGE_SIZE_2M { - td_accept_pages(accept_addr, 512, PAGE_SIZE_4K); - continue; - } - } else if error_code == TDCALL_STATUS_PAGE_ALREADY_ACCEPTED { - continue; - } - } - panic!( - "Accept Page Error: 0x{:x}, page_size: {}, err {:x?}\n", - accept_addr, page_size, e - ); - } - } - } -} - -/// Accept a range of either 4K normal pages or 2M huge pages. This is basically a wrapper over -/// td_accept_pages and initializes the pages to zero using the TD ephemeral private key. -pub fn td_accept_memory(address: u64, len: u64) { - let mut start = address; - let end = address + len; - - while start < end { - let remaining = end - start; - - // Try larger accepts first to keep 1G/2M Secure EPT entries - // where possible and speeds up process by cutting number of - // tdcalls (if successful). - if remaining >= PAGE_SIZE_2M && (start & (PAGE_SIZE_2M - 1)) == 0 { - let npages = remaining >> 21; - td_accept_pages(start, npages, PAGE_SIZE_2M); - start += npages << 21; - } else if remaining >= PAGE_SIZE_4K && (start & (PAGE_SIZE_4K - 1)) == 0 { - let mut npages = remaining >> 12; - // Try to consume in 4K chunks until 2M aligned. - if remaining >= PAGE_SIZE_2M { - npages = (PAGE_SIZE_2M - (start & (PAGE_SIZE_2M - 1))) >> 12; - } - td_accept_pages(start, npages, PAGE_SIZE_4K); - start += npages << 12; - } else { - panic!("Accept Memory Error: 0x{:x}, length: {}\n", address, len); - } - } -} - -/// Get the guest physical address (GPA) width via TDG.VP.INFO -/// The GPA width can be used to determine the shared-bit of GPA -pub fn td_shared_mask() -> Option { - let td_info = tdcall_get_td_info().ok()?; - let gpaw = (td_info.gpaw & 0x3f) as u8; - - // Detail can be found in TDX Module v1.5 ABI spec section 'TDVPS(excluding TD VMCS)'. - if gpaw == 48 || gpaw == 52 { - Some(1u64 << (gpaw - 1)) - } else { - None - } -} - -/// Used by a service TD to read a metadata field (control structure field) of -/// a target TD. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SERVTD.RD Leaf'. -pub fn tdcall_servtd_rd( - binding_handle: u64, - field_identifier: u64, - target_td_uuid: &[u64], -) -> Result { - if target_td_uuid.len() != TARGET_TD_UUID_NUM { - return Err(TdCallError::TdxExitInvalidParameters); - } - - let mut args = TdcallArgs { - rax: TDCALL_SERVTD_RD, - rcx: binding_handle, - rdx: field_identifier, - r10: target_td_uuid[0], - r11: target_td_uuid[1], - r12: target_td_uuid[2], - r13: target_td_uuid[3], - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - let sertd_rw_result = ServtdRWResult { - content: args.r8, - uuid: [args.r10, args.r11, args.r12, args.r13], - }; - - Ok(sertd_rw_result) -} - -/// Used by a service TD to write a metadata field (control structure field) of -/// a target TD. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SERVTD.RD Leaf'. -pub fn tdcall_servtd_wr( - binding_handle: u64, - field_identifier: u64, - data: u64, - target_td_uuid: &[u64], -) -> Result { - if target_td_uuid.len() != TARGET_TD_UUID_NUM { - return Err(TdCallError::TdxExitInvalidParameters); - } - - let mut args = TdcallArgs { - rax: TDCALL_SERVTD_WR, - rcx: binding_handle, - rdx: field_identifier, - r8: data, - r9: u64::MAX, - r10: target_td_uuid[0], - r11: target_td_uuid[1], - r12: target_td_uuid[2], - r13: target_td_uuid[3], - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - let result = ServtdRWResult { - content: args.r8, - uuid: [args.r10, args.r11, args.r12, args.r13], - }; - - Ok(result) -} - -/// Used to read a TDX Module global-scope metadata field. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SYS.RD Leaf'. -pub fn tdcall_sys_rd(field_identifier: u64) -> core::result::Result<(u64, u64), TdCallError> { - let mut args = TdcallArgs { - rax: TDCALL_SYS_RD, - rdx: field_identifier, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok((args.rdx, args.r8)) -} - -/// Read a VCPU-scope metadata field (control structure field) of a TD. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.RD Leaf'. -pub fn tdcall_vp_read(field: u64) -> Result<(u64, u64), TdCallError> { - let mut args = TdcallArgs { - rax: TDCALL_VP_RD, - rdx: field, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok((args.rdx, args.r8)) -} - -/// Write a VCPU-scope metadata field (control structure field) of a TD. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.WR Leaf'. -pub fn tdcall_vp_write(field: u64, value: u64, mask: u64) -> Result { - let mut args = TdcallArgs { - rax: TDCALL_VP_WR, - rdx: field, - r8: value, - r9: mask, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(args.r8) -} - -/// Invalidate mappings in the translation lookaside buffers (TLBs) and paging-structure caches -/// for a specified L2 VM and a specified list of 4KB page linear addresses. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.INVVPID Leaf'. -pub fn tdcall_vp_invvpid(flags: u64, gla: u64) -> Result { - let mut args = TdcallArgs { - rax: TDCALL_VP_INVVPID, - rcx: flags, - rdx: gla, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(args.rdx) -} - -/// Invalidate cached EPT translations for selected L2 VM. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.INVEPT Leaf'. -pub fn tdcall_vp_invept(vm_flags: u64) -> Result<(), TdCallError> { - let mut args = TdcallArgs { - rax: TDCALL_VP_INVEPT, - rcx: vm_flags, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(()) -} - -/// Enter L2 VCPU operation. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.ENTER Leaf'. -pub fn tdcall_vp_enter(vm_flags: u64, gpa: u64) -> TdcallArgs { - let mut args = TdcallArgs { - rax: TDCALL_VP_ENTER, - rcx: vm_flags, - rdx: gpa, - ..Default::default() - }; - - td_call(&mut args); - - args -} - -/// Read a TD-scope metadata field (control structure field) of a TD. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VM.RD Leaf'. -pub fn tdcall_vm_read(field: u64, version: u8) -> Result<(u64, u64), TdCallError> { - let mut args = TdcallArgs { - rax: TDCALL_VM_RD | (version as u64) << 16, - rdx: field, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok((args.rdx, args.r8)) -} - -/// Write a TD-scope metadata field (control structure field) of a TD. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VM.WR Leaf'. -pub fn tdcall_vm_write(field: u64, value: u64, mask: u64) -> Result { - let mut args = TdcallArgs { - rax: TDCALL_VM_WR, - rdx: field, - r8: value, - r9: mask, - ..Default::default() - }; - - let ret = td_call(&mut args); - - if ret != TDCALL_STATUS_SUCCESS { - return Err(ret.into()); - } - - Ok(args.r8) -} - -/// Write the attributes of a private page. Create or remove L2 page aliases as required. -/// -/// Details can be found in TDX Module v1.5 ABI spec section 'TDG.MEM.PAGE.ATTR.WR Leaf'. -pub fn tdcall_mem_page_attr_wr( - gpa_mapping: u64, - gpa_attr: u64, - attr_flags: u64, -) -> Result<(u64, u64), TdCallError> { - let mut args = TdcallArgs { - rax: TDCALL_MEM_PAGE_ATTR_WR, - rcx: gpa_mapping, - rdx: gpa_attr, - r8: attr_flags, - ..Default::default() - }; - - const MAX_RETRIES_ATTR_WR: usize = 5; - let mut retry_counter = 0; - let mut ret = 0; - - while retry_counter < MAX_RETRIES_ATTR_WR { - ret = td_call(&mut args); - - if ret == TDCALL_STATUS_SUCCESS { - return Ok((args.rcx, args.rdx)); - } else { - match TdCallError::from(ret) { - TdCallError::TdxExitReasonOperandBusy(_) => retry_counter += 1, - e => return Err(e), - } - } - } - - return Err(ret.into()); -} - -#[cfg(test)] -mod tests { - use super::*; - use core::mem::{align_of, size_of}; - - #[test] - fn test_struct_size_alignment() { - assert_eq!(align_of::(), 64); - assert_eq!(size_of::(), 64); - assert_eq!(size_of::(), 48); - assert_eq!(size_of::(), 48); - } - - #[test] - fn test_tdcall_servtd_rd() { - let uuid: [u64; 3] = [0; 3]; - let ret = tdcall_servtd_rd(0x0, 0x0, &uuid); - - assert!(ret.is_err()); - } - - #[test] - fn test_tdcall_servtd_wr() { - let uuid: [u64; 3] = [0; 3]; - let ret = tdcall_servtd_wr(0x0, 0x0, 0x0, &uuid); - - assert!(ret.is_err()); - } -} From 3f7069d383efa717e6e9bf2381b5cac358d3815b Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:10:13 +0100 Subject: [PATCH 03/31] tdx-tdcall: move remaining tdcall functions into tdcall.rs Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/lib.rs | 97 ---------------------------------------- tdx-tdcall/src/tdcall.rs | 94 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 97 deletions(-) diff --git a/tdx-tdcall/src/lib.rs b/tdx-tdcall/src/lib.rs index f41fb664..44a5571d 100644 --- a/tdx-tdcall/src/lib.rs +++ b/tdx-tdcall/src/lib.rs @@ -30,104 +30,7 @@ pub const USE_TDX_EMULATION: bool = false; pub mod asm; pub mod tdreport; -pub mod tdx; #[cfg(feature = "tdvmcall")] pub mod tdvmcall; #[cfg(feature = "tdcall")] pub mod tdcall; - -// Guest-Side (TDCALL) interface functions leaf numbers -const TDCALL_TDINFO: u64 = 1; -const TDCALL_TDEXTENDRTMR: u64 = 2; -const TDCALL_TDGETVEINFO: u64 = 3; -const TDCALL_TDREPORT: u64 = 4; -const TDCALL_TDACCEPTPAGE: u64 = 6; -const TDCALL_VM_RD: u64 = 7; -const TDCALL_VM_WR: u64 = 8; -const TDCALL_VP_RD: u64 = 9; -const TDCALL_VP_WR: u64 = 10; -const TDCALL_SYS_RD: u64 = 11; -const TDCALL_SERVTD_RD: u64 = 18; -const TDCALL_SERVTD_WR: u64 = 20; -const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24; -const TDCALL_VP_ENTER: u64 = 25; -const TDCALL_VP_INVEPT: u64 = 26; -const TDCALL_VP_INVVPID: u64 = 27; - -// TDCALL completion status code -const TDCALL_STATUS_SUCCESS: u64 = 0; - -// leaf-specific completion status code -pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000; -pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001; - - -// An extended public wrapper for use of asm_td_vmcall. -// -// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall` -pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 { - unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) } -} - -// Wrapper for use of asm_td_call, this function takes a mutable reference of a -// TdVmcallArgs structure to ensure the input is valid -// -// ## TDCALL ABI -// Defined in TDX Module 1.0 Spec section 'TDCALL Instruction (Common)' -// -// ### Input Operands: -// * RAX - Leaf and version numbers. -// * Other - Used by leaf functions as input values. -// -// ### Output Operands: -// * RAX - Instruction return code. -// * Other - Used by leaf functions as output values. -// -pub fn td_call(args: &mut TdcallArgs) -> u64 { - unsafe { asm::asm_td_call(args as *mut TdcallArgs as *mut c_void) } -} - -// Used to pass the values of input/output register when performing TDCALL -// instruction -#[repr(C)] -#[derive(Default)] -pub struct TdcallArgs { - pub rax: u64, - pub rcx: u64, - pub rdx: u64, - pub r8: u64, - pub r9: u64, - pub r10: u64, - pub r11: u64, - pub r12: u64, - pub r13: u64, -} - -/// TDCALL instruction return error code -/// -/// Refer to Intel TDX Module 1.0 Specifiction section 'TDCALL Instruction (Common)' -#[derive(Debug, PartialEq)] -pub enum TdCallError { - // Invalid parameters - TdxExitInvalidParameters, - - // The operand is busy (e.g., it is locked in Exclusive mode) - TdxExitReasonOperandBusy(u32), - - // Operand is invalid (e.g., illegal leaf number) - TdxExitReasonOperandInvalid(u32), - - // Error code defined by individual leaf function - LeafSpecific(u64), -} - -// TDCALL Completion Status Codes (Returned in RAX) Definition -impl From for TdCallError { - fn from(val: u64) -> Self { - match val >> 32 { - 0x8000_0200 => Self::TdxExitReasonOperandBusy(val as u32), - 0xC000_0100 => Self::TdxExitReasonOperandInvalid(val as u32), - _ => Self::LeafSpecific(val), - } - } -} diff --git a/tdx-tdcall/src/tdcall.rs b/tdx-tdcall/src/tdcall.rs index d8eac3a3..07000172 100644 --- a/tdx-tdcall/src/tdcall.rs +++ b/tdx-tdcall/src/tdcall.rs @@ -15,6 +15,31 @@ pub const PAGE_SIZE_4K: u64 = 0x1000; pub const PAGE_SIZE_2M: u64 = 0x200000; const TARGET_TD_UUID_NUM: usize = 4; +// Guest-Side (TDCALL) interface functions leaf numbers +const TDCALL_TDINFO: u64 = 1; +const TDCALL_TDEXTENDRTMR: u64 = 2; +const TDCALL_TDGETVEINFO: u64 = 3; +const TDCALL_TDREPORT: u64 = 4; +const TDCALL_TDACCEPTPAGE: u64 = 6; +const TDCALL_VM_RD: u64 = 7; +const TDCALL_VM_WR: u64 = 8; +const TDCALL_VP_RD: u64 = 9; +const TDCALL_VP_WR: u64 = 10; +const TDCALL_SYS_RD: u64 = 11; +const TDCALL_SERVTD_RD: u64 = 18; +const TDCALL_SERVTD_WR: u64 = 20; +const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24; +const TDCALL_VP_ENTER: u64 = 25; +const TDCALL_VP_INVEPT: u64 = 26; +const TDCALL_VP_INVVPID: u64 = 27; + +// TDCALL completion status code +const TDCALL_STATUS_SUCCESS: u64 = 0; + +// leaf-specific completion status code +pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000; +pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001; + /// SHA384 digest value extended to RTMR /// Both alignment and size are 64 bytes. #[repr(C, align(64))] @@ -55,6 +80,75 @@ pub struct ServtdRWResult { pub uuid: [u64; 4], } +// An extended public wrapper for use of asm_td_vmcall. +// +// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall` +pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 { + unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) } +} + +// Wrapper for use of asm_td_call, this function takes a mutable reference of a +// TdVmcallArgs structure to ensure the input is valid +// +// ## TDCALL ABI +// Defined in TDX Module 1.0 Spec section 'TDCALL Instruction (Common)' +// +// ### Input Operands: +// * RAX - Leaf and version numbers. +// * Other - Used by leaf functions as input values. +// +// ### Output Operands: +// * RAX - Instruction return code. +// * Other - Used by leaf functions as output values. +// +pub fn td_call(args: &mut TdcallArgs) -> u64 { + unsafe { asm::asm_td_call(args as *mut TdcallArgs as *mut c_void) } +} + +// Used to pass the values of input/output register when performing TDCALL +// instruction +#[repr(C)] +#[derive(Default)] +pub struct TdcallArgs { + pub rax: u64, + pub rcx: u64, + pub rdx: u64, + pub r8: u64, + pub r9: u64, + pub r10: u64, + pub r11: u64, + pub r12: u64, + pub r13: u64, +} + +/// TDCALL instruction return error code +/// +/// Refer to Intel TDX Module 1.0 Specifiction section 'TDCALL Instruction (Common)' +#[derive(Debug, PartialEq)] +pub enum TdCallError { + // Invalid parameters + TdxExitInvalidParameters, + + // The operand is busy (e.g., it is locked in Exclusive mode) + TdxExitReasonOperandBusy(u32), + + // Operand is invalid (e.g., illegal leaf number) + TdxExitReasonOperandInvalid(u32), + + // Error code defined by individual leaf function + LeafSpecific(u64), +} + +// TDCALL Completion Status Codes (Returned in RAX) Definition +impl From for TdCallError { + fn from(val: u64) -> Self { + match val >> 32 { + 0x8000_0200 => Self::TdxExitReasonOperandBusy(val as u32), + 0xC000_0100 => Self::TdxExitReasonOperandInvalid(val as u32), + _ => Self::LeafSpecific(val), + } + } +} /// Get guest TD execution environment information /// From 614c4ad6975943235c860b9bbc1afdb5d5ee1c35 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:14:17 +0100 Subject: [PATCH 04/31] tdx-tdcall: remove tdvmcall_ prefix Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/tdvmcall.rs | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tdx-tdcall/src/tdvmcall.rs b/tdx-tdcall/src/tdvmcall.rs index b2c7a33b..c44ef9b9 100644 --- a/tdx-tdcall/src/tdvmcall.rs +++ b/tdx-tdcall/src/tdvmcall.rs @@ -117,7 +117,7 @@ pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 { /// Used to help perform HLT operation. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_halt() { +pub fn halt() { let interrupt_blocked = !rflags::read().contains(RFlags::INTERRUPT_FLAG); let mut args = TdVmcallArgs { @@ -133,7 +133,7 @@ pub fn tdvmcall_halt() { /// `sti;hlt` which typically used for idle is not working in this case since `hlt` instruction /// must be the instruction next to `sti`. To use safe halt, `sti` must be executed just before /// `tdcall` instruction. -pub fn tdvmcall_sti_halt() { +pub fn sti_halt() { let mut args = TdVmcallArgs { r11: TDVMCALL_HALT, ..Default::default() @@ -150,7 +150,7 @@ const IO_WRITE: u64 = 1; /// Request the VMM perform single byte IO read operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_read_8(port: u16) -> u8 { +pub fn io_read_8(port: u16) -> u8 { let mut args = TdVmcallArgs { r11: TDVMCALL_IO, r12: core::mem::size_of::() as u64, @@ -162,7 +162,7 @@ pub fn tdvmcall_io_read_8(port: u16) -> u8 { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } (args.r11 & 0xff) as u8 @@ -171,7 +171,7 @@ pub fn tdvmcall_io_read_8(port: u16) -> u8 { /// Request the VMM perform 2-bytes byte IO read operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_read_16(port: u16) -> u16 { +pub fn io_read_16(port: u16) -> u16 { let mut args = TdVmcallArgs { r11: TDVMCALL_IO, r12: core::mem::size_of::() as u64, @@ -183,7 +183,7 @@ pub fn tdvmcall_io_read_16(port: u16) -> u16 { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } (args.r11 & 0xffff) as u16 @@ -192,7 +192,7 @@ pub fn tdvmcall_io_read_16(port: u16) -> u16 { /// Request the VMM perform 4-bytes byte IO read operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_read_32(port: u16) -> u32 { +pub fn io_read_32(port: u16) -> u32 { let mut args = TdVmcallArgs { r11: TDVMCALL_IO, r12: core::mem::size_of::() as u64, @@ -204,7 +204,7 @@ pub fn tdvmcall_io_read_32(port: u16) -> u32 { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } (args.r11 & 0xffff_ffff) as u32 @@ -213,7 +213,7 @@ pub fn tdvmcall_io_read_32(port: u16) -> u32 { /// Request the VMM perform single byte IO write operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_write_8(port: u16, byte: u8) { +pub fn io_write_8(port: u16, byte: u8) { let mut args = TdVmcallArgs { r11: TDVMCALL_IO, r12: core::mem::size_of::() as u64, @@ -226,14 +226,14 @@ pub fn tdvmcall_io_write_8(port: u16, byte: u8) { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } } /// Request the VMM perform 2-bytes IO write operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_write_16(port: u16, byte: u16) { +pub fn io_write_16(port: u16, byte: u16) { let mut args = TdVmcallArgs { r11: TDVMCALL_IO, r12: core::mem::size_of::() as u64, @@ -246,14 +246,14 @@ pub fn tdvmcall_io_write_16(port: u16, byte: u16) { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } } /// Request the VMM perform 4-bytes IO write operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_io_write_32(port: u16, byte: u32) { +pub fn io_write_32(port: u16, byte: u32) { let mut args = TdVmcallArgs { r11: TDVMCALL_IO, r12: core::mem::size_of::() as u64, @@ -266,14 +266,14 @@ pub fn tdvmcall_io_write_32(port: u16, byte: u32) { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } } /// Used to help request the VMM perform emulated-MMIO-write operation. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<#VE.RequestMMIO>' -pub fn tdvmcall_mmio_write(address: *const T, value: T) { +pub fn mmio_write(address: *const T, value: T) { let address = address as u64 | *SHARED_MASK; fence(Ordering::SeqCst); let val = unsafe { *(core::ptr::addr_of!(value) as *const u64) }; @@ -290,14 +290,14 @@ pub fn tdvmcall_mmio_write(address: *const T, value: T) { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } } /// Used to help request the VMM perform emulated-MMIO-read operation. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL<#VE.RequestMMIO>' -pub fn tdvmcall_mmio_read(address: usize) -> T { +pub fn mmio_read(address: usize) -> T { let address = address as u64 | *SHARED_MASK; fence(Ordering::SeqCst); @@ -312,7 +312,7 @@ pub fn tdvmcall_mmio_read(address: usize) -> T { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } unsafe { *(core::ptr::addr_of!(args.r11) as *const T) } @@ -322,7 +322,7 @@ pub fn tdvmcall_mmio_read(address: usize) -> T { /// It can be used to convert page mappings from private to shared or vice versa /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_mapgpa(shared: bool, paddr: u64, length: usize) -> Result<(), TdVmcallError> { +pub fn mapgpa(shared: bool, paddr: u64, length: usize) -> Result<(), TdVmcallError> { let share_bit = *SHARED_MASK; let mut map_start = if shared { paddr | share_bit @@ -378,7 +378,7 @@ pub fn tdvmcall_mapgpa(shared: bool, paddr: u64, length: usize) -> Result<(), Td /// Used to help perform RDMSR operation. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_rdmsr(index: u32) -> Result { +pub fn rdmsr(index: u32) -> Result { let mut args = TdVmcallArgs { r11: TDVMCALL_RDMSR, r12: index as u64, @@ -397,7 +397,7 @@ pub fn tdvmcall_rdmsr(index: u32) -> Result { /// Used to help perform WRMSR operation. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> { +pub fn wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> { let mut args = TdVmcallArgs { r11: TDVMCALL_WRMSR, r12: index as u64, @@ -417,7 +417,7 @@ pub fn tdvmcall_wrmsr(index: u32, value: u64) -> Result<(), TdVmcallError> { /// Used to enable the TD-guest to request the VMM to emulate the CPUID operation /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_cpuid(eax: u32, ecx: u32) -> CpuIdInfo { +pub fn cpuid(eax: u32, ecx: u32) -> CpuIdInfo { let mut args = TdVmcallArgs { r11: TDVMCALL_CPUID, r12: eax as u64, @@ -428,7 +428,7 @@ pub fn tdvmcall_cpuid(eax: u32, ecx: u32) -> CpuIdInfo { let ret = td_vmcall(&mut args); if ret != TDVMCALL_STATUS_SUCCESS { - tdvmcall_halt(); + halt(); } CpuIdInfo { @@ -443,7 +443,7 @@ pub fn tdvmcall_cpuid(eax: u32, ecx: u32) -> CpuIdInfo { /// vector. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' -pub fn tdvmcall_setup_event_notify(vector: u64) -> Result<(), TdVmcallError> { +pub fn setup_event_notify(vector: u64) -> Result<(), TdVmcallError> { let mut args = TdVmcallArgs { r11: TDVMCALL_SETUPEVENTNOTIFY, r12: vector, @@ -464,7 +464,7 @@ pub fn tdvmcall_setup_event_notify(vector: u64) -> Result<(), TdVmcallError> { /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' /// /// * buffer: a piece of 4KB-aligned shared memory -pub fn tdvmcall_get_quote(buffer: &mut [u8]) -> Result<(), TdVmcallError> { +pub fn get_quote(buffer: &mut [u8]) -> Result<(), TdVmcallError> { let addr = buffer.as_mut_ptr() as u64 | *SHARED_MASK; let mut args = TdVmcallArgs { @@ -491,7 +491,7 @@ pub fn tdvmcall_get_quote(buffer: &mut [u8]) -> Result<(), TdVmcallError> { /// * response: a piece of 4KB-aligned shared memory as ouput /// * interrupt: event notification interrupt vector, valid values [32-255] /// * wait_time: Maximum wait time for the command and response -pub fn tdvmcall_service( +pub fn service( command: &[u8], response: &mut [u8], interrupt: u64, From 6cb7de46bd79b3bf098949e703a00646059f125d Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:14:53 +0100 Subject: [PATCH 05/31] tdx-tdcall: remove tdcall_ prefix Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/tdcall.rs | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tdx-tdcall/src/tdcall.rs b/tdx-tdcall/src/tdcall.rs index 07000172..d7dd79d7 100644 --- a/tdx-tdcall/src/tdcall.rs +++ b/tdx-tdcall/src/tdcall.rs @@ -153,7 +153,7 @@ impl From for TdCallError { /// Get guest TD execution environment information /// /// Details can be found in TDX Module ABI spec section 'TDG.VP.INFO Leaf' -pub fn tdcall_get_td_info() -> Result { +pub fn get_td_info() -> Result { let mut args = TdcallArgs { rax: TDCALL_TDINFO, ..Default::default() @@ -180,7 +180,7 @@ pub fn tdcall_get_td_info() -> Result { /// Extend a TDCS.RTMR measurement register /// /// Details can be found in TDX Module ABI spec section 'TDG.VP.INFO Leaf' -pub fn tdcall_extend_rtmr(digest: &TdxDigest, mr_index: u32) -> Result<(), TdCallError> { +pub fn extend_rtmr(digest: &TdxDigest, mr_index: u32) -> Result<(), TdCallError> { let buffer: u64 = core::ptr::addr_of!(digest.data) as u64; let mut args = TdcallArgs { @@ -202,7 +202,7 @@ pub fn tdcall_extend_rtmr(digest: &TdxDigest, mr_index: u32) -> Result<(), TdCal /// Get virtualization exception information for the recent #VE /// /// Details can be found in TDX Module ABI spec section 'TDG.VP.VEINFO.GET Leaf' -pub fn tdcall_get_ve_info() -> Result { +pub fn get_ve_info() -> Result { let mut args = TdcallArgs { rax: TDCALL_TDGETVEINFO, ..Default::default() @@ -231,7 +231,7 @@ pub fn tdcall_get_ve_info() -> Result { /// private key /// /// Details can be found in TDX Module ABI spec section 'TDG.MEM.PAGE.Accept Leaf' -pub fn tdcall_accept_page(address: u64) -> Result<(), TdCallError> { +pub fn accept_page(address: u64) -> Result<(), TdCallError> { let mut args = TdcallArgs { rax: TDCALL_TDACCEPTPAGE, rcx: address, @@ -261,12 +261,12 @@ pub fn tdcall_accept_page(address: u64) -> Result<(), TdCallError> { /// Accept a range of private pages and initialize the pages to zeros using the TD ephemeral /// private key. /// -/// This function is a wrapper to `tdcall_accept_page()`. +/// This function is a wrapper to `accept_page()`. pub fn td_accept_pages(address: u64, pages: u64, page_size: u64) { for i in 0..pages { let accept_addr = address + i * page_size; let accept_level = if page_size == PAGE_SIZE_2M { 1 } else { 0 }; - match tdcall_accept_page(accept_addr | accept_level) { + match accept_page(accept_addr | accept_level) { Ok(()) => {} Err(e) => { if let TdCallError::LeafSpecific(error_code) = e { @@ -321,7 +321,7 @@ pub fn td_accept_memory(address: u64, len: u64) { /// Get the guest physical address (GPA) width via TDG.VP.INFO /// The GPA width can be used to determine the shared-bit of GPA pub fn td_shared_mask() -> Option { - let td_info = tdcall_get_td_info().ok()?; + let td_info = get_td_info().ok()?; let gpaw = (td_info.gpaw & 0x3f) as u8; // Detail can be found in TDX Module v1.5 ABI spec section 'TDVPS(excluding TD VMCS)'. @@ -336,7 +336,7 @@ pub fn td_shared_mask() -> Option { /// a target TD. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SERVTD.RD Leaf'. -pub fn tdcall_servtd_rd( +pub fn servtd_rd( binding_handle: u64, field_identifier: u64, target_td_uuid: &[u64], @@ -374,7 +374,7 @@ pub fn tdcall_servtd_rd( /// a target TD. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SERVTD.RD Leaf'. -pub fn tdcall_servtd_wr( +pub fn servtd_wr( binding_handle: u64, field_identifier: u64, data: u64, @@ -413,7 +413,7 @@ pub fn tdcall_servtd_wr( /// Used to read a TDX Module global-scope metadata field. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.SYS.RD Leaf'. -pub fn tdcall_sys_rd(field_identifier: u64) -> core::result::Result<(u64, u64), TdCallError> { +pub fn sys_rd(field_identifier: u64) -> core::result::Result<(u64, u64), TdCallError> { let mut args = TdcallArgs { rax: TDCALL_SYS_RD, rdx: field_identifier, @@ -432,7 +432,7 @@ pub fn tdcall_sys_rd(field_identifier: u64) -> core::result::Result<(u64, u64), /// Read a VCPU-scope metadata field (control structure field) of a TD. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.RD Leaf'. -pub fn tdcall_vp_read(field: u64) -> Result<(u64, u64), TdCallError> { +pub fn vp_read(field: u64) -> Result<(u64, u64), TdCallError> { let mut args = TdcallArgs { rax: TDCALL_VP_RD, rdx: field, @@ -451,7 +451,7 @@ pub fn tdcall_vp_read(field: u64) -> Result<(u64, u64), TdCallError> { /// Write a VCPU-scope metadata field (control structure field) of a TD. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.WR Leaf'. -pub fn tdcall_vp_write(field: u64, value: u64, mask: u64) -> Result { +pub fn vp_write(field: u64, value: u64, mask: u64) -> Result { let mut args = TdcallArgs { rax: TDCALL_VP_WR, rdx: field, @@ -473,7 +473,7 @@ pub fn tdcall_vp_write(field: u64, value: u64, mask: u64) -> Result Result { +pub fn vp_invvpid(flags: u64, gla: u64) -> Result { let mut args = TdcallArgs { rax: TDCALL_VP_INVVPID, rcx: flags, @@ -493,7 +493,7 @@ pub fn tdcall_vp_invvpid(flags: u64, gla: u64) -> Result { /// Invalidate cached EPT translations for selected L2 VM. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.INVEPT Leaf'. -pub fn tdcall_vp_invept(vm_flags: u64) -> Result<(), TdCallError> { +pub fn vp_invept(vm_flags: u64) -> Result<(), TdCallError> { let mut args = TdcallArgs { rax: TDCALL_VP_INVEPT, rcx: vm_flags, @@ -512,7 +512,7 @@ pub fn tdcall_vp_invept(vm_flags: u64) -> Result<(), TdCallError> { /// Enter L2 VCPU operation. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VP.ENTER Leaf'. -pub fn tdcall_vp_enter(vm_flags: u64, gpa: u64) -> TdcallArgs { +pub fn vp_enter(vm_flags: u64, gpa: u64) -> TdcallArgs { let mut args = TdcallArgs { rax: TDCALL_VP_ENTER, rcx: vm_flags, @@ -528,7 +528,7 @@ pub fn tdcall_vp_enter(vm_flags: u64, gpa: u64) -> TdcallArgs { /// Read a TD-scope metadata field (control structure field) of a TD. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VM.RD Leaf'. -pub fn tdcall_vm_read(field: u64, version: u8) -> Result<(u64, u64), TdCallError> { +pub fn vm_read(field: u64, version: u8) -> Result<(u64, u64), TdCallError> { let mut args = TdcallArgs { rax: TDCALL_VM_RD | (version as u64) << 16, rdx: field, @@ -547,7 +547,7 @@ pub fn tdcall_vm_read(field: u64, version: u8) -> Result<(u64, u64), TdCallError /// Write a TD-scope metadata field (control structure field) of a TD. /// /// Details can be found in TDX Module v1.5 ABI spec section 'TDG.VM.WR Leaf'. -pub fn tdcall_vm_write(field: u64, value: u64, mask: u64) -> Result { +pub fn vm_write(field: u64, value: u64, mask: u64) -> Result { let mut args = TdcallArgs { rax: TDCALL_VM_WR, rdx: field, @@ -568,7 +568,7 @@ pub fn tdcall_vm_write(field: u64, value: u64, mask: u64) -> Result Date: Mon, 3 Mar 2025 15:17:42 +0100 Subject: [PATCH 06/31] Replace tdvmcall_ with tdvmcall:: Signed-off-by: Stanislaw Grams --- td-exception/src/interrupt.rs | 22 +++++++++++----------- td-logger/src/lib.rs | 2 +- td-payload/src/arch/x86_64/apic.rs | 6 +++--- td-payload/src/arch/x86_64/serial.rs | 2 +- td-payload/src/arch/x86_64/shared.rs | 4 ++-- tdx-tdcall/CHANGELOG.md | 4 ++-- tdx-tdcall/src/asm/mod.rs | 2 +- tests/test-td-payload/src/testiorw32.rs | 8 ++++---- tests/test-td-payload/src/testiorw8.rs | 8 ++++---- tests/test-td-payload/src/testmsrrw.rs | 6 +++--- 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/td-exception/src/interrupt.rs b/td-exception/src/interrupt.rs index 3b8b3095..eb4ac0b9 100644 --- a/td-exception/src/interrupt.rs +++ b/td-exception/src/interrupt.rs @@ -351,26 +351,26 @@ fn virtualization(stack: &mut InterruptStack) { match ve_info.exit_reason { EXIT_REASON_HLT => { - tdx::tdvmcall_halt(); + tdx::tdvmcall::halt(); } EXIT_REASON_IO_INSTRUCTION => { if !handle_tdx_ioexit(&ve_info, stack) { - tdx::tdvmcall_halt(); + tdx::tdvmcall::halt(); } } EXIT_REASON_MSR_READ => { - let msr = tdx::tdvmcall_rdmsr(stack.scratch.rcx as u32) + let msr = tdx::tdvmcall::rdmsr(stack.scratch.rcx as u32) .expect("fail to perform RDMSR operation\n"); stack.scratch.rax = (msr as u32 & u32::MAX) as usize; // EAX stack.scratch.rdx = ((msr >> 32) as u32 & u32::MAX) as usize; // EDX } EXIT_REASON_MSR_WRITE => { let data = stack.scratch.rax as u64 | ((stack.scratch.rdx as u64) << 32); // EDX:EAX - tdx::tdvmcall_wrmsr(stack.scratch.rcx as u32, data) + tdx::tdvmcall::wrmsr(stack.scratch.rcx as u32, data) .expect("fail to perform WRMSR operation\n"); } EXIT_REASON_CPUID => { - let cpuid = tdx::tdvmcall_cpuid(stack.scratch.rax as u32, stack.scratch.rcx as u32); + let cpuid = tdx::tdvmcall::cpuid(stack.scratch.rax as u32, stack.scratch.rcx as u32); let mask = 0xFFFF_FFFF_0000_0000_usize; stack.scratch.rax = (stack.scratch.rax & mask) | cpuid.eax as usize; stack.preserved.rbx = (stack.preserved.rbx & mask) | cpuid.ebx as usize; @@ -471,17 +471,17 @@ fn handle_tdx_ioexit(ve_info: &tdx::TdVeInfo, stack: &mut InterruptStack) -> boo // Define closure to perform IO port read with different size operands let io_read = |size, port| match size { - 1 => tdx::tdvmcall_io_read_8(port) as u32, - 2 => tdx::tdvmcall_io_read_16(port) as u32, - 4 => tdx::tdvmcall_io_read_32(port), + 1 => tdx::tdvmcall::io_read_8(port) as u32, + 2 => tdx::tdvmcall::io_read_16(port) as u32, + 4 => tdx::tdvmcall::io_read_32(port), _ => 0, }; // Define closure to perform IO port write with different size operands let io_write = |size, port, data| match size { - 1 => tdx::tdvmcall_io_write_8(port, data as u8), - 2 => tdx::tdvmcall_io_write_16(port, data as u16), - 4 => tdx::tdvmcall_io_write_32(port, data), + 1 => tdx::tdvmcall::io_write_8(port, data as u8), + 2 => tdx::tdvmcall::io_write_16(port, data as u16), + 4 => tdx::tdvmcall::io_write_32(port, data), _ => {} }; diff --git a/td-logger/src/lib.rs b/td-logger/src/lib.rs index af2e591a..6a753695 100644 --- a/td-logger/src/lib.rs +++ b/td-logger/src/lib.rs @@ -58,7 +58,7 @@ const SERIAL_IO_PORT: u16 = 0x3F8; #[cfg(feature = "tdx")] fn dbg_port_write(byte: u8) { - tdx_tdcall::tdx::tdvmcall_io_write_8(SERIAL_IO_PORT, byte); + tdx_tdcall::tdx::tdvmcall::io_write_8(SERIAL_IO_PORT, byte); } #[cfg(all(not(feature = "tdx"), feature = "serial-port"))] diff --git a/td-payload/src/arch/x86_64/apic.rs b/td-payload/src/arch/x86_64/apic.rs index 89fc4441..da74d775 100644 --- a/td-payload/src/arch/x86_64/apic.rs +++ b/td-payload/src/arch/x86_64/apic.rs @@ -19,14 +19,14 @@ pub fn enable_apic_interrupt() { // In x2APIC mode, SVR is mapped to MSR address 0x80f. // Since SVR(SIVR) is not virtualized, before we implement the handling in #VE of MSRRD/WR, // use tdvmcall instead direct read/write operation. - let svr = tdx_tdcall::tdx::tdvmcall_rdmsr(0x80f).expect("fail to perform RDMSR operation\n"); - tdx_tdcall::tdx::tdvmcall_wrmsr(0x80f, svr | (0x1 << 8)) + let svr = tdx_tdcall::tdx::tdvmcall::rdmsr(0x80f).expect("fail to perform RDMSR operation\n"); + tdx_tdcall::tdx::tdvmcall::wrmsr(0x80f, svr | (0x1 << 8)) .expect("fail to perform WRMSR operation\n"); } pub fn enable_and_hlt() { #[cfg(feature = "tdx")] - tdx_tdcall::tdx::tdvmcall_sti_halt(); + tdx_tdcall::tdx::tdvmcall::sti_halt(); #[cfg(not(feature = "tdx"))] x86_64::instructions::interrupts::enable_and_hlt() } diff --git a/td-payload/src/arch/x86_64/serial.rs b/td-payload/src/arch/x86_64/serial.rs index d61d2838..dc7988fd 100644 --- a/td-payload/src/arch/x86_64/serial.rs +++ b/td-payload/src/arch/x86_64/serial.rs @@ -21,7 +21,7 @@ const SERIAL_IO_PORT: u16 = 0x3F8; #[cfg(feature = "tdx")] fn io_write(byte: u8) { - tdx_tdcall::tdx::tdvmcall_io_write_8(SERIAL_IO_PORT, byte); + tdx_tdcall::tdx::tdvmcall::io_write_8(SERIAL_IO_PORT, byte); } #[cfg(not(feature = "tdx"))] diff --git a/td-payload/src/arch/x86_64/shared.rs b/td-payload/src/arch/x86_64/shared.rs index 8d05c5cf..f3cffa83 100644 --- a/td-payload/src/arch/x86_64/shared.rs +++ b/td-payload/src/arch/x86_64/shared.rs @@ -11,7 +11,7 @@ pub fn decrypt(addr: u64, length: usize) { set_shared_bit(addr, length); // Safety: Fail to map GPA is a fatal error that we cannot handle - if tdx::tdvmcall_mapgpa(true, addr, length).is_err() { + if tdx::tdvmcall::mapgpa(true, addr, length).is_err() { panic!("Fail to map GPA to shared memory with TDVMCALL"); } } @@ -20,7 +20,7 @@ pub fn encrypt(addr: u64, length: usize) { clear_shared_bit(addr, length); // Safety: Fail to map GPA is a fatal error that we cannot handle - if tdx_tdcall::tdx::tdvmcall_mapgpa(false, addr, length).is_err() { + if tdx_tdcall::tdx::tdvmcall::mapgpa(false, addr, length).is_err() { panic!("Fail to map GPA to private memory with TDVMCALL"); } accept_memory(addr, length); diff --git a/tdx-tdcall/CHANGELOG.md b/tdx-tdcall/CHANGELOG.md index 1b06898f..d3c925e6 100644 --- a/tdx-tdcall/CHANGELOG.md +++ b/tdx-tdcall/CHANGELOG.md @@ -16,8 +16,8 @@ All notable changes to this project will be documented in this file. - Add tdcall to support memory attribute write. ### Changed -- Change return type for tdvmcall_wrmsr, tdvmcall_rdmsr -- Replace the & operator with addr_of! macro for tdvmcall_mmio_write/tdvmcall_mmio_read +- Change return type for tdvmcall::wrmsr, tdvmcall::rdmsr +- Replace the & operator with addr_of! macro for tdvmcall::mmio_write/tdvmcall::mmio_read - Extend TdInfo struct to add vcpu_index field ## [0.1.0] - 2024-06-07 diff --git a/tdx-tdcall/src/asm/mod.rs b/tdx-tdcall/src/asm/mod.rs index 02e43d40..fe3afe62 100644 --- a/tdx-tdcall/src/asm/mod.rs +++ b/tdx-tdcall/src/asm/mod.rs @@ -8,7 +8,7 @@ use core::ffi::c_void; global_asm!(include_str!("tdcall_emu.asm")); #[cfg(feature = "use_tdx_emulation")] -global_asm!(include_str!("tdvmcall_emu.asm")); +global_asm!(include_str!("tdvmcall::emu.asm")); #[cfg(not(feature = "use_tdx_emulation"))] global_asm!(include_str!("tdcall.asm")); diff --git a/tests/test-td-payload/src/testiorw32.rs b/tests/test-td-payload/src/testiorw32.rs index 001db8cc..5485a98c 100644 --- a/tests/test-td-payload/src/testiorw32.rs +++ b/tests/test-td-payload/src/testiorw32.rs @@ -38,14 +38,14 @@ impl TestCase for Tdiorw32 { * io read Century of RTC */ fn run(&mut self) { - tdx::tdvmcall_io_write_8(0x70, 0x32); + tdx::tdvmcall::io_write_8(0x70, 0x32); - let read1 = tdx::tdvmcall_io_read_32(0x71); + let read1 = tdx::tdvmcall::io_read_32(0x71); log::info!("First time read {}\n", read1); - tdx::tdvmcall_io_write_32(0x71, read1 + 1); + tdx::tdvmcall::io_write_32(0x71, read1 + 1); - let read2 = tdx::tdvmcall_io_read_32(0x71); + let read2 = tdx::tdvmcall::io_read_32(0x71); log::info!("Second time read {}\n", read2); if (read1 + 1 != read2) { diff --git a/tests/test-td-payload/src/testiorw8.rs b/tests/test-td-payload/src/testiorw8.rs index 43ac4270..3c3cf95e 100644 --- a/tests/test-td-payload/src/testiorw8.rs +++ b/tests/test-td-payload/src/testiorw8.rs @@ -38,14 +38,14 @@ impl TestCase for Tdiorw8 { * io read Century of RTC */ fn run(&mut self) { - tdx::tdvmcall_io_write_8(0x70, 0x32); + tdx::tdvmcall::io_write_8(0x70, 0x32); - let read1 = tdx::tdvmcall_io_read_8(0x71); + let read1 = tdx::tdvmcall::io_read_8(0x71); log::info!("First time read {}\n", read1); - tdx::tdvmcall_io_write_8(0x71, read1 + 1); + tdx::tdvmcall::io_write_8(0x71, read1 + 1); - let read2 = tdx::tdvmcall_io_read_8(0x71); + let read2 = tdx::tdvmcall::io_read_8(0x71); log::info!("Second time read {}\n", read2); if (read1 + 1 != read2) { diff --git a/tests/test-td-payload/src/testmsrrw.rs b/tests/test-td-payload/src/testmsrrw.rs index d89fa60f..c85066cf 100644 --- a/tests/test-td-payload/src/testmsrrw.rs +++ b/tests/test-td-payload/src/testmsrrw.rs @@ -27,16 +27,16 @@ impl Tdmsrrw { const APIC_SVR_MSR: u32 = 0x80f; // APIC Spurious Vector Register MSR address // Read the current value of the APIC SVR MSR - match tdx::tdvmcall_rdmsr(APIC_SVR_MSR) { + match tdx::tdvmcall::rdmsr(APIC_SVR_MSR) { Ok(read1) => { // Attempt to write the incremented value back to the APIC SVR MSR - if tdx::tdvmcall_wrmsr(APIC_SVR_MSR, read1 + 1).is_err() { + if tdx::tdvmcall::wrmsr(APIC_SVR_MSR, read1 + 1).is_err() { log::info!("Failed to write MSR 0x{:x}", APIC_SVR_MSR); return TestResult::Fail; } // Read the value again to verify the write operation - match tdx::tdvmcall_rdmsr(APIC_SVR_MSR) { + match tdx::tdvmcall::rdmsr(APIC_SVR_MSR) { Ok(read2) if read1 + 1 == read2 => TestResult::Pass, Ok(read2) => { log::info!( From ebc17eee7c4a180f135711d50a4599d99309203a Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:18:46 +0100 Subject: [PATCH 07/31] Replace tdcall_ with tdcall:: Signed-off-by: Stanislaw Grams --- td-exception/src/interrupt.rs | 2 +- td-payload/src/arch/x86_64/shared.rs | 2 +- td-payload/src/bin/example/main.rs | 2 +- td-payload/src/mm/mod.rs | 1 - td-shim/src/bin/td-shim/td/tdx.rs | 4 ++-- tdx-tdcall/CHANGELOG.md | 10 +++++----- tdx-tdcall/src/asm/mod.rs | 2 +- tdx-tdcall/src/asm/tdcall_emu.asm | 4 ++-- tdx-tdcall/src/asm/tdvmcall_emu.asm | 8 ++++---- tests/test-td-payload/src/testtdinfo.rs | 2 +- 10 files changed, 18 insertions(+), 19 deletions(-) diff --git a/td-exception/src/interrupt.rs b/td-exception/src/interrupt.rs index eb4ac0b9..f636e04a 100644 --- a/td-exception/src/interrupt.rs +++ b/td-exception/src/interrupt.rs @@ -347,7 +347,7 @@ const EXIT_REASON_WBINVD: u32 = 54; #[cfg(feature = "tdx")] fn virtualization(stack: &mut InterruptStack) { // Firstly get VE information from TDX module, halt it error occurs - let ve_info = tdx::tdcall_get_ve_info().expect("#VE handler: fail to get VE info\n"); + let ve_info = tdx::tdcall::get_ve_info().expect("#VE handler: fail to get VE info\n"); match ve_info.exit_reason { EXIT_REASON_HLT => { diff --git a/td-payload/src/arch/x86_64/shared.rs b/td-payload/src/arch/x86_64/shared.rs index f3cffa83..fa37a6f8 100644 --- a/td-payload/src/arch/x86_64/shared.rs +++ b/td-payload/src/arch/x86_64/shared.rs @@ -30,7 +30,7 @@ fn accept_memory(addr: u64, length: usize) { let page_num = length / SIZE_4K; for p in 0..page_num { - if let Err(e) = tdx::tdcall_accept_page(addr + (p * SIZE_4K) as u64) { + if let Err(e) = tdx::tdcall::accept_page(addr + (p * SIZE_4K) as u64) { if let tdx_tdcall::TdCallError::LeafSpecific(error_code) = e { if error_code == tdx_tdcall::TDCALL_STATUS_PAGE_ALREADY_ACCEPTED { continue; diff --git a/td-payload/src/bin/example/main.rs b/td-payload/src/bin/example/main.rs index 519574a0..2871ec8a 100644 --- a/td-payload/src/bin/example/main.rs +++ b/td-payload/src/bin/example/main.rs @@ -51,7 +51,7 @@ pub extern "C" fn main() -> ! { stack::bench_stack(); } - #[cfg(feature = "tdx")] + #[cfg(feature = "tdcall")] { use tdx_tdcall::tdreport::TD_REPORT_ADDITIONAL_DATA_SIZE; //Dump TD Report diff --git a/td-payload/src/mm/mod.rs b/td-payload/src/mm/mod.rs index 9cf66a1e..de4e298f 100644 --- a/td-payload/src/mm/mod.rs +++ b/td-payload/src/mm/mod.rs @@ -21,7 +21,6 @@ use crate::Error; #[cfg(any(target_os = "none", target_os = "uefi"))] pub(crate) mod heap; -#[cfg(feature = "tdx")] pub mod shared; #[cfg(not(any(target_os = "none", target_os = "uefi")))] pub(crate) mod heap { diff --git a/td-shim/src/bin/td-shim/td/tdx.rs b/td-shim/src/bin/td-shim/td/tdx.rs index fad23d6e..28b1ec5b 100644 --- a/td-shim/src/bin/td-shim/td/tdx.rs +++ b/td-shim/src/bin/td-shim/td/tdx.rs @@ -38,7 +38,7 @@ pub fn set_idt(idt_ptr: &DescriptorTablePointer) { } pub fn get_num_vcpus() -> u32 { - let td_info = tdx::tdcall_get_td_info().expect("Fail to get TDINFO"); + let td_info = tdx::tdcall::get_td_info().expect("Fail to get TDINFO"); log::info!("gpaw - {:?}\n", td_info.gpaw); log::info!("num_vcpus - {:?}\n", td_info.num_vcpus); @@ -54,5 +54,5 @@ pub fn extend_rtmr(data: &[u8; SHA384_DIGEST_SIZE], mr_index: u32) -> Result<(), e => return Err(CcEventLogError::InvalidMrIndex(e)), }; - tdx::tdcall_extend_rtmr(&digest, rtmr_index).map_err(|_| CcEventLogError::ExtendMr) + tdx::tdcall::extend_rtmr(&digest, rtmr_index).map_err(|_| CcEventLogError::ExtendMr) } diff --git a/tdx-tdcall/CHANGELOG.md b/tdx-tdcall/CHANGELOG.md index d3c925e6..26e1b6b2 100644 --- a/tdx-tdcall/CHANGELOG.md +++ b/tdx-tdcall/CHANGELOG.md @@ -8,11 +8,11 @@ All notable changes to this project will be documented in this file. ## [0.2.0] - 2024-06-21 ### Added -- Wrapper to tdcall_accept_page to accept a memory range (for both normal 4K as well as 2M large pages). -- Add tdcall_vm_read/write to access TD-scope meta field of a TD. -- Add tdcall_vp_read/write is to access vCPU-scope meta field of a TD. -- Add tdcall_vp_invept/invvpid to provide SEPT flushing support. -- Add tdcall_vp_enter support. +- Wrapper to tdcall::accept_page to accept a memory range (for both normal 4K as well as 2M large pages). +- Add tdcall::vm_read/write to access TD-scope meta field of a TD. +- Add tdcall::vp_read/write is to access vCPU-scope meta field of a TD. +- Add tdcall::vp_invept/invvpid to provide SEPT flushing support. +- Add tdcall::vp_enter support. - Add tdcall to support memory attribute write. ### Changed diff --git a/tdx-tdcall/src/asm/mod.rs b/tdx-tdcall/src/asm/mod.rs index fe3afe62..abe7de7e 100644 --- a/tdx-tdcall/src/asm/mod.rs +++ b/tdx-tdcall/src/asm/mod.rs @@ -5,7 +5,7 @@ use core::arch::global_asm; use core::ffi::c_void; #[cfg(feature = "use_tdx_emulation")] -global_asm!(include_str!("tdcall_emu.asm")); +global_asm!(include_str!("tdcall::emu.asm")); #[cfg(feature = "use_tdx_emulation")] global_asm!(include_str!("tdvmcall::emu.asm")); diff --git a/tdx-tdcall/src/asm/tdcall_emu.asm b/tdx-tdcall/src/asm/tdcall_emu.asm index 988c2c70..073878a5 100644 --- a/tdx-tdcall/src/asm/tdcall_emu.asm +++ b/tdx-tdcall/src/asm/tdcall_emu.asm @@ -19,7 +19,7 @@ .global td_call td_call: endbr64 - # tdcall_push_regs + # tdcall::push_regs push rbp mov rbp, rsp push r15 @@ -57,7 +57,7 @@ td_call: mov [r12+32], r10 mov [r12+40], r11 exit: - # tdcall_pop_regs + # tdcall::pop_regs pop rdi pop rsi pop rbx diff --git a/tdx-tdcall/src/asm/tdvmcall_emu.asm b/tdx-tdcall/src/asm/tdvmcall_emu.asm index 33cd99cb..19016e71 100644 --- a/tdx-tdcall/src/asm/tdvmcall_emu.asm +++ b/tdx-tdcall/src/asm/tdvmcall_emu.asm @@ -26,7 +26,7 @@ .global td_vm_call td_vm_call: endbr64 - # tdcall_push_regs + # tdcall::push_regs push rbp mov rbp, rsp push r15 @@ -43,7 +43,7 @@ td_vm_call: mov r14, r9 mov r15, [rsp+first_variable_on_stack_offset] - #tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK + #tdcall::regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK mov rax, TDVMCALL mov ecx, TDVMCALL_EXPOSE_REGS_MASK @@ -89,7 +89,7 @@ td_vm_call: mov [r9], r11 no_return_data: - #tdcall_regs_postamble + #tdcall::regs_postamble xor ebx, ebx xor esi, esi xor edi, edi @@ -101,7 +101,7 @@ no_return_data: xor r10d, r10d xor r11d, r11d - # tdcall_pop_regs + # tdcall::pop_regs pop rdi pop rsi pop rbx diff --git a/tests/test-td-payload/src/testtdinfo.rs b/tests/test-td-payload/src/testtdinfo.rs index 0d238e93..1191fca6 100644 --- a/tests/test-td-payload/src/testtdinfo.rs +++ b/tests/test-td-payload/src/testtdinfo.rs @@ -57,7 +57,7 @@ impl TestCase for Tdinfo { * run the test case */ fn run(&mut self) { - let mut td_info = tdx::tdcall_get_td_info().expect("Failt to get td info"); + let mut td_info = tdx::tdcall::get_td_info().expect("Failt to get td info"); // Only GPAW values 48 and 52 are possible. if (td_info.gpaw != 52) && (td_info.gpaw != 48) { log::info!( From 383f9fa5674a678575a9309db2f9d2dcaf820bc5 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 09:52:17 +0100 Subject: [PATCH 08/31] tdx-tdcall: Revert rename in CHANGELOG.md Signed-off-by: Stanislaw Grams --- tdx-tdcall/CHANGELOG.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tdx-tdcall/CHANGELOG.md b/tdx-tdcall/CHANGELOG.md index 26e1b6b2..1b06898f 100644 --- a/tdx-tdcall/CHANGELOG.md +++ b/tdx-tdcall/CHANGELOG.md @@ -8,16 +8,16 @@ All notable changes to this project will be documented in this file. ## [0.2.0] - 2024-06-21 ### Added -- Wrapper to tdcall::accept_page to accept a memory range (for both normal 4K as well as 2M large pages). -- Add tdcall::vm_read/write to access TD-scope meta field of a TD. -- Add tdcall::vp_read/write is to access vCPU-scope meta field of a TD. -- Add tdcall::vp_invept/invvpid to provide SEPT flushing support. -- Add tdcall::vp_enter support. +- Wrapper to tdcall_accept_page to accept a memory range (for both normal 4K as well as 2M large pages). +- Add tdcall_vm_read/write to access TD-scope meta field of a TD. +- Add tdcall_vp_read/write is to access vCPU-scope meta field of a TD. +- Add tdcall_vp_invept/invvpid to provide SEPT flushing support. +- Add tdcall_vp_enter support. - Add tdcall to support memory attribute write. ### Changed -- Change return type for tdvmcall::wrmsr, tdvmcall::rdmsr -- Replace the & operator with addr_of! macro for tdvmcall::mmio_write/tdvmcall::mmio_read +- Change return type for tdvmcall_wrmsr, tdvmcall_rdmsr +- Replace the & operator with addr_of! macro for tdvmcall_mmio_write/tdvmcall_mmio_read - Extend TdInfo struct to add vcpu_index field ## [0.1.0] - 2024-06-07 From 4afbf1fe8f13ddb8caa1ec0437cf52140e38198f Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:19:51 +0100 Subject: [PATCH 09/31] tdx-tdcall: add tdcall feature and add default features Signed-off-by: Stanislaw Grams --- tdx-tdcall/Cargo.toml | 3 ++- tdx-tdcall/src/tdcall.rs | 43 ++++++++++++++++---------------------- tdx-tdcall/src/tdreport.rs | 4 ++-- tdx-tdcall/src/tdvmcall.rs | 9 +++++++- tdx-tdcall/src/tdx.rs | 6 ------ 5 files changed, 30 insertions(+), 35 deletions(-) delete mode 100644 tdx-tdcall/src/tdx.rs diff --git a/tdx-tdcall/Cargo.toml b/tdx-tdcall/Cargo.toml index 27283d43..fc95ae54 100644 --- a/tdx-tdcall/Cargo.toml +++ b/tdx-tdcall/Cargo.toml @@ -18,6 +18,7 @@ spin = "0.9.2" x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] } [features] -default = [] +default = ["tdcall", "tdvmcall"] use_tdx_emulation = [] tdvmcall = [] +tdcall = [] diff --git a/tdx-tdcall/src/tdcall.rs b/tdx-tdcall/src/tdcall.rs index d7dd79d7..6c75f0e6 100644 --- a/tdx-tdcall/src/tdcall.rs +++ b/tdx-tdcall/src/tdcall.rs @@ -13,28 +13,28 @@ use crate::*; pub const PAGE_SIZE_4K: u64 = 0x1000; pub const PAGE_SIZE_2M: u64 = 0x200000; -const TARGET_TD_UUID_NUM: usize = 4; +pub const TARGET_TD_UUID_NUM: usize = 4; // Guest-Side (TDCALL) interface functions leaf numbers -const TDCALL_TDINFO: u64 = 1; -const TDCALL_TDEXTENDRTMR: u64 = 2; -const TDCALL_TDGETVEINFO: u64 = 3; -const TDCALL_TDREPORT: u64 = 4; -const TDCALL_TDACCEPTPAGE: u64 = 6; -const TDCALL_VM_RD: u64 = 7; -const TDCALL_VM_WR: u64 = 8; -const TDCALL_VP_RD: u64 = 9; -const TDCALL_VP_WR: u64 = 10; -const TDCALL_SYS_RD: u64 = 11; -const TDCALL_SERVTD_RD: u64 = 18; -const TDCALL_SERVTD_WR: u64 = 20; -const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24; -const TDCALL_VP_ENTER: u64 = 25; -const TDCALL_VP_INVEPT: u64 = 26; -const TDCALL_VP_INVVPID: u64 = 27; +pub const TDCALL_TDINFO: u64 = 1; +pub const TDCALL_TDEXTENDRTMR: u64 = 2; +pub const TDCALL_TDGETVEINFO: u64 = 3; +pub const TDCALL_TDREPORT: u64 = 4; +pub const TDCALL_TDACCEPTPAGE: u64 = 6; +pub const TDCALL_VM_RD: u64 = 7; +pub const TDCALL_VM_WR: u64 = 8; +pub const TDCALL_VP_RD: u64 = 9; +pub const TDCALL_VP_WR: u64 = 10; +pub const TDCALL_SYS_RD: u64 = 11; +pub const TDCALL_SERVTD_RD: u64 = 18; +pub const TDCALL_SERVTD_WR: u64 = 20; +pub const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24; +pub const TDCALL_VP_ENTER: u64 = 25; +pub const TDCALL_VP_INVEPT: u64 = 26; +pub const TDCALL_VP_INVVPID: u64 = 27; // TDCALL completion status code -const TDCALL_STATUS_SUCCESS: u64 = 0; +pub const TDCALL_STATUS_SUCCESS: u64 = 0; // leaf-specific completion status code pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000; @@ -80,13 +80,6 @@ pub struct ServtdRWResult { pub uuid: [u64; 4], } -// An extended public wrapper for use of asm_td_vmcall. -// -// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall` -pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 { - unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) } -} - // Wrapper for use of asm_td_call, this function takes a mutable reference of a // TdVmcallArgs structure to ensure the input is valid // diff --git a/tdx-tdcall/src/tdreport.rs b/tdx-tdcall/src/tdreport.rs index 87470eab..02895548 100644 --- a/tdx-tdcall/src/tdreport.rs +++ b/tdx-tdcall/src/tdreport.rs @@ -7,7 +7,7 @@ use core::mem::{size_of, zeroed}; use core::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; use scroll::{Pread, Pwrite}; -use crate::{td_call, TdCallError, TdcallArgs, TDCALL_TDREPORT, TDVMCALL_STATUS_SUCCESS}; +use crate::tdcall::{td_call, TdCallError, TdcallArgs, TDCALL_TDREPORT, TDCALL_STATUS_SUCCESS}; pub const TD_REPORT_SIZE: usize = 0x400; pub const TD_REPORT_ADDITIONAL_DATA_SIZE: usize = 64; @@ -208,7 +208,7 @@ pub fn tdcall_report( }; let ret = td_call(&mut args); - if ret != TDVMCALL_STATUS_SUCCESS { + if ret != TDCALL_STATUS_SUCCESS { return Err(args.r10.into()); } diff --git a/tdx-tdcall/src/tdvmcall.rs b/tdx-tdcall/src/tdvmcall.rs index c44ef9b9..282a9cc3 100644 --- a/tdx-tdcall/src/tdvmcall.rs +++ b/tdx-tdcall/src/tdvmcall.rs @@ -14,7 +14,7 @@ use lazy_static::lazy_static; use crate::*; lazy_static! { - static ref SHARED_MASK: u64 = td_shared_mask().expect("Fail to get the shared mask of TD"); + static ref SHARED_MASK: u64 = tdcall::td_shared_mask().expect("Fail to get the shared mask of TD"); } // GTDG.VP.VMCALL leaf sub-function numbers @@ -114,6 +114,13 @@ pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 { unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) } } +// An extended public wrapper for use of asm_td_vmcall. +// +// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall` +pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 { + unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) } +} + /// Used to help perform HLT operation. /// /// Details can be found in TDX GHCI spec section 'TDG.VP.VMCALL' diff --git a/tdx-tdcall/src/tdx.rs b/tdx-tdcall/src/tdx.rs deleted file mode 100644 index db8a6bf1..00000000 --- a/tdx-tdcall/src/tdx.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2020-2022 Intel Corporation -// -// SPDX-License-Identifier: BSD-2-Clause-Patent - - -use crate::*; From 1746f9b515c0b1f15f73f924abdbe7c086cb69b0 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:39:40 +0100 Subject: [PATCH 10/31] td-payload: adapt to new tdx-tdcall layout Signed-off-by: Stanislaw Grams --- td-payload/Cargo.toml | 5 +++-- td-payload/src/arch/x86_64/apic.rs | 13 +++++++------ td-payload/src/arch/x86_64/mod.rs | 1 - td-payload/src/arch/x86_64/paging.rs | 14 +++++++------- td-payload/src/arch/x86_64/serial.rs | 8 ++++---- td-payload/src/arch/x86_64/shared.rs | 24 +++++++++++++++++------- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/td-payload/Cargo.toml b/td-payload/Cargo.toml index 6f19bf4a..ce526e46 100644 --- a/td-payload/Cargo.toml +++ b/td-payload/Cargo.toml @@ -35,8 +35,9 @@ zerocopy = { version = "0.7.31", features = ["derive"] } minicov = { version = "0.2", default-features = false, optional = true } [features] -default = ["tdx"] -tdx = ["tdx-tdcall", "td-logger/tdx", "td-exception/tdx"] +default = ["tdcall"] +tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall"] +tdvmcall = ["tdx-tdcall/tdvmcall", "td-logger/tdvmcall"] stack-guard = [] cet-shstk = ["td-exception/cet-shstk"] cet-ibt = [] diff --git a/td-payload/src/arch/x86_64/apic.rs b/td-payload/src/arch/x86_64/apic.rs index da74d775..0389ae50 100644 --- a/td-payload/src/arch/x86_64/apic.rs +++ b/td-payload/src/arch/x86_64/apic.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Intel Corporation +// Copyright (c) 2022, 2025 Intel Corporation // // SPDX-License-Identifier: BSD-2-Clause-Patent @@ -13,21 +13,22 @@ pub const LOCAL_APIC_LVTT: u32 = 0xfee0_0320; pub const INITIAL_COUNT: u32 = 0xfee0_0380; pub const DIVIDE_CONFIGURATION_REGISTER: u32 = 0xfee0_03e0; +#[cfg(feature = "tdvmcall")] pub fn enable_apic_interrupt() { // Enable the local APIC by setting bit 8 of the APIC spurious vector region (SVR) // Ref: Intel SDM Vol3. 8.4.4.1 // In x2APIC mode, SVR is mapped to MSR address 0x80f. // Since SVR(SIVR) is not virtualized, before we implement the handling in #VE of MSRRD/WR, // use tdvmcall instead direct read/write operation. - let svr = tdx_tdcall::tdx::tdvmcall::rdmsr(0x80f).expect("fail to perform RDMSR operation\n"); - tdx_tdcall::tdx::tdvmcall::wrmsr(0x80f, svr | (0x1 << 8)) + let svr = tdx_tdcall::tdvmcall::rdmsr(0x80f).expect("fail to perform RDMSR operation\n"); + tdx_tdcall::tdvmcall::wrmsr(0x80f, svr | (0x1 << 8)) .expect("fail to perform WRMSR operation\n"); } pub fn enable_and_hlt() { - #[cfg(feature = "tdx")] - tdx_tdcall::tdx::tdvmcall::sti_halt(); - #[cfg(not(feature = "tdx"))] + #[cfg(feature = "tdvmcall")] + tdx_tdcall::tdvmcall::sti_halt(); + #[cfg(not(feature = "tdvmcall"))] x86_64::instructions::interrupts::enable_and_hlt() } diff --git a/td-payload/src/arch/x86_64/mod.rs b/td-payload/src/arch/x86_64/mod.rs index b2577c9e..44d2b92c 100644 --- a/td-payload/src/arch/x86_64/mod.rs +++ b/td-payload/src/arch/x86_64/mod.rs @@ -10,5 +10,4 @@ pub mod idt; pub mod init; pub mod paging; pub mod serial; -#[cfg(feature = "tdx")] pub mod shared; diff --git a/td-payload/src/arch/x86_64/paging.rs b/td-payload/src/arch/x86_64/paging.rs index d476c64d..dcc440b5 100644 --- a/td-payload/src/arch/x86_64/paging.rs +++ b/td-payload/src/arch/x86_64/paging.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Intel Corporation +// Copyright (c) 2022, 2025 Intel Corporation // // SPDX-License-Identifier: BSD-2-Clause-Patent @@ -129,13 +129,13 @@ pub fn set_not_present(address: u64, size: usize) { set_page_flags(&mut pt, address, size, flags); } -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] pub fn set_shared_bit(address: u64, size: usize) { let mut pt = offset_pt(); map_shared(&mut pt, address, size, true); } -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] pub fn clear_shared_bit(address: u64, size: usize) { let mut pt = offset_pt(); map_shared(&mut pt, address, size, false); @@ -202,7 +202,7 @@ pub(crate) fn set_page_flags(pt: &mut OffsetPageTable, va: u64, size: usize, fla } } -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] fn map_shared(pt: &mut OffsetPageTable, va: u64, size: usize, shared: bool) { let end = va + size as u64; let mut va = VirtAddr::new(va); @@ -217,7 +217,7 @@ fn map_shared(pt: &mut OffsetPageTable, va: u64, size: usize, shared: bool) { } } -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] fn pt_set_shared_bit(pt: &mut OffsetPageTable, page: &Page, shared: bool) { let p4 = pt.level_4_table(); let p3 = unsafe { &mut *(p4.index(page.p4_index()).addr().as_u64() as *mut PageTable) }; @@ -237,10 +237,10 @@ fn pt_set_shared_bit(pt: &mut OffsetPageTable, page: &Page, shared: bool) { } } -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] fn pt_entry_set_shared_bit(page_table: &mut PageTable, index: PageTableIndex, shared: bool) { let entry = page_table.index(index); - let shared_bit = tdx_tdcall::tdx::td_shared_mask().expect("Failed to get shared bit of GPA"); + let shared_bit = tdx_tdcall::tdcall::td_shared_mask().expect("Failed to get shared bit of GPA"); let addr = if shared { entry.addr().as_u64() | shared_bit diff --git a/td-payload/src/arch/x86_64/serial.rs b/td-payload/src/arch/x86_64/serial.rs index dc7988fd..f4b624eb 100644 --- a/td-payload/src/arch/x86_64/serial.rs +++ b/td-payload/src/arch/x86_64/serial.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Intel Corporation +// Copyright (c) 2022, 2025 Intel Corporation // // SPDX-License-Identifier: BSD-2-Clause-Patent @@ -19,12 +19,12 @@ pub fn serial_write_string(s: &str) { const SERIAL_IO_PORT: u16 = 0x3F8; -#[cfg(feature = "tdx")] +#[cfg(feature = "tdvmcall")] fn io_write(byte: u8) { - tdx_tdcall::tdx::tdvmcall::io_write_8(SERIAL_IO_PORT, byte); + tdx_tdcall::tdvmcall::io_write_8(SERIAL_IO_PORT, byte); } -#[cfg(not(feature = "tdx"))] +#[cfg(not(feature = "tdvmcall"))] fn io_write(byte: u8) { unsafe { x86::io::outb(SERIAL_IO_PORT, byte) }; } diff --git a/td-payload/src/arch/x86_64/shared.rs b/td-payload/src/arch/x86_64/shared.rs index fa37a6f8..cef46426 100644 --- a/td-payload/src/arch/x86_64/shared.rs +++ b/td-payload/src/arch/x86_64/shared.rs @@ -1,38 +1,48 @@ -// Copyright (c) 2022 Intel Corporation +// Copyright (c) 2022, 2025 Intel Corporation // // SPDX-License-Identifier: BSD-2-Clause-Patent + +#[cfg(feature = "tdcall")] use crate::mm::SIZE_4K; -use tdx_tdcall::tdx; +#[cfg(feature = "tdcall")] +use tdx_tdcall::tdcall; + +#[cfg(feature = "tdvmcall")] +use tdx_tdcall::tdvmcall; +#[cfg(feature = "tdvmcall")] use super::paging::{clear_shared_bit, set_shared_bit}; +#[cfg(feature = "tdvmcall")] pub fn decrypt(addr: u64, length: usize) { set_shared_bit(addr, length); // Safety: Fail to map GPA is a fatal error that we cannot handle - if tdx::tdvmcall::mapgpa(true, addr, length).is_err() { + if tdvmcall::mapgpa(true, addr, length).is_err() { panic!("Fail to map GPA to shared memory with TDVMCALL"); } } +#[cfg(feature = "tdvmcall")] pub fn encrypt(addr: u64, length: usize) { clear_shared_bit(addr, length); // Safety: Fail to map GPA is a fatal error that we cannot handle - if tdx_tdcall::tdx::tdvmcall::mapgpa(false, addr, length).is_err() { + if tdvmcall::mapgpa(false, addr, length).is_err() { panic!("Fail to map GPA to private memory with TDVMCALL"); } accept_memory(addr, length); } +#[cfg(feature = "tdcall")] fn accept_memory(addr: u64, length: usize) { let page_num = length / SIZE_4K; for p in 0..page_num { - if let Err(e) = tdx::tdcall::accept_page(addr + (p * SIZE_4K) as u64) { - if let tdx_tdcall::TdCallError::LeafSpecific(error_code) = e { - if error_code == tdx_tdcall::TDCALL_STATUS_PAGE_ALREADY_ACCEPTED { + if let Err(e) = tdcall::accept_page(addr + (p * SIZE_4K) as u64) { + if let tdcall::TdCallError::LeafSpecific(error_code) = e { + if error_code == tdcall::TDCALL_STATUS_PAGE_ALREADY_ACCEPTED { continue; } } From bc5bf165933e17a12785ae0ef8ab6ef1a6fd721c Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 17:13:22 +0100 Subject: [PATCH 11/31] td-logger: adapt to new tdx-tdcall layout Signed-off-by: Stanislaw Grams --- td-logger/Cargo.toml | 2 +- td-logger/src/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/td-logger/Cargo.toml b/td-logger/Cargo.toml index d16aa217..a7245891 100644 --- a/td-logger/Cargo.toml +++ b/td-logger/Cargo.toml @@ -16,5 +16,5 @@ tdx-tdcall = { path = "../tdx-tdcall", optional = true } x86 = { version = "0.47.0", optional = true } [features] -tdx = ["tdx-tdcall"] +tdvmcall = ["tdx-tdcall/tdvmcall"] serial-port = ["x86"] diff --git a/td-logger/src/lib.rs b/td-logger/src/lib.rs index 6a753695..b065fd97 100644 --- a/td-logger/src/lib.rs +++ b/td-logger/src/lib.rs @@ -53,20 +53,20 @@ pub fn dbg_write_string(s: &str) { } } -#[cfg(any(feature = "tdx", feature = "serial-port"))] +#[cfg(any(feature = "tdvmcall", feature = "serial-port"))] const SERIAL_IO_PORT: u16 = 0x3F8; -#[cfg(feature = "tdx")] +#[cfg(feature = "tdvmcall")] fn dbg_port_write(byte: u8) { - tdx_tdcall::tdx::tdvmcall::io_write_8(SERIAL_IO_PORT, byte); + tdx_tdcall::tdvmcall::io_write_8(SERIAL_IO_PORT, byte); } -#[cfg(all(not(feature = "tdx"), feature = "serial-port"))] +#[cfg(all(not(feature = "tdvmcall"), feature = "serial-port"))] fn dbg_port_write(byte: u8) { unsafe { x86::io::outb(SERIAL_IO_PORT, byte) }; } -#[cfg(all(not(feature = "tdx"), not(feature = "serial-port")))] +#[cfg(all(not(feature = "tdvmcall"), not(feature = "serial-port")))] fn dbg_port_write(_byte: u8) {} #[cfg(test)] From 84854076120695ca146493cae6c4a2c2af745285 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:34:13 +0100 Subject: [PATCH 12/31] td-exception: adapt to new tdx-tdcall layout Signed-off-by: Stanislaw Grams --- td-exception/Cargo.toml | 3 +- td-exception/src/interrupt.rs | 60 +++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/td-exception/Cargo.toml b/td-exception/Cargo.toml index 5025cc10..891f644c 100644 --- a/td-exception/Cargo.toml +++ b/td-exception/Cargo.toml @@ -17,5 +17,6 @@ spin = "0.9.2" [features] cet-shstk = [] -tdx = ["tdx-tdcall"] +tdcall = ["tdx-tdcall/tdcall"] +tdvmcall = ["tdx-tdcall/tdvmcall"] integration-test = [] diff --git a/td-exception/src/interrupt.rs b/td-exception/src/interrupt.rs index f636e04a..ce881b63 100644 --- a/td-exception/src/interrupt.rs +++ b/td-exception/src/interrupt.rs @@ -4,8 +4,12 @@ use core::arch::asm; use spin::Mutex; -#[cfg(feature = "tdx")] -use tdx_tdcall::tdx; + +#[cfg(feature = "tdvmcall")] +use tdx_tdcall::tdcall; + +#[cfg(feature = "tdvmcall")] +use tdx_tdcall::tdvmcall; use crate::{idt::IDT_ENTRY_COUNT, ExceptionError}; @@ -141,7 +145,7 @@ pub(crate) fn init_interrupt_callbacks() { callbacks.table[17].func = alignment_check; callbacks.table[18].func = machine_check; callbacks.table[19].func = simd; - #[cfg(feature = "tdx")] + #[cfg(all(feature = "tdcall", feature = "tdvmcall"))] { callbacks.table[20].func = virtualization; } @@ -323,54 +327,54 @@ fn control_flow(stack: &mut InterruptStack) { deadloop(); } -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_CPUID: u32 = 10; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_HLT: u32 = 12; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_RDPMC: u32 = 15; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_VMCALL: u32 = 18; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_IO_INSTRUCTION: u32 = 30; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_MSR_READ: u32 = 31; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_MSR_WRITE: u32 = 32; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_MWAIT_INSTRUCTION: u32 = 36; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_MONITOR_INSTRUCTION: u32 = 39; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] const EXIT_REASON_WBINVD: u32 = 54; -#[cfg(feature = "tdx")] +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] fn virtualization(stack: &mut InterruptStack) { // Firstly get VE information from TDX module, halt it error occurs - let ve_info = tdx::tdcall::get_ve_info().expect("#VE handler: fail to get VE info\n"); + let ve_info = tdcall::get_ve_info().expect("#VE handler: fail to get VE info\n"); match ve_info.exit_reason { EXIT_REASON_HLT => { - tdx::tdvmcall::halt(); + tdvmcall::halt(); } EXIT_REASON_IO_INSTRUCTION => { if !handle_tdx_ioexit(&ve_info, stack) { - tdx::tdvmcall::halt(); + tdvmcall::halt(); } } EXIT_REASON_MSR_READ => { - let msr = tdx::tdvmcall::rdmsr(stack.scratch.rcx as u32) + let msr = tdvmcall::rdmsr(stack.scratch.rcx as u32) .expect("fail to perform RDMSR operation\n"); stack.scratch.rax = (msr as u32 & u32::MAX) as usize; // EAX stack.scratch.rdx = ((msr >> 32) as u32 & u32::MAX) as usize; // EDX } EXIT_REASON_MSR_WRITE => { let data = stack.scratch.rax as u64 | ((stack.scratch.rdx as u64) << 32); // EDX:EAX - tdx::tdvmcall::wrmsr(stack.scratch.rcx as u32, data) + tdvmcall::wrmsr(stack.scratch.rcx as u32, data) .expect("fail to perform WRMSR operation\n"); } EXIT_REASON_CPUID => { - let cpuid = tdx::tdvmcall::cpuid(stack.scratch.rax as u32, stack.scratch.rcx as u32); + let cpuid = tdvmcall::cpuid(stack.scratch.rax as u32, stack.scratch.rcx as u32); let mask = 0xFFFF_FFFF_0000_0000_usize; stack.scratch.rax = (stack.scratch.rax & mask) | cpuid.eax as usize; stack.preserved.rbx = (stack.preserved.rbx & mask) | cpuid.ebx as usize; @@ -451,8 +455,8 @@ fn virtualization(stack: &mut InterruptStack) { // // Use TDVMCALL to realize IO read/write operation // Return false if VE info is invalid -#[cfg(feature = "tdx")] -fn handle_tdx_ioexit(ve_info: &tdx::TdVeInfo, stack: &mut InterruptStack) -> bool { +#[cfg(all(feature = "tdcall", feature = "tdvmcall"))] +fn handle_tdx_ioexit(ve_info: &tdcall::TdVeInfo, stack: &mut InterruptStack) -> bool { let size = ((ve_info.exit_qualification & 0x7) + 1) as usize; // 0 - 1bytes, 1 - 2bytes, 3 - 4bytes let read = (ve_info.exit_qualification >> 3) & 0x1 == 1; let string = (ve_info.exit_qualification >> 4) & 0x1 == 1; @@ -471,17 +475,17 @@ fn handle_tdx_ioexit(ve_info: &tdx::TdVeInfo, stack: &mut InterruptStack) -> boo // Define closure to perform IO port read with different size operands let io_read = |size, port| match size { - 1 => tdx::tdvmcall::io_read_8(port) as u32, - 2 => tdx::tdvmcall::io_read_16(port) as u32, - 4 => tdx::tdvmcall::io_read_32(port), + 1 => tdvmcall::io_read_8(port) as u32, + 2 => tdvmcall::io_read_16(port) as u32, + 4 => tdvmcall::io_read_32(port), _ => 0, }; // Define closure to perform IO port write with different size operands let io_write = |size, port, data| match size { - 1 => tdx::tdvmcall::io_write_8(port, data as u8), - 2 => tdx::tdvmcall::io_write_16(port, data as u16), - 4 => tdx::tdvmcall::io_write_32(port, data), + 1 => tdvmcall::io_write_8(port, data as u8), + 2 => tdvmcall::io_write_16(port, data as u16), + 4 => tdvmcall::io_write_32(port, data), _ => {} }; From 93e3ca4f2ed9645734e358b78f6c0d1cd0119a98 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 17:28:59 +0100 Subject: [PATCH 13/31] td-shim: adapt to new tdx-tdcall layout Signed-off-by: Stanislaw Grams --- td-shim/Cargo.toml | 7 +- .../bin/td-shim/asm/ap_loop_notdvmcall.asm | 70 +++++++++++++++++++ .../bin/td-shim/asm/exception_notdvmcall.asm | 20 ++++++ td-shim/src/bin/td-shim/asm/mod.rs | 10 ++- td-shim/src/bin/td-shim/linux/boot.rs | 4 +- td-shim/src/bin/td-shim/main.rs | 2 +- td-shim/src/bin/td-shim/memory.rs | 6 +- td-shim/src/bin/td-shim/td/mod.rs | 10 +-- td-shim/src/bin/td-shim/td/tdx.rs | 10 +-- td-shim/src/bin/td-shim/td/tdx_mailbox.rs | 2 +- 10 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 td-shim/src/bin/td-shim/asm/ap_loop_notdvmcall.asm create mode 100644 td-shim/src/bin/td-shim/asm/exception_notdvmcall.asm diff --git a/td-shim/Cargo.toml b/td-shim/Cargo.toml index f876b241..01c5ff3b 100644 --- a/td-shim/Cargo.toml +++ b/td-shim/Cargo.toml @@ -32,7 +32,7 @@ linked_list_allocator = { version = "0.10", optional = true } log = { version = "0.4.13", features = ["release_max_level_off"], optional = true } ring = { version = "0.17.6", default-features = false, features = ["alloc"], optional = true } spin = { version = "0.9.2", optional = true } -td-exception = { path = "../td-exception", features = ["tdx"], optional = true } +td-exception = { path = "../td-exception", optional = true } td-logger = { path = "../td-logger", optional = true } td-paging = { path = "../td-paging", optional = true } x86 = { version ="0.47.0", optional = true } @@ -47,8 +47,9 @@ tdx-tdcall = { path = "../tdx-tdcall", optional = true } [features] default = ["secure-boot"] secure-boot = ["der", "ring"] -tdx = ["tdx-tdcall", "td-exception/tdx", "td-logger/tdx", "x86"] -lazy-accept = ["tdx"] +tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall", "x86"] +tdvmcall = ["tdx-tdcall/tdvmcall", "td-exception/tdvmcall", "td-logger/tdvmcall", "x86"] +lazy-accept = ["tdcall"] ring-hash = ["cc-measurement/ring"] sha2-hash = ["cc-measurement/sha2"] main = [ diff --git a/td-shim/src/bin/td-shim/asm/ap_loop_notdvmcall.asm b/td-shim/src/bin/td-shim/asm/ap_loop_notdvmcall.asm new file mode 100644 index 00000000..94ca59c0 --- /dev/null +++ b/td-shim/src/bin/td-shim/asm/ap_loop_notdvmcall.asm @@ -0,0 +1,70 @@ +# Copyright (c) 2022, 2025 Intel Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent + +.set CommandOffset, 0 +.set ApicIdOffset, 0x4 +.set WakeupVectorOffset, 0x8 + +.set MpProtectedModeWakeupCommandNoop, 0 +.set MpProtectedModeWakeupCommandWakeup, 1 +.set MpProtectedModeWakeupCommandSleep, 2 + +.set MailboxApicIdInvalid, 0xffffffff +.set MailboxApicIdBroadcast, 0xfffffffe + +.section .text + +#-------------------------------------------------------------------- +# ap_relocated_vector +# +# rbx: Relocated mailbox address +# rbp: vCpuId +#-------------------------------------------------------------------- +.global ap_relocated_func +ap_relocated_func: + mov r8, rbx + # + # Get the APIC ID via CPUID + mov rax, 1 + cpuid + shr ebx, 24 + # + # r8 will hold the APIC ID of current AP + xchg r8, rbx + +.check_apicid: + # + # Determine if this is a broadcast or directly for my apic-id, if not, ignore + cmp dword ptr[rbx + ApicIdOffset], MailboxApicIdBroadcast + je .check_command + cmp dword ptr[rbx + ApicIdOffset], r8d + jne .check_apicid + +.check_command: + mov eax, dword ptr[rbx + CommandOffset] + cmp eax, MpProtectedModeWakeupCommandNoop + je .check_apicid + + cmp eax, MpProtectedModeWakeupCommandWakeup + je .wakeup + + jmp .check_apicid + +.wakeup: + # + # BSP sets these variables before unblocking APs + mov rax, 0 + mov eax, dword ptr[rbx + WakeupVectorOffset] + + # + # Clear the command as the acknowledgement that the wake up command is received + mov qword ptr[rbx + CommandOffset], MpProtectedModeWakeupCommandNoop + nop + jmp rax + +.panic: + ud2 + +.global ap_relocated_func_end +ap_relocated_func_end: + jmp .panic diff --git a/td-shim/src/bin/td-shim/asm/exception_notdvmcall.asm b/td-shim/src/bin/td-shim/asm/exception_notdvmcall.asm new file mode 100644 index 00000000..3cbb95ac --- /dev/null +++ b/td-shim/src/bin/td-shim/asm/exception_notdvmcall.asm @@ -0,0 +1,20 @@ +# Copyright (c) 2022, 2025 Intel Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent + +.section .text + +#-------------------------------------------------------------------- +# empty_exception_handler +# +# We do not need to save the context here because this function will +# never return. +#-------------------------------------------------------------------- +.global empty_exception_handler +empty_exception_handler: + hlt +.exception_loop: + jmp .exception_loop + +.global empty_exception_handler_end +empty_exception_handler_end: + jmp .exception_loop diff --git a/td-shim/src/bin/td-shim/asm/mod.rs b/td-shim/src/bin/td-shim/asm/mod.rs index b1e7ae2d..41b2a21e 100644 --- a/td-shim/src/bin/td-shim/asm/mod.rs +++ b/td-shim/src/bin/td-shim/asm/mod.rs @@ -4,8 +4,16 @@ use core::arch::global_asm; global_asm!(include_str!("msr64.asm")); -global_asm!(include_str!("ap_loop.asm")); + +#[cfg(not(feature = "tdvmcall"))] global_asm!(include_str!("exception.asm")); +#[cfg(not(feature = "tdvmcall"))] +global_asm!(include_str!("ap_loop_notdvmcall.asm")); + +#[cfg(feature = "tdvmcall")] +global_asm!(include_str!("exception_notdvmcall.asm")); +#[cfg(feature = "tdvmcall")] +global_asm!(include_str!("ap_loop.asm")); extern "C" { fn ap_relocated_func(); diff --git a/td-shim/src/bin/td-shim/linux/boot.rs b/td-shim/src/bin/td-shim/linux/boot.rs index b0c53da5..6087002c 100644 --- a/td-shim/src/bin/td-shim/linux/boot.rs +++ b/td-shim/src/bin/td-shim/linux/boot.rs @@ -62,13 +62,13 @@ pub fn boot_kernel( e820: &[E820Entry], mailbox: &mut [u8], info: &PayloadInfo, - #[cfg(feature = "tdx")] unaccepted_bitmap: u64, + #[cfg(feature = "tdcall")] unaccepted_bitmap: u64, ) -> Result<(), Error> { let mut params: BootParams = BootParams::default(); params.acpi_rsdp_addr = rsdp_addr; params.e820_entries = e820.len() as u8; params.e820_table[..e820.len()].copy_from_slice(e820); - #[cfg(feature = "tdx")] + #[cfg(feature = "tdcall")] { params.unaccepted_memory = unaccepted_bitmap; } diff --git a/td-shim/src/bin/td-shim/main.rs b/td-shim/src/bin/td-shim/main.rs index 4d9af7e2..19e8f515 100644 --- a/td-shim/src/bin/td-shim/main.rs +++ b/td-shim/src/bin/td-shim/main.rs @@ -196,7 +196,7 @@ fn boot_linux_kernel( e820_table.as_slice(), mailbox, kernel_info, - #[cfg(feature = "tdx")] + #[cfg(feature = "tdcall")] mem.build_unaccepted_memory_bitmap(), ); panic!("Linux kernel should not return here!!!"); diff --git a/td-shim/src/bin/td-shim/memory.rs b/td-shim/src/bin/td-shim/memory.rs index d90cb8da..351aa326 100644 --- a/td-shim/src/bin/td-shim/memory.rs +++ b/td-shim/src/bin/td-shim/memory.rs @@ -224,7 +224,7 @@ impl<'a> Memory<'a> { regions.push(new); } - #[cfg(feature = "tdx")] + #[cfg(feature = "tdcall")] Self::accept_memory_resources(&mut regions); regions @@ -245,7 +245,7 @@ impl<'a> Memory<'a> { false } - #[cfg(feature = "tdx")] + #[cfg(feature = "tdcall")] /// Build a 2M granularity bitmap for kernel to track the unaccepted memory pub fn build_unaccepted_memory_bitmap(&self) -> u64 { #[cfg(not(feature = "lazy-accept"))] @@ -287,7 +287,7 @@ impl<'a> Memory<'a> { .base_address as u64 } - #[cfg(feature = "tdx")] + #[cfg(feature = "tdcall")] fn accept_memory_resources(resources: &mut Vec) { use td_layout::TD_PAYLOAD_PARTIAL_ACCEPT_MEMORY_SIZE; use td_shim_interface::td_uefi_pi::pi; diff --git a/td-shim/src/bin/td-shim/td/mod.rs b/td-shim/src/bin/td-shim/td/mod.rs index c20a1473..2587da94 100644 --- a/td-shim/src/bin/td-shim/td/mod.rs +++ b/td-shim/src/bin/td-shim/td/mod.rs @@ -2,14 +2,14 @@ // // SPDX-License-Identifier: BSD-2-Clause-Patent -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] mod tdx; -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] mod tdx_mailbox; -#[cfg(feature = "tdx")] +#[cfg(feature = "tdcall")] pub use tdx::*; -#[cfg(not(feature = "tdx"))] +#[cfg(not(feature = "tdcall"))] mod dummy; -#[cfg(not(feature = "tdx"))] +#[cfg(not(feature = "tdcall"))] pub use dummy::*; diff --git a/td-shim/src/bin/td-shim/td/tdx.rs b/td-shim/src/bin/td-shim/td/tdx.rs index 28b1ec5b..ac508ed0 100644 --- a/td-shim/src/bin/td-shim/td/tdx.rs +++ b/td-shim/src/bin/td-shim/td/tdx.rs @@ -4,7 +4,7 @@ use cc_measurement::log::CcEventLogError; use td_exception::idt::DescriptorTablePointer; -use tdx_tdcall::tdx; +use tdx_tdcall::tdcall; extern "win64" { fn asm_read_msr64(index: u32) -> u64; @@ -17,7 +17,7 @@ const EXTENDED_PROCESSOR_INFO: u32 = 0x80000001; const SHA384_DIGEST_SIZE: usize = 48; pub fn get_shared_page_mask() -> u64 { - tdx::td_shared_mask().expect("Unable to get GPAW") + tdcall::td_shared_mask().expect("Unable to get GPAW") } pub fn accept_memory_resource_range(address: u64, size: u64) { @@ -38,7 +38,7 @@ pub fn set_idt(idt_ptr: &DescriptorTablePointer) { } pub fn get_num_vcpus() -> u32 { - let td_info = tdx::tdcall::get_td_info().expect("Fail to get TDINFO"); + let td_info = tdcall::get_td_info().expect("Fail to get TDINFO"); log::info!("gpaw - {:?}\n", td_info.gpaw); log::info!("num_vcpus - {:?}\n", td_info.num_vcpus); @@ -47,12 +47,12 @@ pub fn get_num_vcpus() -> u32 { } pub fn extend_rtmr(data: &[u8; SHA384_DIGEST_SIZE], mr_index: u32) -> Result<(), CcEventLogError> { - let digest = tdx::TdxDigest { data: *data }; + let digest = tdcall::TdxDigest { data: *data }; let rtmr_index = match mr_index { 1 | 2 | 3 | 4 => mr_index - 1, e => return Err(CcEventLogError::InvalidMrIndex(e)), }; - tdx::tdcall::extend_rtmr(&digest, rtmr_index).map_err(|_| CcEventLogError::ExtendMr) + tdcall::extend_rtmr(&digest, rtmr_index).map_err(|_| CcEventLogError::ExtendMr) } diff --git a/td-shim/src/bin/td-shim/td/tdx_mailbox.rs b/td-shim/src/bin/td-shim/td/tdx_mailbox.rs index a3039677..810b3e87 100644 --- a/td-shim/src/bin/td-shim/td/tdx_mailbox.rs +++ b/td-shim/src/bin/td-shim/td/tdx_mailbox.rs @@ -10,7 +10,7 @@ use core::cmp::min; use core::ops::RangeInclusive; use td_exception::idt::DescriptorTablePointer; use td_layout::memslice::{get_mem_slice_mut, SliceType}; -use tdx_tdcall::{self, tdx::*}; +use tdx_tdcall::{self, tdcall::*}; use crate::asm::{ap_relocated_func_addr, ap_relocated_func_size}; From fe3605647f75500f82a5990050815fc4a131673e Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 17:42:27 +0100 Subject: [PATCH 14/31] tests: adapt to new tdx-tdcall layout Signed-off-by: Stanislaw Grams --- tests/test-td-payload/Cargo.toml | 5 +++-- tests/test-td-payload/src/testiorw32.rs | 10 +++++----- tests/test-td-payload/src/testiorw8.rs | 10 +++++----- tests/test-td-payload/src/testmemmap.rs | 2 +- tests/test-td-payload/src/testmsrrw.rs | 8 ++++---- tests/test-td-payload/src/testtdinfo.rs | 4 ++-- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tests/test-td-payload/Cargo.toml b/tests/test-td-payload/Cargo.toml index 1fa6cda8..a047ee29 100644 --- a/tests/test-td-payload/Cargo.toml +++ b/tests/test-td-payload/Cargo.toml @@ -24,7 +24,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] } x86 = { version = "0.47.0" } ring = { version = "0.17.6", default-features = false, features = ["alloc"] } td-shim = { path = "../../td-shim" } -td-payload = { path = "../../td-payload", features = ["tdx","cet-shstk","stack-guard"] } +td-payload = { path = "../../td-payload", features = ["tdcall","tdvmcall","cet-shstk","stack-guard"] } zerocopy = { version = "0.7.31", features = ["derive"] } minicov = { version = "0.2", default-features = false, optional = true } @@ -37,6 +37,7 @@ features = ["spin_no_std"] map-physical-memory = true [features] -tdx = ["tdx-tdcall", "td-logger/tdx"] +tdvmcall = ["tdx-tdcall/tdvmcall", "td-logger/tdvmcall"] +tdcall = ["tdx-tdcall/tdcall"] main = [] coverage = ["minicov"] diff --git a/tests/test-td-payload/src/testiorw32.rs b/tests/test-td-payload/src/testiorw32.rs index 5485a98c..f6303922 100644 --- a/tests/test-td-payload/src/testiorw32.rs +++ b/tests/test-td-payload/src/testiorw32.rs @@ -8,7 +8,7 @@ extern crate alloc; use crate::lib::{TestCase, TestResult}; use alloc::string::String; use core::ffi::c_void; -use tdx_tdcall::tdx; +use tdx_tdcall::tdvmcall; use serde::{Deserialize, Serialize}; @@ -38,14 +38,14 @@ impl TestCase for Tdiorw32 { * io read Century of RTC */ fn run(&mut self) { - tdx::tdvmcall::io_write_8(0x70, 0x32); + tdvmcall::io_write_8(0x70, 0x32); - let read1 = tdx::tdvmcall::io_read_32(0x71); + let read1 = tdvmcall::io_read_32(0x71); log::info!("First time read {}\n", read1); - tdx::tdvmcall::io_write_32(0x71, read1 + 1); + tdvmcall::io_write_32(0x71, read1 + 1); - let read2 = tdx::tdvmcall::io_read_32(0x71); + let read2 = tdvmcall::io_read_32(0x71); log::info!("Second time read {}\n", read2); if (read1 + 1 != read2) { diff --git a/tests/test-td-payload/src/testiorw8.rs b/tests/test-td-payload/src/testiorw8.rs index 3c3cf95e..8df1368b 100644 --- a/tests/test-td-payload/src/testiorw8.rs +++ b/tests/test-td-payload/src/testiorw8.rs @@ -8,7 +8,7 @@ extern crate alloc; use crate::lib::{TestCase, TestResult}; use alloc::string::String; use core::ffi::c_void; -use tdx_tdcall::tdx; +use tdx_tdcall::tdvmcall; use serde::{Deserialize, Serialize}; @@ -38,14 +38,14 @@ impl TestCase for Tdiorw8 { * io read Century of RTC */ fn run(&mut self) { - tdx::tdvmcall::io_write_8(0x70, 0x32); + tdvmcall::io_write_8(0x70, 0x32); - let read1 = tdx::tdvmcall::io_read_8(0x71); + let read1 = tdvmcall::io_read_8(0x71); log::info!("First time read {}\n", read1); - tdx::tdvmcall::io_write_8(0x71, read1 + 1); + tdvmcall::io_write_8(0x71, read1 + 1); - let read2 = tdx::tdvmcall::io_read_8(0x71); + let read2 = tdvmcall::io_read_8(0x71); log::info!("Second time read {}\n", read2); if (read1 + 1 != read2) { diff --git a/tests/test-td-payload/src/testmemmap.rs b/tests/test-td-payload/src/testmemmap.rs index f7b10a51..e141a325 100644 --- a/tests/test-td-payload/src/testmemmap.rs +++ b/tests/test-td-payload/src/testmemmap.rs @@ -88,7 +88,7 @@ impl TestMemoryMap { fn verify_memory_map(&self, e820: Vec) -> TestResult { let mut top = 0; let mut total = 0; - let max_gpa = 1 << 51; //tdx::td_shared_page_mask(); + let max_gpa = 1 << 51; // tdcall::td_shared_page_mask(); for entry in e820 { let entry_end = entry.addr + entry.size; if entry.r#type < E820Type::Memory as u32 diff --git a/tests/test-td-payload/src/testmsrrw.rs b/tests/test-td-payload/src/testmsrrw.rs index c85066cf..ee43896f 100644 --- a/tests/test-td-payload/src/testmsrrw.rs +++ b/tests/test-td-payload/src/testmsrrw.rs @@ -8,7 +8,7 @@ extern crate alloc; use crate::lib::{TestCase, TestResult}; use alloc::string::String; use core::ffi::c_void; -use tdx_tdcall::tdx; +use tdx_tdcall::tdvmcall; use serde::{Deserialize, Serialize}; @@ -27,16 +27,16 @@ impl Tdmsrrw { const APIC_SVR_MSR: u32 = 0x80f; // APIC Spurious Vector Register MSR address // Read the current value of the APIC SVR MSR - match tdx::tdvmcall::rdmsr(APIC_SVR_MSR) { + match tdvmcall::rdmsr(APIC_SVR_MSR) { Ok(read1) => { // Attempt to write the incremented value back to the APIC SVR MSR - if tdx::tdvmcall::wrmsr(APIC_SVR_MSR, read1 + 1).is_err() { + if tdvmcall::wrmsr(APIC_SVR_MSR, read1 + 1).is_err() { log::info!("Failed to write MSR 0x{:x}", APIC_SVR_MSR); return TestResult::Fail; } // Read the value again to verify the write operation - match tdx::tdvmcall::rdmsr(APIC_SVR_MSR) { + match tdvmcall::rdmsr(APIC_SVR_MSR) { Ok(read2) if read1 + 1 == read2 => TestResult::Pass, Ok(read2) => { log::info!( diff --git a/tests/test-td-payload/src/testtdinfo.rs b/tests/test-td-payload/src/testtdinfo.rs index 1191fca6..01c0b134 100644 --- a/tests/test-td-payload/src/testtdinfo.rs +++ b/tests/test-td-payload/src/testtdinfo.rs @@ -8,7 +8,7 @@ extern crate alloc; use crate::lib::{TestCase, TestResult}; use alloc::string::String; use core::ffi::c_void; -use tdx_tdcall::tdx; +use tdx_tdcall::tdcall; use serde::{Deserialize, Serialize}; @@ -57,7 +57,7 @@ impl TestCase for Tdinfo { * run the test case */ fn run(&mut self) { - let mut td_info = tdx::tdcall::get_td_info().expect("Failt to get td info"); + let mut td_info = tdcall::get_td_info().expect("Failt to get td info"); // Only GPAW values 48 and 52 are possible. if (td_info.gpaw != 52) && (td_info.gpaw != 48) { log::info!( From 6961b90d2e1a8c8d3fea9e24a1c23203d7f0df35 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 4 Mar 2025 12:03:37 +0100 Subject: [PATCH 15/31] xtask: adapt to new tdx-tdcall layout Now tdx feature is removed and replaced by two separate features: tdcall and tdvmcall. Only tdcall is enabled by default. Signed-off-by: Stanislaw Grams --- xtask/src/build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xtask/src/build.rs b/xtask/src/build.rs index ff5abae9..0c5d0f98 100644 --- a/xtask/src/build.rs +++ b/xtask/src/build.rs @@ -11,7 +11,7 @@ use std::{ }; use xshell::{cmd, Shell}; -const TD_SHIM_DEFAULT_FEATURES: &str = "main,tdx"; +const TD_SHIM_DEFAULT_FEATURES: &str = "main,tdcall"; lazy_static! { static ref PROJECT_ROOT: &'static Path = @@ -41,8 +41,8 @@ pub(crate) struct BuildArgs { /// Path of the output td-shim image file #[arg(short, long)] output: Option, - /// List of features of `td-shim` crate to activate in addition to the `main` and `tdx`, - /// separated by comma. By default, only the `main` and `tdx` features of `td-shim` are enabled + /// List of features of `td-shim` crate to activate in addition to the `main` and `tdcall`, + /// separated by comma. By default, only the `main` and `tdcall` features of `td-shim` are enabled #[arg(long)] features: Option, /// Path of customized metadata configuration file @@ -140,7 +140,7 @@ impl BuildArgs { sh, "cargo build -p td-payload --bin example --target x86_64-unknown-none" ) - .args(["--features", "tdx,start,cet-shstk,stack-guard"]) + .args(["--features", "tdcall,start,cet-shstk,stack-guard"]) .args(["--profile", self.profile()]) .run()?; From 013c6c00f6a59e69f7854c02d7df9bd13fafd6cf Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 4 Mar 2025 12:09:06 +0100 Subject: [PATCH 16/31] tdx-tdcall: move td-report under tdcall feature Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tdx-tdcall/src/lib.rs b/tdx-tdcall/src/lib.rs index 44a5571d..1598b124 100644 --- a/tdx-tdcall/src/lib.rs +++ b/tdx-tdcall/src/lib.rs @@ -29,8 +29,9 @@ pub const USE_TDX_EMULATION: bool = true; pub const USE_TDX_EMULATION: bool = false; pub mod asm; +#[cfg(feature = "tdcall")] pub mod tdreport; -#[cfg(feature = "tdvmcall")] -pub mod tdvmcall; #[cfg(feature = "tdcall")] pub mod tdcall; +#[cfg(feature = "tdvmcall")] +pub mod tdvmcall; From eb829c541c08550070c6fb5dc3dfb4e25f3aa959 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 4 Mar 2025 12:21:47 +0100 Subject: [PATCH 17/31] td-payload: add non-tdvmcall version of enable_apic_interrupt Signed-off-by: Stanislaw Grams --- td-payload/src/arch/x86_64/apic.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/td-payload/src/arch/x86_64/apic.rs b/td-payload/src/arch/x86_64/apic.rs index 0389ae50..14d7976b 100644 --- a/td-payload/src/arch/x86_64/apic.rs +++ b/td-payload/src/arch/x86_64/apic.rs @@ -25,6 +25,17 @@ pub fn enable_apic_interrupt() { .expect("fail to perform WRMSR operation\n"); } +#[cfg(not(feature = "tdvmcall"))] +pub fn enable_apic_interrupt() { + // Enable the local APIC by setting bit 8 of the APIC spurious vector region (SVR) + // Ref: Intel SDM Vol3. 8.4.4.1 + // In x2APIC mode, SVR is mapped to MSR address 0x80f. + let svr = unsafe { x86::msr::rdmsr(0x80f) }; + unsafe { + x86::msr::wrmsr(0x80f, svr | (0x1 << 8)); + } +} + pub fn enable_and_hlt() { #[cfg(feature = "tdvmcall")] tdx_tdcall::tdvmcall::sti_halt(); From 50056a3e8a3c9eceb5d515b549342c62b4a77bb2 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 4 Mar 2025 12:25:12 +0100 Subject: [PATCH 18/31] td-payload: add non-tdvmcall versions of decrypt and encrypt Signed-off-by: Stanislaw Grams --- td-payload/src/arch/x86_64/shared.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/td-payload/src/arch/x86_64/shared.rs b/td-payload/src/arch/x86_64/shared.rs index cef46426..4ae90e52 100644 --- a/td-payload/src/arch/x86_64/shared.rs +++ b/td-payload/src/arch/x86_64/shared.rs @@ -11,7 +11,6 @@ use tdx_tdcall::tdcall; #[cfg(feature = "tdvmcall")] use tdx_tdcall::tdvmcall; -#[cfg(feature = "tdvmcall")] use super::paging::{clear_shared_bit, set_shared_bit}; #[cfg(feature = "tdvmcall")] @@ -35,6 +34,17 @@ pub fn encrypt(addr: u64, length: usize) { accept_memory(addr, length); } +#[cfg(not(feature = "tdvmcall"))] +pub fn decrypt(addr: u64, length: usize) { + set_shared_bit(addr, length); +} + +#[cfg(not(feature = "tdvmcall"))] +pub fn encrypt(addr: u64, length: usize) { + clear_shared_bit(addr, length); + accept_memory(addr, length); +} + #[cfg(feature = "tdcall")] fn accept_memory(addr: u64, length: usize) { let page_num = length / SIZE_4K; From 97db27531b99847ba1d8fab58edd88495f05698f Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Mon, 3 Mar 2025 15:07:37 +0100 Subject: [PATCH 19/31] tdx-tdcall: Bump version after changing the API Signed-off-by: Stanislaw Grams --- tdx-tdcall/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdx-tdcall/Cargo.toml b/tdx-tdcall/Cargo.toml index fc95ae54..75d3cbe0 100644 --- a/tdx-tdcall/Cargo.toml +++ b/tdx-tdcall/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tdx-tdcall" -version = "0.2.1" +version = "0.3.0" description = "Constants, stuctures and wrappers to access TDCALL services" repository = "https://github.com/confidential-containers/td-shim" homepage = "https://github.com/confidential-containers" From 0a394379dabe229f55abe5575d04d83a45069f36 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 4 Mar 2025 12:07:24 +0100 Subject: [PATCH 20/31] Cargo.lock: lock tdx-tdcall version after bump Signed-off-by: Stanislaw Grams --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index b62a087b..6ed270ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1255,7 +1255,7 @@ dependencies = [ [[package]] name = "tdx-tdcall" -version = "0.2.1" +version = "0.3.0" dependencies = [ "lazy_static", "log", From e8faa4cc6cc603f26ea5f6238636da26227e9e5e Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 09:43:09 +0100 Subject: [PATCH 21/31] xtask: enable tdvmcall feature by default Signed-off-by: Stanislaw Grams --- xtask/src/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xtask/src/build.rs b/xtask/src/build.rs index 0c5d0f98..5193ae79 100644 --- a/xtask/src/build.rs +++ b/xtask/src/build.rs @@ -11,7 +11,7 @@ use std::{ }; use xshell::{cmd, Shell}; -const TD_SHIM_DEFAULT_FEATURES: &str = "main,tdcall"; +const TD_SHIM_DEFAULT_FEATURES: &str = "main,tdcall,tdvmcall"; lazy_static! { static ref PROJECT_ROOT: &'static Path = @@ -42,7 +42,7 @@ pub(crate) struct BuildArgs { #[arg(short, long)] output: Option, /// List of features of `td-shim` crate to activate in addition to the `main` and `tdcall`, - /// separated by comma. By default, only the `main` and `tdcall` features of `td-shim` are enabled + /// separated by comma. By default, only the `main`, `tdcall` and `tdvmcall` features of `td-shim` are enabled #[arg(long)] features: Option, /// Path of customized metadata configuration file @@ -140,7 +140,7 @@ impl BuildArgs { sh, "cargo build -p td-payload --bin example --target x86_64-unknown-none" ) - .args(["--features", "tdcall,start,cet-shstk,stack-guard"]) + .args(["--features", "tdcall,tdvmcall,start,cet-shstk,stack-guard"]) .args(["--profile", self.profile()]) .run()?; From 9ccd2363a0579fb63907dbcaf630f729e2766cb0 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 09:45:46 +0100 Subject: [PATCH 22/31] tdx-tdcall: fix-up src/asm after tdcall rename Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/asm/mod.rs | 4 ++-- tdx-tdcall/src/asm/tdcall_emu.asm | 4 ++-- tdx-tdcall/src/asm/tdvmcall_emu.asm | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tdx-tdcall/src/asm/mod.rs b/tdx-tdcall/src/asm/mod.rs index abe7de7e..02e43d40 100644 --- a/tdx-tdcall/src/asm/mod.rs +++ b/tdx-tdcall/src/asm/mod.rs @@ -5,10 +5,10 @@ use core::arch::global_asm; use core::ffi::c_void; #[cfg(feature = "use_tdx_emulation")] -global_asm!(include_str!("tdcall::emu.asm")); +global_asm!(include_str!("tdcall_emu.asm")); #[cfg(feature = "use_tdx_emulation")] -global_asm!(include_str!("tdvmcall::emu.asm")); +global_asm!(include_str!("tdvmcall_emu.asm")); #[cfg(not(feature = "use_tdx_emulation"))] global_asm!(include_str!("tdcall.asm")); diff --git a/tdx-tdcall/src/asm/tdcall_emu.asm b/tdx-tdcall/src/asm/tdcall_emu.asm index 073878a5..988c2c70 100644 --- a/tdx-tdcall/src/asm/tdcall_emu.asm +++ b/tdx-tdcall/src/asm/tdcall_emu.asm @@ -19,7 +19,7 @@ .global td_call td_call: endbr64 - # tdcall::push_regs + # tdcall_push_regs push rbp mov rbp, rsp push r15 @@ -57,7 +57,7 @@ td_call: mov [r12+32], r10 mov [r12+40], r11 exit: - # tdcall::pop_regs + # tdcall_pop_regs pop rdi pop rsi pop rbx diff --git a/tdx-tdcall/src/asm/tdvmcall_emu.asm b/tdx-tdcall/src/asm/tdvmcall_emu.asm index 19016e71..33cd99cb 100644 --- a/tdx-tdcall/src/asm/tdvmcall_emu.asm +++ b/tdx-tdcall/src/asm/tdvmcall_emu.asm @@ -26,7 +26,7 @@ .global td_vm_call td_vm_call: endbr64 - # tdcall::push_regs + # tdcall_push_regs push rbp mov rbp, rsp push r15 @@ -43,7 +43,7 @@ td_vm_call: mov r14, r9 mov r15, [rsp+first_variable_on_stack_offset] - #tdcall::regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK + #tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK mov rax, TDVMCALL mov ecx, TDVMCALL_EXPOSE_REGS_MASK @@ -89,7 +89,7 @@ td_vm_call: mov [r9], r11 no_return_data: - #tdcall::regs_postamble + #tdcall_regs_postamble xor ebx, ebx xor esi, esi xor edi, edi @@ -101,7 +101,7 @@ no_return_data: xor r10d, r10d xor r11d, r11d - # tdcall::pop_regs + # tdcall_pop_regs pop rdi pop rsi pop rbx From b4c44a314c54e563a79c94b3f35a47766f66eaa6 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 09:54:42 +0100 Subject: [PATCH 23/31] .github: update CI to use tdcall and tdvmcall instead of tdx feature Signed-off-by: Stanislaw Grams --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e7bde598..54b44a03 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,18 +53,18 @@ jobs: - name: Add `x86_64-unknown-none` target run: rustup target add x86_64-unknown-none - + - name: Preparation Work run: bash sh_script/preparation.sh - name: Test Shim Crates - run: make test + run: make test - name: Build Release TdShim - run: cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdx - + run: cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdcall,tdvmcall + - name: Build Debug TdShim - run: cargo build -p td-shim --target x86_64-unknown-none --features=main,tdx --no-default-features + run: cargo build -p td-shim --target x86_64-unknown-none --features=main,tdcall,tdvmcall --no-default-features - name: Build td-shim-tools run: | @@ -73,7 +73,7 @@ jobs: - name: Build image without payload run: | cargo image --release - + - name: Meta data check run: | cargo run -p td-shim-tools --bin td-shim-checker --no-default-features --features=loader -- target/release/final.bin From 5212396c665181bcddcf1d9ba1211a0233474c65 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 09:59:12 +0100 Subject: [PATCH 24/31] tdx-tdcall: fix-up clippy errors Signed-off-by: Stanislaw Grams --- tdx-tdcall/src/tdcall.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tdx-tdcall/src/tdcall.rs b/tdx-tdcall/src/tdcall.rs index 6c75f0e6..93f499d1 100644 --- a/tdx-tdcall/src/tdcall.rs +++ b/tdx-tdcall/src/tdcall.rs @@ -248,7 +248,7 @@ pub fn accept_page(address: u64) -> Result<(), TdCallError> { } } - return Err(ret.into()); + Err(ret.into()) } /// Accept a range of private pages and initialize the pages to zeros using the TD ephemeral @@ -591,7 +591,7 @@ pub fn mem_page_attr_wr( } } - return Err(ret.into()); + Err(ret.into()) } #[cfg(test)] From ddc36b739af7196ce0c2325ad4fe51b089e29ec9 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 10:02:44 +0100 Subject: [PATCH 25/31] tdx-tdcall,td-payload: fix-up cargo fmt errors Signed-off-by: Stanislaw Grams --- td-payload/src/arch/x86_64/shared.rs | 1 - tdx-tdcall/src/lib.rs | 4 ++-- tdx-tdcall/src/tdcall.rs | 2 +- tdx-tdcall/src/tdreport.rs | 2 +- tdx-tdcall/src/tdvmcall.rs | 7 ++++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/td-payload/src/arch/x86_64/shared.rs b/td-payload/src/arch/x86_64/shared.rs index 4ae90e52..da69482d 100644 --- a/td-payload/src/arch/x86_64/shared.rs +++ b/td-payload/src/arch/x86_64/shared.rs @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: BSD-2-Clause-Patent - #[cfg(feature = "tdcall")] use crate::mm::SIZE_4K; #[cfg(feature = "tdcall")] diff --git a/tdx-tdcall/src/lib.rs b/tdx-tdcall/src/lib.rs index 1598b124..6275da53 100644 --- a/tdx-tdcall/src/lib.rs +++ b/tdx-tdcall/src/lib.rs @@ -30,8 +30,8 @@ pub const USE_TDX_EMULATION: bool = false; pub mod asm; #[cfg(feature = "tdcall")] -pub mod tdreport; -#[cfg(feature = "tdcall")] pub mod tdcall; +#[cfg(feature = "tdcall")] +pub mod tdreport; #[cfg(feature = "tdvmcall")] pub mod tdvmcall; diff --git a/tdx-tdcall/src/tdcall.rs b/tdx-tdcall/src/tdcall.rs index 93f499d1..2ea1626d 100644 --- a/tdx-tdcall/src/tdcall.rs +++ b/tdx-tdcall/src/tdcall.rs @@ -8,8 +8,8 @@ //! The TDCALL instruction causes a VM exit to the Intel TDX Module. It is used to call //! guest-side Intel TDX functions, either local or a TD exit to the host VMM. -use core::result::Result; use crate::*; +use core::result::Result; pub const PAGE_SIZE_4K: u64 = 0x1000; pub const PAGE_SIZE_2M: u64 = 0x200000; diff --git a/tdx-tdcall/src/tdreport.rs b/tdx-tdcall/src/tdreport.rs index 02895548..059a5707 100644 --- a/tdx-tdcall/src/tdreport.rs +++ b/tdx-tdcall/src/tdreport.rs @@ -7,7 +7,7 @@ use core::mem::{size_of, zeroed}; use core::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; use scroll::{Pread, Pwrite}; -use crate::tdcall::{td_call, TdCallError, TdcallArgs, TDCALL_TDREPORT, TDCALL_STATUS_SUCCESS}; +use crate::tdcall::{td_call, TdCallError, TdcallArgs, TDCALL_STATUS_SUCCESS, TDCALL_TDREPORT}; pub const TD_REPORT_SIZE: usize = 0x400; pub const TD_REPORT_ADDITIONAL_DATA_SIZE: usize = 64; diff --git a/tdx-tdcall/src/tdvmcall.rs b/tdx-tdcall/src/tdvmcall.rs index 282a9cc3..71872a9b 100644 --- a/tdx-tdcall/src/tdvmcall.rs +++ b/tdx-tdcall/src/tdvmcall.rs @@ -7,14 +7,15 @@ //! TDVMCALL (TDG.VP.VMCALL) is a leaf function 0 for TDCALL. It helps invoke services from //! the host VMM. +use crate::*; use core::result::Result; -use x86_64::registers::rflags::{self, RFlags}; use core::sync::atomic::{fence, Ordering}; use lazy_static::lazy_static; -use crate::*; +use x86_64::registers::rflags::{self, RFlags}; lazy_static! { - static ref SHARED_MASK: u64 = tdcall::td_shared_mask().expect("Fail to get the shared mask of TD"); + static ref SHARED_MASK: u64 = + tdcall::td_shared_mask().expect("Fail to get the shared mask of TD"); } // GTDG.VP.VMCALL leaf sub-function numbers From a7c03cb1cf879f723dd02be47fbf990518f6c6f5 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 11:15:56 +0100 Subject: [PATCH 26/31] sh_script: replace tdx feature with tdcall and tdvmcall Signed-off-by: Stanislaw Grams --- sh_script/build_final.sh | 12 ++++++------ sh_script/rudra.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sh_script/build_final.sh b/sh_script/build_final.sh index 38440382..4164d1b4 100644 --- a/sh_script/build_final.sh +++ b/sh_script/build_final.sh @@ -20,13 +20,13 @@ final_boot_kernel() { final_elf() { echo final-elf - cargo --example-payload -o target/release/final-elf.bin + cargo --example-payload -o target/release/final-elf.bin } final_elf_test() { echo "Build final binary with ELF format test td payload" pushd tests - cargo build -p test-td-payload --target x86_64-unknown-none --release --features=main,tdx --no-default-features + cargo build -p test-td-payload --target x86_64-unknown-none --release --features=main,tdcall,tdvmcall --no-default-features popd cargo run -p td-shim-tools --bin td-shim-strip-info -- -n test-td-payload --target x86_64-unknown-none @@ -37,15 +37,15 @@ final_elf_test() { -p target/x86_64-unknown-none/release/test-td-payload \ --enroll-file F10E684E-3ABD-20E4-5932-8F973C355E57,tests/test-td-payload/config/test_config_${i}.json \ -o target/release/final-elf-test${i}.bin - done + done } final_elf_sb_test() { echo "Build final binaries with ELF format td payload for secure boot test" - cargo build -p td-payload --target x86_64-unknown-none --release --bin example --features=tdx,start,cet-shstk,stack-guard + cargo build -p td-payload --target x86_64-unknown-none --release --bin example --features=tdcall,tdvmcall,start,cet-shstk,stack-guard cargo run -p td-shim-tools --bin td-shim-strip-info -- -n example --target x86_64-unknown-none - cargo run -p td-shim-tools --bin td-shim-sign-payload -- -A ECDSA_NIST_P384_SHA384 data/sample-keys/ecdsa-p384-private.pk8 target/x86_64-unknown-none/release/example 1 1 + cargo run -p td-shim-tools --bin td-shim-sign-payload -- -A ECDSA_NIST_P384_SHA384 data/sample-keys/ecdsa-p384-private.pk8 target/x86_64-unknown-none/release/example 1 1 echo "Build final binary with unsigned td payload" cargo image --release -t executable --features secure-boot \ @@ -77,5 +77,5 @@ case "${1:-}" in elf) final_elf ;; elf_test) final_elf_test ;; elf_sb_test) final_elf_sb_test ;; - *) final_boot_kernel && final_elf && final_elf_test && final_elf_sb_test;; + *) final_boot_kernel && final_elf && final_elf_test && final_elf_sb_test;; esac diff --git a/sh_script/rudra.sh b/sh_script/rudra.sh index 15f27aa0..7ff09c46 100644 --- a/sh_script/rudra.sh +++ b/sh_script/rudra.sh @@ -34,7 +34,7 @@ for i in ${paths[@]}; do pushd $PWD/$i case "$i" in - td-shim) cargo rudra --features main,tdx ;; + td-shim) cargo rudra --features main,tdcall,tdvmcall ;; *) cargo rudra ;; esac From 4b445f03cc5c7ce5100bc8eaf369fdd57d911d3f Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 11:26:42 +0100 Subject: [PATCH 27/31] tdx-tdcall: Update CHANGELOG.md Signed-off-by: Stanislaw Grams --- tdx-tdcall/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tdx-tdcall/CHANGELOG.md b/tdx-tdcall/CHANGELOG.md index 1b06898f..58a3c273 100644 --- a/tdx-tdcall/CHANGELOG.md +++ b/tdx-tdcall/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. +## [0.3.0] - 2025-03-05 +### Changed +- Split tdx feature into two features: tdcall, tdvmcall +- Moved corresponding functions into tdcall.rs and tdvmcall.rs + ## [0.2.1] - 2024-07-23 ### Changed - Remove nightly feature in the x86_64 crate From e4d0c6f7333e58bc0e2c3c5e07f68c4434f26778 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Fri, 7 Mar 2025 10:44:17 +0100 Subject: [PATCH 28/31] xtask,td-shim,sh_script: tdx feature now consists of tdcall and tdvmcall Signed-off-by: Stanislaw Grams --- .github/workflows/main.yml | 4 ++-- sh_script/build_final.sh | 2 +- td-payload/Cargo.toml | 1 + td-shim/Cargo.toml | 1 + tests/test-td-payload/Cargo.toml | 7 ++++--- xtask/src/build.rs | 4 ++-- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 54b44a03..ab67bcf1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,10 +61,10 @@ jobs: run: make test - name: Build Release TdShim - run: cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdcall,tdvmcall + run: cargo build -p td-shim --target x86_64-unknown-none --release --features=main,tdx - name: Build Debug TdShim - run: cargo build -p td-shim --target x86_64-unknown-none --features=main,tdcall,tdvmcall --no-default-features + run: cargo build -p td-shim --target x86_64-unknown-none --features=main,tdx --no-default-features - name: Build td-shim-tools run: | diff --git a/sh_script/build_final.sh b/sh_script/build_final.sh index 4164d1b4..86118291 100644 --- a/sh_script/build_final.sh +++ b/sh_script/build_final.sh @@ -26,7 +26,7 @@ final_elf() { final_elf_test() { echo "Build final binary with ELF format test td payload" pushd tests - cargo build -p test-td-payload --target x86_64-unknown-none --release --features=main,tdcall,tdvmcall --no-default-features + cargo build -p test-td-payload --target x86_64-unknown-none --release --features=main,tdx --no-default-features popd cargo run -p td-shim-tools --bin td-shim-strip-info -- -n test-td-payload --target x86_64-unknown-none diff --git a/td-payload/Cargo.toml b/td-payload/Cargo.toml index ce526e46..44e6f5e1 100644 --- a/td-payload/Cargo.toml +++ b/td-payload/Cargo.toml @@ -38,6 +38,7 @@ minicov = { version = "0.2", default-features = false, optional = true } default = ["tdcall"] tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall"] tdvmcall = ["tdx-tdcall/tdvmcall", "td-logger/tdvmcall"] +tdx = ["tdcall", "tdvmcall"] stack-guard = [] cet-shstk = ["td-exception/cet-shstk"] cet-ibt = [] diff --git a/td-shim/Cargo.toml b/td-shim/Cargo.toml index 01c5ff3b..6d83ddd5 100644 --- a/td-shim/Cargo.toml +++ b/td-shim/Cargo.toml @@ -49,6 +49,7 @@ default = ["secure-boot"] secure-boot = ["der", "ring"] tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall", "x86"] tdvmcall = ["tdx-tdcall/tdvmcall", "td-exception/tdvmcall", "td-logger/tdvmcall", "x86"] +tdx = ["tdcall", "tdvmcall"] lazy-accept = ["tdcall"] ring-hash = ["cc-measurement/ring"] sha2-hash = ["cc-measurement/sha2"] diff --git a/tests/test-td-payload/Cargo.toml b/tests/test-td-payload/Cargo.toml index a047ee29..f8ef9495 100644 --- a/tests/test-td-payload/Cargo.toml +++ b/tests/test-td-payload/Cargo.toml @@ -24,7 +24,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] } x86 = { version = "0.47.0" } ring = { version = "0.17.6", default-features = false, features = ["alloc"] } td-shim = { path = "../../td-shim" } -td-payload = { path = "../../td-payload", features = ["tdcall","tdvmcall","cet-shstk","stack-guard"] } +td-payload = { path = "../../td-payload", features = ["cet-shstk","stack-guard"] } zerocopy = { version = "0.7.31", features = ["derive"] } minicov = { version = "0.2", default-features = false, optional = true } @@ -37,7 +37,8 @@ features = ["spin_no_std"] map-physical-memory = true [features] -tdvmcall = ["tdx-tdcall/tdvmcall", "td-logger/tdvmcall"] -tdcall = ["tdx-tdcall/tdcall"] +tdvmcall = ["td-payload/tdvmcall", "tdx-tdcall/tdvmcall", "td-logger/tdvmcall"] +tdcall = ["td-payload/tdcall", "tdx-tdcall/tdcall"] +tdx = ["tdcall", "tdvmcall"] main = [] coverage = ["minicov"] diff --git a/xtask/src/build.rs b/xtask/src/build.rs index 5193ae79..0aef0fad 100644 --- a/xtask/src/build.rs +++ b/xtask/src/build.rs @@ -11,7 +11,7 @@ use std::{ }; use xshell::{cmd, Shell}; -const TD_SHIM_DEFAULT_FEATURES: &str = "main,tdcall,tdvmcall"; +const TD_SHIM_DEFAULT_FEATURES: &str = "main,tdx"; lazy_static! { static ref PROJECT_ROOT: &'static Path = @@ -42,7 +42,7 @@ pub(crate) struct BuildArgs { #[arg(short, long)] output: Option, /// List of features of `td-shim` crate to activate in addition to the `main` and `tdcall`, - /// separated by comma. By default, only the `main`, `tdcall` and `tdvmcall` features of `td-shim` are enabled + /// separated by comma. By default, only the `main` and `tdx` features of `td-shim` are enabled #[arg(long)] features: Option, /// Path of customized metadata configuration file From 36fc18a0344cb1e42da4356abdc0deeb5302632e Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Fri, 7 Mar 2025 11:02:21 +0100 Subject: [PATCH 29/31] td-payload: add td-exception/tdvmcall dependency to tdvmcall feature Signed-off-by: Stanislaw Grams --- td-payload/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td-payload/Cargo.toml b/td-payload/Cargo.toml index 44e6f5e1..5d2b1772 100644 --- a/td-payload/Cargo.toml +++ b/td-payload/Cargo.toml @@ -37,7 +37,7 @@ minicov = { version = "0.2", default-features = false, optional = true } [features] default = ["tdcall"] tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall"] -tdvmcall = ["tdx-tdcall/tdvmcall", "td-logger/tdvmcall"] +tdvmcall = ["tdx-tdcall/tdvmcall", "td-exception/tdvmcall", "td-logger/tdvmcall"] tdx = ["tdcall", "tdvmcall"] stack-guard = [] cet-shstk = ["td-exception/cet-shstk"] From 15c85e23e419678030744a98e604746f770d717b Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Fri, 7 Mar 2025 11:16:33 +0100 Subject: [PATCH 30/31] sh_script,td-payload,xtask: replace tdcall,tdvmcall with tdx for backward compatiblity Signed-off-by: Stanislaw Grams --- sh_script/build_final.sh | 2 +- sh_script/rudra.sh | 2 +- td-payload/Cargo.toml | 2 +- xtask/src/build.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sh_script/build_final.sh b/sh_script/build_final.sh index 86118291..785cfe9b 100644 --- a/sh_script/build_final.sh +++ b/sh_script/build_final.sh @@ -42,7 +42,7 @@ final_elf_test() { final_elf_sb_test() { echo "Build final binaries with ELF format td payload for secure boot test" - cargo build -p td-payload --target x86_64-unknown-none --release --bin example --features=tdcall,tdvmcall,start,cet-shstk,stack-guard + cargo build -p td-payload --target x86_64-unknown-none --release --bin example --features=tdx,start,cet-shstk,stack-guard cargo run -p td-shim-tools --bin td-shim-strip-info -- -n example --target x86_64-unknown-none cargo run -p td-shim-tools --bin td-shim-sign-payload -- -A ECDSA_NIST_P384_SHA384 data/sample-keys/ecdsa-p384-private.pk8 target/x86_64-unknown-none/release/example 1 1 diff --git a/sh_script/rudra.sh b/sh_script/rudra.sh index 7ff09c46..15f27aa0 100644 --- a/sh_script/rudra.sh +++ b/sh_script/rudra.sh @@ -34,7 +34,7 @@ for i in ${paths[@]}; do pushd $PWD/$i case "$i" in - td-shim) cargo rudra --features main,tdcall,tdvmcall ;; + td-shim) cargo rudra --features main,tdx ;; *) cargo rudra ;; esac diff --git a/td-payload/Cargo.toml b/td-payload/Cargo.toml index 5d2b1772..ba93755f 100644 --- a/td-payload/Cargo.toml +++ b/td-payload/Cargo.toml @@ -35,7 +35,7 @@ zerocopy = { version = "0.7.31", features = ["derive"] } minicov = { version = "0.2", default-features = false, optional = true } [features] -default = ["tdcall"] +default = ["tdx"] tdcall = ["tdx-tdcall/tdcall", "td-exception/tdcall"] tdvmcall = ["tdx-tdcall/tdvmcall", "td-exception/tdvmcall", "td-logger/tdvmcall"] tdx = ["tdcall", "tdvmcall"] diff --git a/xtask/src/build.rs b/xtask/src/build.rs index 0aef0fad..ff5abae9 100644 --- a/xtask/src/build.rs +++ b/xtask/src/build.rs @@ -41,7 +41,7 @@ pub(crate) struct BuildArgs { /// Path of the output td-shim image file #[arg(short, long)] output: Option, - /// List of features of `td-shim` crate to activate in addition to the `main` and `tdcall`, + /// List of features of `td-shim` crate to activate in addition to the `main` and `tdx`, /// separated by comma. By default, only the `main` and `tdx` features of `td-shim` are enabled #[arg(long)] features: Option, @@ -140,7 +140,7 @@ impl BuildArgs { sh, "cargo build -p td-payload --bin example --target x86_64-unknown-none" ) - .args(["--features", "tdcall,tdvmcall,start,cet-shstk,stack-guard"]) + .args(["--features", "tdx,start,cet-shstk,stack-guard"]) .args(["--profile", self.profile()]) .run()?; From 87859682cf5348e2f59af5b9b5b6e3d062d7bbb4 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Wed, 5 Mar 2025 15:42:11 +0100 Subject: [PATCH 31/31] td-shim,tdx-tdcall: gate asm_td_call and asm_td_vmcall Signed-off-by: Stanislaw Grams --- td-shim/src/bin/td-shim/asm/mod.rs | 8 ++++---- tdx-tdcall/src/asm/mod.rs | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/td-shim/src/bin/td-shim/asm/mod.rs b/td-shim/src/bin/td-shim/asm/mod.rs index 41b2a21e..46a4e892 100644 --- a/td-shim/src/bin/td-shim/asm/mod.rs +++ b/td-shim/src/bin/td-shim/asm/mod.rs @@ -5,15 +5,15 @@ use core::arch::global_asm; global_asm!(include_str!("msr64.asm")); -#[cfg(not(feature = "tdvmcall"))] +#[cfg(feature = "tdvmcall")] global_asm!(include_str!("exception.asm")); #[cfg(not(feature = "tdvmcall"))] -global_asm!(include_str!("ap_loop_notdvmcall.asm")); - -#[cfg(feature = "tdvmcall")] global_asm!(include_str!("exception_notdvmcall.asm")); + #[cfg(feature = "tdvmcall")] global_asm!(include_str!("ap_loop.asm")); +#[cfg(not(feature = "tdvmcall"))] +global_asm!(include_str!("ap_loop_notdvmcall.asm")); extern "C" { fn ap_relocated_func(); diff --git a/tdx-tdcall/src/asm/mod.rs b/tdx-tdcall/src/asm/mod.rs index 02e43d40..33ee4853 100644 --- a/tdx-tdcall/src/asm/mod.rs +++ b/tdx-tdcall/src/asm/mod.rs @@ -4,19 +4,21 @@ use core::arch::global_asm; use core::ffi::c_void; -#[cfg(feature = "use_tdx_emulation")] +#[cfg(all(feature = "use_tdx_emulation", feature = "tdcall"))] global_asm!(include_str!("tdcall_emu.asm")); -#[cfg(feature = "use_tdx_emulation")] +#[cfg(all(feature = "use_tdx_emulation", feature = "tdvmcall"))] global_asm!(include_str!("tdvmcall_emu.asm")); -#[cfg(not(feature = "use_tdx_emulation"))] +#[cfg(all(not(feature = "use_tdx_emulation"), feature = "tdcall"))] global_asm!(include_str!("tdcall.asm")); -#[cfg(not(feature = "use_tdx_emulation"))] +#[cfg(all(not(feature = "use_tdx_emulation"), feature = "tdvmcall"))] global_asm!(include_str!("tdvmcall.asm")); extern "win64" { + #[cfg(feature = "tdcall")] pub(crate) fn asm_td_call(args: *mut c_void) -> u64; + #[cfg(feature = "tdvmcall")] pub(crate) fn asm_td_vmcall(args: *mut c_void, do_sti: u64) -> u64; }