Skip to content

Commit

Permalink
svsm/paging: Scrub memory before platform-specific invalidation
Browse files Browse the repository at this point in the history
Instead of invalidating memory, TDP platforms only need to zero out its
content before handing it over to the L2 guest. This is not equivalent
to page invalidation because the page remains accepted after zeroing.

Always scrub the memory region prior to performing platform-specific
invalidation (which is a no-op on TDP platforms). This should have no
functional impact on SNP platforms.

To scrub a physical memory region, the following strategies are adopted:

- Add a cap to the mapping size per iteration
- Try using 4K temporary mappings when the mapping size is small enough
  (< 2M) and try using 2M temporary mappings otherwise
- When a mapping guard cannot be created, reduce the mapping size by
  half

Signed-off-by: Peter Fang <[email protected]>
  • Loading branch information
peterfang committed Nov 7, 2024
1 parent 872240c commit f18f8cd
Showing 1 changed file with 56 additions and 3 deletions.
59 changes: 56 additions & 3 deletions kernel/src/svsm_paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ use crate::config::SvsmConfig;
use crate::error::SvsmError;
use crate::igvm_params::IgvmParams;
use crate::mm::pagetable::{PTEntryFlags, PageTable};
use crate::mm::PageBox;
use crate::mm::{PageBox, PerCPUPageMappingGuard};
use crate::platform::{PageStateChangeOp, PageValidateOp, SvsmPlatform};
use crate::types::PageSize;
use crate::utils::MemoryRegion;
use crate::types::{PageSize, PAGE_SHIFT, PAGE_SHIFT_2M, PAGE_SIZE, PAGE_SIZE_2M};
use crate::utils::{align_down, page_align, zero_mem_region, MemoryRegion};
use bootlib::kernel_launch::KernelLaunchInfo;
use core::cmp::min;

struct IgvmParamInfo<'a> {
virt_addr: VirtAddr,
Expand Down Expand Up @@ -94,6 +95,54 @@ pub fn init_page_table(
Ok(pgtable)
}

fn scrub_phys_memory_region(region: MemoryRegion<PhysAddr>) -> Result<(), SvsmError> {
let mut start = region.start();
let mut maxlen_4k = 512 * PAGE_SIZE; // 2M
let mut maxlen_2m = 512 * PAGE_SIZE_2M; // 1G
let region_end_4k = region.end().page_align_up();
let region_end_2m = region.end().align_up(PAGE_SIZE_2M);

while start < region.end() {
let mut map_start = start.page_align();
let (mapping, map_end) = if maxlen_4k == 0 && maxlen_2m == 0 {
// No more space for temporary mappings
return Err(SvsmError::Mem);
} else if (maxlen_4k > 0 && (region_end_4k - map_start) < PAGE_SIZE_2M) || maxlen_2m == 0 {
// Use 4K mappings if
// - The mapping size < a 2M huge page, or
// - There is no space for 2M temporary mappings
let map_end = min(map_start + maxlen_4k, region_end_4k);
match PerCPUPageMappingGuard::create(map_start, map_end, 0) {
Ok(m) => (m, map_end),
Err(SvsmError::Mem) => {
maxlen_4k = page_align((map_end - map_start) >> 1);
continue;
}
Err(e) => return Err(e),
}
} else {
// Use 2M mappings if
// - The mapping size >= a 2M huge page, or
// - There is no space for 4K temporary mappings
map_start = start.align_down(PAGE_SIZE_2M);
let map_end = min(map_start + maxlen_2m, region_end_2m);
match PerCPUPageMappingGuard::create(map_start, map_end, PAGE_SHIFT_2M - PAGE_SHIFT) {
Ok(m) => (m, map_end),
Err(SvsmError::Mem) => {
maxlen_2m = align_down((map_end - map_start) >> 1, PAGE_SIZE_2M);
continue;
}
Err(e) => return Err(e),
}
};
let off = start - map_start;
let len = min(map_end, region.end()) - map_start;
zero_mem_region(mapping.virt_addr() + off, mapping.virt_addr() + len);
start = map_end;
}
Ok(())
}

fn clean_up_boot_memory_region(
platform: &dyn SvsmPlatform,
config: &SvsmConfig<'_>,
Expand All @@ -106,6 +155,10 @@ fn clean_up_boot_memory_region(
);

if !region.is_empty() {
// Some platforms (such as TDP) do not need page invalidation.
// Scrub the memory region first to make sure its content is
// always at least wiped.
scrub_phys_memory_region(region)?;
platform.validate_physical_page_range(region, PageValidateOp::Invalidate)?;

if config.page_state_change_required() {
Expand Down

0 comments on commit f18f8cd

Please sign in to comment.