Skip to content

Commit

Permalink
Permit customization of the guest VMSA based on IGVM parameters
Browse files Browse the repository at this point in the history
Signed-off-by: Jon Lange <jlange@microsoft.com>
  • Loading branch information
msft-jlange committed Dec 25, 2023
1 parent 5f72217 commit ad078ab
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 6 deletions.
39 changes: 37 additions & 2 deletions bootlib/src/igvm_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ pub struct IgvmParamBlock {
/// of the memory map (which is in IGVM format).
pub memory_map_offset: u32,

/// The offset, in bytes, of the guest context, or zero if no guest
/// context is present.
pub guest_context_offset: u32,

/// The guest physical address of the CPUID page.
pub cpuid_page: u32,

Expand Down Expand Up @@ -71,8 +75,6 @@ pub struct IgvmParamBlock {
/// without parsing any metadata.
pub fw_metadata: u32,

_reserved2: u32,

/// The amount of space that must be reserved at the base of the kernel
/// memory region (e.g. for VMSA contents).
pub kernel_reserved_size: u32,
Expand All @@ -83,3 +85,36 @@ pub struct IgvmParamBlock {
/// The guest physical address of the base of the kernel memory region.
pub kernel_base: u64,
}

/// The IGVM context page is a measured page that is used to specify the start
/// context for the guest VMPL. If present, it overrides the processor state
/// initialized at reset.
#[derive(Copy, Debug, Clone)]
#[repr(C, packed)]
pub struct IgvmGuestContext {
pub cr0: u64,
pub cr3: u64,
pub cr4: u64,
pub efer: u64,
pub gdt_base: u64,
pub gdt_limit: u32,
pub code_selector: u16,
pub data_selector: u16,
pub rip: u64,
pub rax: u64,
pub rcx: u64,
pub rdx: u64,
pub rbx: u64,
pub rsp: u64,
pub rbp: u64,
pub rsi: u64,
pub rdi: u64,
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
}
2 changes: 1 addition & 1 deletion igvmbld/igvmbld.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ typedef struct {
uint32_t param_area_size;
uint32_t param_page_offset;
uint32_t memory_map_offset;
uint32_t guest_context_offset;
uint32_t cpuid_page;
uint32_t secrets_page;
uint16_t debug_serial_port;
Expand All @@ -33,7 +34,6 @@ typedef struct {
uint32_t fw_start;
uint32_t fw_size;
uint32_t fw_metadata;
uint32_t _reserved2;
uint32_t kernel_reserved_size;
uint32_t kernel_size;
uint64_t kernel_base;
Expand Down
8 changes: 8 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::mm::{PAGE_SIZE, SIZE_1G};
use crate::serial::SERIAL_PORT;
use crate::utils::MemoryRegion;
use alloc::vec::Vec;
use cpuarch::vmsa::VMSA;

fn check_ovmf_regions(
flash_regions: &[MemoryRegion<PhysAddr>],
Expand Down Expand Up @@ -154,4 +155,11 @@ impl<'a> SvsmConfig<'a> {
SvsmConfig::IgvmConfig(_) => true,
}
}

pub fn initialize_guest_vmsa(&self, vmsa: &mut VMSA) {
match self {
SvsmConfig::FirmwareConfig(_) => (),
SvsmConfig::IgvmConfig(igvm_params) => igvm_params.initialize_guest_vmsa(vmsa),
}
}
}
66 changes: 65 additions & 1 deletion src/igvm_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate alloc;

use crate::acpi::tables::ACPICPUInfo;
use crate::address::{PhysAddr, VirtAddr};
use crate::cpu::efer::EFERFlags;
use crate::error::SvsmError;
use crate::error::SvsmError::Firmware;
use crate::mm::{PerCPUPageMappingGuard, PAGE_SIZE};
Expand All @@ -16,8 +17,9 @@ use crate::sev::{rmp_adjust, RMPFlags};
use crate::types::PageSize;
use crate::utils::MemoryRegion;
use alloc::vec::Vec;
use cpuarch::vmsa::VMSA;

use bootlib::igvm_params::{IgvmParamBlock, IgvmParamPage};
use bootlib::igvm_params::{IgvmGuestContext, IgvmParamBlock, IgvmParamPage};
use core::mem::size_of;
use igvm_defs::{IgvmEnvironmentInfo, MemoryMapEntryType, IGVM_VHS_MEMORY_MAP_ENTRY};

Expand All @@ -34,6 +36,7 @@ pub struct IgvmParams<'a> {
igvm_param_block: &'a IgvmParamBlock,
igvm_param_page: &'a IgvmParamPage,
igvm_memory_map: &'a IgvmMemoryMap,
igvm_guest_context_address: VirtAddr,
}

impl IgvmParams<'_> {
Expand All @@ -43,11 +46,17 @@ impl IgvmParams<'_> {
let param_page = unsafe { &*param_page_address.as_ptr::<IgvmParamPage>() };
let memory_map_address = addr + param_block.memory_map_offset.try_into().unwrap();
let memory_map = unsafe { &*memory_map_address.as_ptr::<IgvmMemoryMap>() };
let guest_context_address = if param_block.guest_context_offset != 0 {
addr + param_block.guest_context_offset.try_into().unwrap()
} else {
VirtAddr::null()
};

Self {
igvm_param_block: param_block,
igvm_param_page: param_page,
igvm_memory_map: memory_map,
igvm_guest_context_address: guest_context_address,
}
}

Expand Down Expand Up @@ -202,4 +211,59 @@ impl IgvmParams<'_> {
pub fn fw_in_low_memory(&self) -> bool {
self.igvm_param_block.fw_in_low_memory != 0
}

pub fn initialize_guest_vmsa(&self, vmsa: &mut VMSA) {
if self.igvm_param_block.guest_context_offset != 0 {
let guest_context =
unsafe { &*self.igvm_guest_context_address.as_ptr::<IgvmGuestContext>() };

// Copy the specified registers into the VMSA.
vmsa.cr0 = guest_context.cr0;
vmsa.cr3 = guest_context.cr3;
vmsa.cr4 = guest_context.cr4;
vmsa.efer = guest_context.efer;
vmsa.rip = guest_context.rip;
vmsa.rax = guest_context.rax;
vmsa.rcx = guest_context.rcx;
vmsa.rdx = guest_context.rdx;
vmsa.rbx = guest_context.rbx;
vmsa.rsp = guest_context.rsp;
vmsa.rbp = guest_context.rbp;
vmsa.rsi = guest_context.rsi;
vmsa.rdi = guest_context.rdi;
vmsa.r8 = guest_context.r8;
vmsa.r9 = guest_context.r9;
vmsa.r10 = guest_context.r10;
vmsa.r11 = guest_context.r11;
vmsa.r12 = guest_context.r12;
vmsa.r13 = guest_context.r13;
vmsa.r14 = guest_context.r14;
vmsa.r15 = guest_context.r15;
vmsa.gdt.base = guest_context.gdt_base;
vmsa.gdt.limit = guest_context.gdt_limit;
vmsa.cs.selector = guest_context.code_selector;

// Set the code segment attributes based on EFER.LMA.
let efer_lma = EFERFlags::LMA;
if (vmsa.efer & efer_lma.bits()) != 0 {
vmsa.cs.flags = 0xA9B;
} else {
vmsa.cs.flags = 0xC9B;
vmsa.cs.limit = 0xFFFFFFFF;
}

let efer_svme = EFERFlags::SVME;
vmsa.efer &= !efer_svme.bits();

// Modify the data segment attributes to be compatible with
// protected mode.
vmsa.ds.selector = guest_context.data_selector;
vmsa.ds.flags = 0xA93;
vmsa.ds.limit = 0xFFFFFFFF;
vmsa.ss = vmsa.ds;
vmsa.es = vmsa.ds;
vmsa.fs = vmsa.ds;
vmsa.gs = vmsa.ds;
}
}
}
6 changes: 4 additions & 2 deletions src/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,12 @@ fn prepare_fw_launch(fw_metadata: Option<&SevFWMetaData>) -> Result<(), SvsmErro
Ok(())
}

fn launch_fw() -> Result<(), SvsmError> {
fn launch_fw(config: &SvsmConfig) -> Result<(), SvsmError> {
let vmsa_pa = this_cpu_mut().guest_vmsa_ref().vmsa_phys().unwrap();
let vmsa = this_cpu_mut().guest_vmsa();

config.initialize_guest_vmsa(vmsa);

log::info!("VMSA PA: {:#x}", vmsa_pa);

let sev_features = vmsa.sev_features;
Expand Down Expand Up @@ -461,7 +463,7 @@ pub extern "C" fn svsm_main() {
virt_log_usage();

if config.should_launch_fw() {
if let Err(e) = launch_fw() {
if let Err(e) = launch_fw(&config) {
panic!("Failed to launch FW: {:#?}", e);
}
}
Expand Down

0 comments on commit ad078ab

Please sign in to comment.