Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stage2: Use IGVM memory map to resize SVSM kernel #590

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ bitflags = "2.4"
clap = { version = "4.4.14", default-features = false }
gdbstub = { version = "0.6.6", default-features = false }
gdbstub_arch = { version = "0.2.4" }
igvm = { version = "0.3.2", default-features = false }
igvm_defs = { version = "0.3.2", default-features = false }
igvm = { version = "0.3.4", default-features = false }
igvm_defs = { version = "0.3.4", default-features = false }
intrusive-collections = "0.9.6"
libfuzzer-sys = "0.4"
log = "0.4.17"
Expand Down
13 changes: 10 additions & 3 deletions bootlib/src/igvm_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,19 @@ pub struct IgvmParamBlock {
/// memory region (e.g. for VMSA contents).
pub kernel_reserved_size: u32,

/// The number of bytes in the kernel memory region.
pub kernel_size: u32,

/// The guest physical address of the base of the kernel memory region.
pub kernel_base: u64,

/// The minimum size to allocate for the kernel in bytes. If the hypervisor supplies a memory
/// region in the memory map that starts at kernel_base and is larger, that size will be used
/// instead.
pub kernel_min_size: u32,

/// The maximum size to allocate for the kernel in bytes. If the hypervisor supplies a memory
/// region in the memory map that starts at kernel_base and is larger, this maximum size will
/// be used instead.
pub kernel_max_size: u32,

/// The value of vTOM used by the guest, or zero if not used.
pub vtom: u64,
}
Expand Down
13 changes: 8 additions & 5 deletions igvmbuilder/src/gpa_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ pub struct GpaMap {
pub general_params: GpaRange,
pub memory_map: GpaRange,
pub guest_context: GpaRange,
// The kernel region represents the maximum allowable size. The hypervisor may request that it
// be smaller to save memory on smaller machine shapes. However, the entire region should not
// overlap any other regions.
pub kernel: GpaRange,
pub vmsa: GpaRange,
pub init_page_tables: GpaRange,
Expand Down Expand Up @@ -116,19 +119,19 @@ impl GpaMap {
let kernel_elf = GpaRange::new(kernel_address, kernel_elf_len as u64)?;
let kernel_fs = GpaRange::new(kernel_elf.get_end(), kernel_fs_len as u64)?;

// Calculate the kernel size and base.
// Choose the kernel base and maximum size.
let kernel = match options.hypervisor {
Hypervisor::Qemu => {
// Place the kernel area at 512 GB with a size of 16 MB.
// Place the kernel area at 512 GB with a maximum size of 16 MB.
GpaRange::new(0x0000008000000000, 0x01000000)?
}
Hypervisor::HyperV => {
// Place the kernel area at 64 MB with a size of 16 MB.
// Place the kernel area at 64 MB with a maximum size of 16 MB.
GpaRange::new(0x04000000, 0x01000000)?
}
Hypervisor::Vanadium => {
// Place the kernel area at 8TiB-2GiB with a size of 16 MB.
GpaRange::new(0x7ff80000000, 0x01000000)?
// Place the kernel area at 8TiB-2GiB with a maximum size of 2 GiB.
GpaRange::new(0x7ff80000000, 0x80000000)?
}
};

Expand Down
8 changes: 5 additions & 3 deletions igvmbuilder/src/igvm_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ impl IgvmBuilder {
fn create_param_block(&self) -> Result<IgvmParamBlock, Box<dyn Error>> {
let param_page_offset = PAGE_SIZE_4K as u32;
let memory_map_offset = param_page_offset + PAGE_SIZE_4K as u32;
let kernel_min_size = 0x1000000; // 16 MiB
let (guest_context_offset, param_area_size) = if self.gpa_map.guest_context.get_size() == 0
{
(0, memory_map_offset + PAGE_SIZE_4K as u32)
Expand Down Expand Up @@ -237,8 +238,9 @@ impl IgvmBuilder {
stage1_size: self.gpa_map.stage1_image.get_size() as u32,
stage1_base: self.gpa_map.stage1_image.get_start(),
kernel_reserved_size: PAGE_SIZE_4K as u32, // Reserved for VMSA
kernel_size: self.gpa_map.kernel.get_size() as u32,
kernel_base: self.gpa_map.kernel.get_start(),
kernel_min_size,
kernel_max_size: self.gpa_map.kernel.get_size() as u32,
vtom,
use_alternate_injection: u8::from(self.options.alt_injection),
is_qemu,
Expand Down Expand Up @@ -328,7 +330,7 @@ impl IgvmBuilder {
self.directives.push(IgvmDirectiveHeader::RequiredMemory {
gpa: param_block.kernel_base,
compatibility_mask: COMPATIBILITY_MASK.get() & !VSM_COMPATIBILITY_MASK,
number_of_bytes: param_block.kernel_size,
number_of_bytes: param_block.kernel_min_size,
vtl2_protectable: false,
});
}
Expand All @@ -337,7 +339,7 @@ impl IgvmBuilder {
self.directives.push(IgvmDirectiveHeader::RequiredMemory {
gpa: param_block.kernel_base,
compatibility_mask: VSM_COMPATIBILITY_MASK,
number_of_bytes: param_block.kernel_size,
number_of_bytes: param_block.kernel_min_size,
vtl2_protectable: true,
});
}
Expand Down
32 changes: 29 additions & 3 deletions kernel/src/igvm_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
extern crate alloc;

use crate::acpi::tables::ACPICPUInfo;
use crate::address::{PhysAddr, VirtAddr};
use crate::address::{Address, PhysAddr, VirtAddr};
use crate::cpu::efer::EFERFlags;
use crate::error::SvsmError;
use crate::mm::{GuestPtr, PerCPUPageMappingGuard, PAGE_SIZE};
Expand Down Expand Up @@ -76,8 +76,34 @@ impl IgvmParams<'_> {

pub fn find_kernel_region(&self) -> Result<MemoryRegion<PhysAddr>, SvsmError> {
let kernel_base = PhysAddr::from(self.igvm_param_block.kernel_base);
let kernel_size: usize = self.igvm_param_block.kernel_size.try_into().unwrap();
Ok(MemoryRegion::<PhysAddr>::new(kernel_base, kernel_size))
let mut kernel_size = self.igvm_param_block.kernel_min_size;

// Check the untrusted hypervisor-provided memory map to see if the size of the kernel
// should be adjusted. The base location and mimimum and maximum size specified by the
// measured igvm_param_block are still respected to ensure a malicious memory map cannot
// cause the SVSM kernel to overlap anything important or be so small it causes weird
// failures. But if the hypervisor gives a memory map entry of type HIDDEN that starts at
// kernel_start, use the size of that entry as a guide. This allows the hypervisor to
// adjust the size of the SVSM kernel to what it expects will be needed based on the
// machine shape.
if let Some(memory_map_region) = self.igvm_memory_map.memory_map.iter().find(|region| {
region.entry_type == MemoryMapEntryType::HIDDEN
&& region.starting_gpa_page_number.try_into() == Ok(kernel_base.pfn())
}) {
let region_size_bytes = memory_map_region
.number_of_pages
.try_into()
.unwrap_or(u32::MAX)
.saturating_mul(PAGE_SIZE as u32);
kernel_size = region_size_bytes.clamp(
self.igvm_param_block.kernel_min_size,
self.igvm_param_block.kernel_max_size,
);
}
Ok(MemoryRegion::<PhysAddr>::new(
kernel_base,
kernel_size.try_into().unwrap(),
))
}

pub fn reserved_kernel_area_size(&self) -> usize {
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/stage2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ pub extern "C" fn stage2_main(launch_info: &Stage2LaunchInfo) {
.find_kernel_region()
.expect("Failed to find memory region for SVSM kernel");

log::info!("SVSM memory region: {kernel_region:?}");

init_valid_bitmap_alloc(kernel_region).expect("Failed to allocate valid-bitmap");

// The physical memory region we've loaded so far
Expand Down
Loading