Skip to content

Commit

Permalink
Merge pull request #195 from msft-jlange/igvm_bootmem
Browse files Browse the repository at this point in the history
Fix issues with IGVM boot
joergroedel authored Dec 22, 2023

Verified

This commit was signed with the committer’s verified signature.
Moritzoni Moritz
2 parents 6db2a65 + b0921c9 commit c936b63
Showing 4 changed files with 66 additions and 20 deletions.
8 changes: 5 additions & 3 deletions igvmbld/igvmbld.c
Original file line number Diff line number Diff line change
@@ -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;
7 changes: 7 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
7 changes: 4 additions & 3 deletions src/svsm.rs
Original file line number Diff line number Diff line change
@@ -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};
@@ -439,15 +439,16 @@ 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();

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;

64 changes: 50 additions & 14 deletions src/svsm_paging.rs
Original file line number Diff line number Diff line change
@@ -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<PhysAddr>,
) -> 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(())
}

0 comments on commit c936b63

Please sign in to comment.