From 737fb11e4816d5656e5d675454d9c9adda3bc8c8 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Mon, 22 Jul 2024 18:18:03 -0700 Subject: [PATCH 01/13] igvmbuilder: Insert a zero CPUID page for TDP platforms Since both the stage2 bootloader and the SVSM kernel dump the CPUID page, there needs to be a page present at the respective GPA on TDP platforms. Insert a normal zero page at the CPUID page location so that dump_cpuid_table() can work as expected. Signed-off-by: Peter Fang --- igvmbuilder/src/igvm_builder.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/igvmbuilder/src/igvm_builder.rs b/igvmbuilder/src/igvm_builder.rs index f620fbfa1..ff79a09df 100644 --- a/igvmbuilder/src/igvm_builder.rs +++ b/igvmbuilder/src/igvm_builder.rs @@ -428,6 +428,15 @@ impl IgvmBuilder { IgvmPageDataType::SECRETS, )?; } + if COMPATIBILITY_MASK.contains(TDP_COMPATIBILITY_MASK) { + // Insert a zero page in place of the CPUID page + self.add_empty_pages( + self.gpa_map.cpuid_page.get_start(), + self.gpa_map.cpuid_page.get_size(), + TDP_COMPATIBILITY_MASK, + IgvmPageDataType::NORMAL, + )?; + } // Add optional stage 1 binary. if let Some(stage1) = &self.options.tdx_stage1 { From 082a840037fcf92bf13314187f707e6ef129685d Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Fri, 26 Jul 2024 03:37:48 -0700 Subject: [PATCH 02/13] igvmbuilder: Insert a zero secrets page for TDP platforms Since the SVSM kernel touches the secrets page in svsm_start(), there needs to be a page present at the respective GPA on TDP platforms. Insert a normal zero page at the secrets page location so that the SVSM kernel can touch it without issues. Signed-off-by: Peter Fang --- igvmbuilder/src/igvm_builder.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/igvmbuilder/src/igvm_builder.rs b/igvmbuilder/src/igvm_builder.rs index ff79a09df..955f88dbe 100644 --- a/igvmbuilder/src/igvm_builder.rs +++ b/igvmbuilder/src/igvm_builder.rs @@ -436,6 +436,14 @@ impl IgvmBuilder { TDP_COMPATIBILITY_MASK, IgvmPageDataType::NORMAL, )?; + + // Insert a zero page in place of the secrets page + self.add_empty_pages( + self.gpa_map.secrets_page.get_start(), + self.gpa_map.secrets_page.get_size(), + TDP_COMPATIBILITY_MASK, + IgvmPageDataType::NORMAL, + )?; } // Add optional stage 1 binary. From 7a5b260ea8921093af10179b2dc693fd2fee320c Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Mon, 22 Jul 2024 18:27:24 -0700 Subject: [PATCH 03/13] Cargo.toml: Clean up Clean up formatting and crate ordering. Signed-off-by: Peter Fang --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f1e2906be..acdc59aa7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,16 +32,16 @@ aes-gcm = { version = "0.10.3", default-features = false } arbitrary = "1.3.0" bitfield-struct = "0.6.2" bitflags = "2.4" -clap = { version = "4.4.14", default-features = false} +clap = { version = "4.4.14", default-features = false } gdbstub = { version = "0.6.6", default-features = false } gdbstub_arch = { version = "0.2.4" } -sha2 = "0.10.8" -igvm_defs = { version = "0.3.2", default-features = false} -igvm = { version = "0.3.2", default-features = false} +igvm = { version = "0.3.2", default-features = false } +igvm_defs = { version = "0.3.2", default-features = false } intrusive-collections = "0.9.6" libfuzzer-sys = "0.4" log = "0.4.17" p384 = { version = "0.13.0" } +sha2 = "0.10.8" uuid = "1.6.1" # Add the derive feature by default because all crates use it. zerocopy = { version = "0.8.2", features = ["alloc", "derive"] } From 53eccbe93a1e4bdd073cf88f29a67ff5772a918b Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Mon, 22 Jul 2024 18:30:52 -0700 Subject: [PATCH 04/13] Cargo.toml: Add tdx-tdcall crate Add the tdx-tdcall crate in preparation for the upcoming TDX enabling changes. Signed-off-by: Peter Fang --- Cargo.toml | 1 + kernel/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index acdc59aa7..682019d5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ libfuzzer-sys = "0.4" log = "0.4.17" p384 = { version = "0.13.0" } sha2 = "0.10.8" +tdx-tdcall = "0.2.1" uuid = "1.6.1" # Add the derive feature by default because all crates use it. zerocopy = { version = "0.8.2", features = ["alloc", "derive"] } diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index d2abf5a43..a1a3f649d 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -33,6 +33,7 @@ igvm_defs = { workspace = true, features = ["unstable"] } intrusive-collections.workspace = true log = { workspace = true, features = ["max_level_info", "release_max_level_info"] } packit.workspace = true +tdx-tdcall.workspace = true libmstpm = { workspace = true, optional = true } zerocopy.workspace = true From 15053baf9d74912479fc4c5de99b7e08c4704566 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Wed, 21 Aug 2024 04:56:41 -0700 Subject: [PATCH 05/13] stage1: Fix stage2 launch info size Stage2LaunchInfo has been increased to 48 bytes. Make the according changes in stage1 trampoline. Signed-off-by: Peter Fang --- stage1/stage1.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stage1/stage1.S b/stage1/stage1.S index 6f449a162..10e17bdee 100644 --- a/stage1/stage1.S +++ b/stage1/stage1.S @@ -87,7 +87,7 @@ startup_32: * Stage 2 launch info has been prepared * Make sure platform type is TDP */ - movl $(STAGE1_STACK - 32), %eax + movl $(STAGE1_STACK - 40), %eax movl (%eax), %eax cmpl $2, %eax je .Lsetup_td @@ -104,7 +104,7 @@ startup_32: .Lsetup_bsp_stack: /* Set up BSP stack for stage 2 */ - movl $(STAGE1_STACK - 40), %esp + movl $(STAGE1_STACK - 48), %esp /* %ebx is initialized with GPAW - save (1u64 << (GPAW - 1)) to vtom */ mov %esp, %eax /* GPAW must be either 48 or 52 */ From 2def94b5155a4a8a873b361e44b46bec67b7514b Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Wed, 21 Aug 2024 04:57:00 -0700 Subject: [PATCH 06/13] stage1: Revert lds change Setting the initial location counter has no effect since all of the addresses before edata are derived based on the subsequent locations. Signed-off-by: Peter Fang --- stage1/stage1.lds | 1 - 1 file changed, 1 deletion(-) diff --git a/stage1/stage1.lds b/stage1/stage1.lds index 2ead62330..4066f5d02 100644 --- a/stage1/stage1.lds +++ b/stage1/stage1.lds @@ -10,7 +10,6 @@ OUTPUT_ARCH(i386:x86-64) SECTIONS { - . = 0x800000; .stext = ALIGN(.sdata - SIZEOF(.text) - 4095, 4096); . = .stext; .text : { *(.startup.*) *(.text) *(.text.*) } From 08825893f6b06b44e858efef9414dab0cf123817 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Wed, 25 Sep 2024 01:01:56 -0700 Subject: [PATCH 07/13] platform: tdp: Add I/O port driver Add GHCI-based PIO driver to TdpPlatform. This implementation translates all of the in/out operations to TDVMCALL operations as required by the GHCI spec. Additionally, move console initialization to env_setup() to enable it as early as possible. Signed-off-by: Peter Fang --- kernel/src/platform/tdp.rs | 56 ++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/kernel/src/platform/tdp.rs b/kernel/src/platform/tdp.rs index 6ba12e878..b8c2b782a 100644 --- a/kernel/src/platform/tdp.rs +++ b/kernel/src/platform/tdp.rs @@ -9,12 +9,17 @@ use crate::console::init_svsm_console; use crate::cpu::cpuid::CpuidResult; use crate::cpu::percpu::PerCpu; use crate::error::SvsmError; -use crate::io::{IOPort, DEFAULT_IO_DRIVER}; +use crate::io::IOPort; use crate::platform::{PageEncryptionMasks, PageStateChangeOp, PageValidateOp, SvsmPlatform}; use crate::types::PageSize; use crate::utils::immut_after_init::ImmutAfterInitCell; use crate::utils::MemoryRegion; +use tdx_tdcall::tdx::{ + tdvmcall_io_read_16, tdvmcall_io_read_32, tdvmcall_io_read_8, tdvmcall_io_write_16, + tdvmcall_io_write_32, tdvmcall_io_write_8, +}; +static GHCI_IO_DRIVER: GHCIIOPort = GHCIIOPort::new(); static VTOM: ImmutAfterInitCell = ImmutAfterInitCell::uninit(); #[derive(Clone, Copy, Debug)] @@ -33,12 +38,14 @@ impl Default for TdpPlatform { } impl SvsmPlatform for TdpPlatform { - fn env_setup(&mut self, _debug_serial_port: u16, vtom: usize) -> Result<(), SvsmError> { - VTOM.init(&vtom).map_err(|_| SvsmError::PlatformInit) + fn env_setup(&mut self, debug_serial_port: u16, vtom: usize) -> Result<(), SvsmError> { + VTOM.init(&vtom).map_err(|_| SvsmError::PlatformInit)?; + // Serial console device can be initialized immediately + init_svsm_console(&GHCI_IO_DRIVER, debug_serial_port) } - fn env_setup_late(&mut self, debug_serial_port: u16) -> Result<(), SvsmError> { - init_svsm_console(&DEFAULT_IO_DRIVER, debug_serial_port) + fn env_setup_late(&mut self, _debug_serial_port: u16) -> Result<(), SvsmError> { + Ok(()) } fn env_setup_svsm(&self) -> Result<(), SvsmError> { @@ -72,9 +79,7 @@ impl SvsmPlatform for TdpPlatform { fn setup_guest_host_comm(&mut self, _cpu: &PerCpu, _is_bsp: bool) {} fn get_io_port(&self) -> &'static dyn IOPort { - // FIXME - the default I/O port implementation doesn't work on TDP, - // but the platform does not yet have an alternative available. - &DEFAULT_IO_DRIVER + &GHCI_IO_DRIVER } fn page_state_change( @@ -124,3 +129,38 @@ impl SvsmPlatform for TdpPlatform { todo!(); } } + +#[derive(Clone, Copy, Debug, Default)] +struct GHCIIOPort {} + +impl GHCIIOPort { + pub const fn new() -> Self { + GHCIIOPort {} + } +} + +impl IOPort for GHCIIOPort { + fn outb(&self, port: u16, value: u8) { + tdvmcall_io_write_8(port, value); + } + + fn inb(&self, port: u16) -> u8 { + tdvmcall_io_read_8(port) + } + + fn outw(&self, port: u16, value: u16) { + tdvmcall_io_write_16(port, value); + } + + fn inw(&self, port: u16) -> u16 { + tdvmcall_io_read_16(port) + } + + fn outl(&self, port: u16, value: u32) { + tdvmcall_io_write_32(port, value); + } + + fn inl(&self, port: u16) -> u32 { + tdvmcall_io_read_32(port) + } +} From 9783f454c0c3207f829233296f299be60b3e5d49 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Wed, 25 Sep 2024 01:05:07 -0700 Subject: [PATCH 08/13] stage2: Add logging before jumping into kernel Make stage2 a tad more verbose by signaling when it's about ready to jump into the SVSM kernel. Signed-off-by: Peter Fang --- kernel/src/stage2.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/src/stage2.rs b/kernel/src/stage2.rs index 1bfd6650e..3520ad39a 100755 --- a/kernel/src/stage2.rs +++ b/kernel/src/stage2.rs @@ -443,6 +443,8 @@ pub extern "C" fn stage2_main(launch_info: &Stage2LaunchInfo) { let valid_bitmap = valid_bitmap_addr(); + log::info!("Starting SVSM kernel..."); + // Shut down the GHCB unsafe { shutdown_percpu(); From 60a4b2c8d29903a7851a305cfb2c51baa2ed08c9 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Mon, 22 Jul 2024 18:48:50 -0700 Subject: [PATCH 09/13] platform: tdp: Fix phys_addr_sizes phys_addr_sizes should be the entirety of CPUID leaf 0x80000008.EAX, not just the Physical Address Bits field. Signed-off-by: Peter Fang --- kernel/src/platform/tdp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/platform/tdp.rs b/kernel/src/platform/tdp.rs index b8c2b782a..2bfb1eca4 100644 --- a/kernel/src/platform/tdp.rs +++ b/kernel/src/platform/tdp.rs @@ -68,7 +68,7 @@ impl SvsmPlatform for TdpPlatform { private_pte_mask: 0, shared_pte_mask: vtom, addr_mask_width: vtom.trailing_zeros(), - phys_addr_sizes: res.eax & 0xff, + phys_addr_sizes: res.eax, } } From c12ea27e73110db6909087bab56a2d31ac3cba76 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Thu, 17 Oct 2024 23:55:42 -0700 Subject: [PATCH 10/13] types: Introduce PAGE_SHIFT_1G/PAGE_SIZE_1G This is in preparation for the upcoming changes to PageTable::virt_to_phys(). Since 1G huge pages are architecturally permissible when translating a virtual address, PAGE_SIZE_1G is now a valid page size even though it's currently not actively used anywhere. Signed-off-by: Peter Fang --- kernel/src/types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/src/types.rs b/kernel/src/types.rs index e77ba8b0b..0f8f78cd6 100644 --- a/kernel/src/types.rs +++ b/kernel/src/types.rs @@ -9,8 +9,10 @@ use crate::sev::vmsa::VMPL_MAX; pub const PAGE_SHIFT: usize = 12; pub const PAGE_SHIFT_2M: usize = 21; +pub const PAGE_SHIFT_1G: usize = 30; pub const PAGE_SIZE: usize = 1 << PAGE_SHIFT; -pub const PAGE_SIZE_2M: usize = PAGE_SIZE * 512; +pub const PAGE_SIZE_2M: usize = 1 << PAGE_SHIFT_2M; +pub const PAGE_SIZE_1G: usize = 1 << PAGE_SHIFT_1G; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum PageSize { From 134bbad6dd716a3fa96d2a58b38d987a72886e27 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Fri, 18 Oct 2024 00:02:19 -0700 Subject: [PATCH 11/13] mm/pagetable: Introduce PageFrame PageFrame is an enum describing not only a physical address, but also the page frame to which it belongs. - PageFrame::address(): return its internal PhysAddr - PageFrame::start(): return the beginning of the page frame - PageFrame::end(): return the end of the page frame Signed-off-by: Peter Fang --- kernel/src/mm/pagetable.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/kernel/src/mm/pagetable.rs b/kernel/src/mm/pagetable.rs index c70a97911..a663b37b3 100644 --- a/kernel/src/mm/pagetable.rs +++ b/kernel/src/mm/pagetable.rs @@ -16,7 +16,7 @@ use crate::mm::{ SVSM_PTE_BASE, }; use crate::platform::SvsmPlatform; -use crate::types::{PageSize, PAGE_SIZE, PAGE_SIZE_2M}; +use crate::types::{PageSize, PAGE_SIZE, PAGE_SIZE_1G, PAGE_SIZE_2M}; use crate::utils::immut_after_init::{ImmutAfterInitCell, ImmutAfterInitResult}; use crate::utils::MemoryRegion; use crate::BIT_MASK; @@ -450,6 +450,41 @@ pub enum Mapping<'a> { Level0(&'a mut PTEntry), } +/// A physical address within a page frame +#[derive(Debug)] +pub enum PageFrame { + Size4K(PhysAddr), + Size2M(PhysAddr), + Size1G(PhysAddr), +} + +impl PageFrame { + pub fn address(&self) -> PhysAddr { + match *self { + Self::Size4K(pa) => pa, + Self::Size2M(pa) => pa, + Self::Size1G(pa) => pa, + } + } + + fn size(&self) -> usize { + match self { + Self::Size4K(_) => PAGE_SIZE, + Self::Size2M(_) => PAGE_SIZE_2M, + Self::Size1G(_) => PAGE_SIZE_1G, + } + } + + pub fn start(&self) -> PhysAddr { + let end = self.address().bits() & !(self.size() - 1); + end.into() + } + + pub fn end(&self) -> PhysAddr { + self.start() + self.size() + } +} + /// Page table structure containing a root page with multiple entries. #[repr(C)] #[derive(Default, Debug)] From 789257ea3321e901f57d0d4fe3594772ec9060fa Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Fri, 18 Oct 2024 00:21:02 -0700 Subject: [PATCH 12/13] mm/pagetable: Introduce virt_to_frame() virt_to_frame() not only returns the translated physical address, but also returns the size of the underlying page through PageFrame. Signed-off-by: Peter Fang --- kernel/src/mm/address_space.rs | 15 +++++++++++---- kernel/src/mm/pagetable.rs | 15 +++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/kernel/src/mm/address_space.rs b/kernel/src/mm/address_space.rs index a3005669e..b05d5bc4b 100644 --- a/kernel/src/mm/address_space.rs +++ b/kernel/src/mm/address_space.rs @@ -5,11 +5,9 @@ // Author: Joerg Roedel use crate::address::{PhysAddr, VirtAddr}; +use crate::mm::pagetable::{PageFrame, PageTable}; use crate::utils::immut_after_init::ImmutAfterInitCell; -#[cfg(target_os = "none")] -use crate::mm::pagetable::PageTable; - #[derive(Debug, Copy, Clone)] #[allow(dead_code)] pub struct FixedAddressMappingRange { @@ -67,7 +65,16 @@ pub fn init_kernel_mapping_info( #[cfg(target_os = "none")] pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { - match PageTable::virt_to_phys(vaddr) { + match PageTable::virt_to_frame(vaddr) { + Some(paddr) => paddr.address(), + None => { + panic!("Invalid virtual address {:#018x}", vaddr); + } + } +} + +pub fn virt_to_frame(vaddr: VirtAddr) -> PageFrame { + match PageTable::virt_to_frame(vaddr) { Some(paddr) => paddr, None => { panic!("Invalid virtual address {:#018x}", vaddr); diff --git a/kernel/src/mm/pagetable.rs b/kernel/src/mm/pagetable.rs index a663b37b3..6f3f13f89 100644 --- a/kernel/src/mm/pagetable.rs +++ b/kernel/src/mm/pagetable.rs @@ -643,12 +643,12 @@ impl PageTable { /// Perform a virtual to physical translation using the self-map. /// /// # Parameters - /// - `vaddr': The virtual address to transalte. + /// - `vaddr': The virtual address to translate. /// /// # Returns - /// Some(PhysAddr) if the virtual address is valid. + /// Some(PageFrame) if the virtual address is valid. /// None if the virtual address is not valid. - pub fn virt_to_phys(vaddr: VirtAddr) -> Option { + pub fn virt_to_frame(vaddr: VirtAddr) -> Option { // Calculate the virtual addresses of each level of the paging // hierarchy in the self-map. let pte_addr = Self::get_pte_address(vaddr); @@ -675,7 +675,8 @@ impl PageTable { return None; } if pdpe.huge() { - return Some(pdpe.address() + (usize::from(vaddr) & 0x3FFF_FFFF)); + let pa = pdpe.address() + (usize::from(vaddr) & 0x3FFF_FFFF); + return Some(PageFrame::Size1G(pa)); } let pde = unsafe { PTEntry::read_pte(pde_addr) }; @@ -683,12 +684,14 @@ impl PageTable { return None; } if pde.huge() { - return Some(pde.address() + (usize::from(vaddr) & 0x001F_FFFF)); + let pa = pde.address() + (usize::from(vaddr) & 0x001F_FFFF); + return Some(PageFrame::Size2M(pa)); } let pte = unsafe { PTEntry::read_pte(pte_addr) }; if pte.present() { - Some(pte.address() + (usize::from(vaddr) & 0xFFF)) + let pa = pte.address() + (usize::from(vaddr) & 0xFFF); + Some(PageFrame::Size4K(pa)) } else { None } From a4223742a63da5274b8cb2d5210df0215e2a0b57 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Fri, 18 Oct 2024 00:24:47 -0700 Subject: [PATCH 13/13] platform: tdp: Implement page validation interfaces On TDP platforms, page validation means page acceptance. Implement validate_{physical, virtual}_page_range() using the tdx-tdcall crate for this TDCALL operation. Page invalidation simply means zeroing out the page on TDP platforms. Signed-off-by: Peter Fang --- kernel/src/platform/mod.rs | 2 +- kernel/src/platform/tdp.rs | 43 ++++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/kernel/src/platform/mod.rs b/kernel/src/platform/mod.rs index e9171d451..1a6cd68c4 100644 --- a/kernel/src/platform/mod.rs +++ b/kernel/src/platform/mod.rs @@ -98,7 +98,7 @@ pub trait SvsmPlatform { /// Marks a virtual range of pages as valid or invalid for use as private /// pages. Provided primarily for use in stage2 where validation by - /// physical address cannot e supported. + /// physical address cannot be supported. fn validate_virtual_page_range( &self, region: MemoryRegion, diff --git a/kernel/src/platform/tdp.rs b/kernel/src/platform/tdp.rs index 2bfb1eca4..bb210c14b 100644 --- a/kernel/src/platform/tdp.rs +++ b/kernel/src/platform/tdp.rs @@ -10,13 +10,14 @@ use crate::cpu::cpuid::CpuidResult; use crate::cpu::percpu::PerCpu; use crate::error::SvsmError; use crate::io::IOPort; +use crate::mm::{virt_to_frame, PerCPUPageMappingGuard}; use crate::platform::{PageEncryptionMasks, PageStateChangeOp, PageValidateOp, SvsmPlatform}; use crate::types::PageSize; use crate::utils::immut_after_init::ImmutAfterInitCell; -use crate::utils::MemoryRegion; +use crate::utils::{zero_mem_region, MemoryRegion}; use tdx_tdcall::tdx::{ - tdvmcall_io_read_16, tdvmcall_io_read_32, tdvmcall_io_read_8, tdvmcall_io_write_16, - tdvmcall_io_write_32, tdvmcall_io_write_8, + td_accept_memory, tdvmcall_io_read_16, tdvmcall_io_read_32, tdvmcall_io_read_8, + tdvmcall_io_write_16, tdvmcall_io_write_32, tdvmcall_io_write_8, }; static GHCI_IO_DRIVER: GHCIIOPort = GHCIIOPort::new(); @@ -93,18 +94,42 @@ impl SvsmPlatform for TdpPlatform { fn validate_physical_page_range( &self, - _region: MemoryRegion, - _op: PageValidateOp, + region: MemoryRegion, + op: PageValidateOp, ) -> Result<(), SvsmError> { - Err(SvsmError::Tdx) + match op { + PageValidateOp::Validate => { + td_accept_memory(region.start().into(), region.len().try_into().unwrap()); + } + PageValidateOp::Invalidate => { + let mapping = PerCPUPageMappingGuard::create(region.start(), region.end(), 0)?; + zero_mem_region(mapping.virt_addr(), mapping.virt_addr() + region.len()); + } + } + Ok(()) } fn validate_virtual_page_range( &self, - _region: MemoryRegion, - _op: PageValidateOp, + region: MemoryRegion, + op: PageValidateOp, ) -> Result<(), SvsmError> { - Err(SvsmError::Tdx) + match op { + PageValidateOp::Validate => { + let mut va = region.start(); + while va < region.end() { + let pa = virt_to_frame(va); + let sz = pa.end() - pa.address(); + // td_accept_memory() will take care of alignment + td_accept_memory(pa.address().into(), sz.try_into().unwrap()); + va = va + sz; + } + } + PageValidateOp::Invalidate => { + zero_mem_region(region.start(), region.end()); + } + } + Ok(()) } fn configure_alternate_injection(&mut self, _alt_inj_requested: bool) -> Result<(), SvsmError> {