From b0921c9d115c25755b0fbb42079c246bca54d440 Mon Sep 17 00:00:00 2001 From: Jon Lange Date: Wed, 20 Dec 2023 10:33:16 -0800 Subject: [PATCH] Fix issues with IGVM boot - Move the kernel ELF/fileystem so they do not collide with low memory ROMs - Invalidate the kernel ELF/filesystem memory so it can be reused by OVMF Signed-off-by: Jon Lange --- igvmbld/igvmbld.c | 8 +++--- src/config.rs | 7 +++++ src/svsm.rs | 7 ++--- src/svsm_paging.rs | 64 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 66 insertions(+), 20 deletions(-) diff --git a/igvmbld/igvmbld.c b/igvmbld/igvmbld.c index cee6413bc..a96de1e09 100644 --- a/igvmbld/igvmbld.c +++ b/igvmbld/igvmbld.c @@ -885,9 +885,11 @@ int main(int argc, const char *argv[]) cpuid_page->page_type = IgvmPageType_Cpuid; fill_cpuid_page((SNP_CPUID_PAGE *)cpuid_page->data); - // Construct a data object for the kernel image. The kernel is always - // loaded at 640K. - kernel_data = construct_file_data_object(kernel_filename, 0xA0000); + // Load the kernel data at a base address of 1 MB. + address = 1 << 20; + + // Construct a data object for the kernel. + kernel_data = construct_file_data_object(kernel_filename, address); if (kernel_data == NULL) { return 1; diff --git a/src/config.rs b/src/config.rs index 89c658db5..31e73e7bb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -91,4 +91,11 @@ impl<'a> SvsmConfig<'a> { SvsmConfig::IgvmConfig(igvm_params) => igvm_params.get_fw_regions(), } } + + pub fn invalidate_boot_data(&self) -> bool { + match self { + SvsmConfig::FirmwareConfig(_) => false, + SvsmConfig::IgvmConfig(_) => true, + } + } } diff --git a/src/svsm.rs b/src/svsm.rs index 9b5b94990..bbc0507bc 100755 --- a/src/svsm.rs +++ b/src/svsm.rs @@ -47,7 +47,7 @@ use svsm::sev::secrets_page::{copy_secrets_page, disable_vmpck0, SecretsPage}; use svsm::sev::sev_status_init; use svsm::sev::utils::{rmp_adjust, RMPFlags}; use svsm::svsm_console::SVSMIOPort; -use svsm::svsm_paging::{init_page_table, invalidate_stage2}; +use svsm::svsm_paging::{init_page_table, invalidate_early_boot_memory}; use svsm::task::{create_task, TASK_FLAG_SHARE_PT}; use svsm::types::{PageSize, GUEST_VMPL, PAGE_SIZE}; use svsm::utils::{halt, immut_after_init::ImmutAfterInitCell, zero_mem_region, MemoryRegion}; @@ -440,8 +440,6 @@ pub extern "C" fn svsm_main() { SvsmConfig::FirmwareConfig(FwCfg::new(&CONSOLE_IO)) }; - invalidate_stage2(&config).expect("Failed to invalidate Stage2 memory"); - init_memory_map(&config, &LAUNCH_INFO).expect("Failed to init guest memory map"); initialize_fs(); @@ -449,6 +447,9 @@ pub extern "C" fn svsm_main() { populate_ram_fs(LAUNCH_INFO.kernel_fs_start, LAUNCH_INFO.kernel_fs_end) .expect("Failed to unpack FS archive"); + invalidate_early_boot_memory(&config, launch_info) + .expect("Failed to invalidate early boot memory"); + let cpus = config.load_cpu_info().expect("Failed to load ACPI tables"); let mut nr_cpus = 0; diff --git a/src/svsm_paging.rs b/src/svsm_paging.rs index 10c6c0d09..4f9095faa 100644 --- a/src/svsm_paging.rs +++ b/src/svsm_paging.rs @@ -15,7 +15,8 @@ use crate::mm::pagetable::{set_init_pgtable, PTEntryFlags, PageTable, PageTableR use crate::mm::PerCPUPageMappingGuard; use crate::sev::ghcb::PageStateChangeOp; use crate::sev::{pvalidate, PvalidateOp}; -use crate::types::{PageSize, PAGE_SIZE}; +use crate::types::PageSize; +use crate::utils::MemoryRegion; use bootlib::kernel_launch::KernelLaunchInfo; struct IgvmParamInfo<'a> { @@ -94,29 +95,64 @@ pub fn init_page_table(launch_info: &KernelLaunchInfo, kernel_elf: &elf::Elf64Fi set_init_pgtable(pgtable); } -pub fn invalidate_stage2(config: &SvsmConfig) -> Result<(), SvsmError> { - let pstart = PhysAddr::null(); - let pend = pstart + (640 * 1024); - let mut paddr = pstart; - - // Stage2 memory must be invalidated when already on the SVSM page-table, - // because before that the stage2 page-table is still active, which is in - // stage2 memory, causing invalidation of page-table pages. - while paddr < pend { +fn invalidate_boot_memory_region( + config: &SvsmConfig, + region: MemoryRegion, +) -> Result<(), SvsmError> { + log::info!( + "Invalidating boot region {:018x}-{:018x}", + region.start(), + region.end() + ); + + for paddr in region.iter_pages(PageSize::Regular) { let guard = PerCPUPageMappingGuard::create_4k(paddr)?; let vaddr = guard.virt_addr(); pvalidate(vaddr, PageSize::Regular, PvalidateOp::Invalid)?; - - paddr = paddr + PAGE_SIZE; } - if config.page_state_change_required() { + if config.page_state_change_required() && !region.is_empty() { this_cpu_mut() .ghcb() - .page_state_change(paddr, pend, PageSize::Regular, PageStateChangeOp::PscShared) + .page_state_change( + region.start(), + region.end(), + PageSize::Regular, + PageStateChangeOp::PscShared, + ) .expect("Failed to invalidate Stage2 memory"); } Ok(()) } + +pub fn invalidate_early_boot_memory( + config: &SvsmConfig, + launch_info: &KernelLaunchInfo, +) -> Result<(), SvsmError> { + // Early boot memory must be invalidated after changing to the SVSM page + // page table to avoid invalidating page tables currently in use. Always + // invalidate stage 2 memory, and invalidate the boot data if required. + let stage2_region = MemoryRegion::new(PhysAddr::null(), 640 * 1024); + invalidate_boot_memory_region(config, stage2_region)?; + + if config.invalidate_boot_data() { + let kernel_elf_size = + launch_info.kernel_elf_stage2_virt_end - launch_info.kernel_elf_stage2_virt_start; + let kernel_elf_region = MemoryRegion::new( + PhysAddr::new(launch_info.kernel_elf_stage2_virt_start.try_into().unwrap()), + kernel_elf_size.try_into().unwrap(), + ); + invalidate_boot_memory_region(config, kernel_elf_region)?; + + let kernel_fs_size = launch_info.kernel_fs_end - launch_info.kernel_fs_start; + let kernel_fs_region = MemoryRegion::new( + PhysAddr::new(launch_info.kernel_fs_start.try_into().unwrap()), + kernel_fs_size.try_into().unwrap(), + ); + invalidate_boot_memory_region(config, kernel_fs_region)?; + } + + Ok(()) +}