Skip to content

Commit

Permalink
svsm: Use fw metadata from IGVM config instead of from OVMF
Browse files Browse the repository at this point in the history
When using an IGVM based configuration, currently the firmware metadata
can be provided either in the IGVM configuration itself or can be parsed
from the OVMF image. However, there is no reason for SVSM to parse the
OVMF metadata as this can be done by the IGVM builder and populated into
the IGVM configuration.

This patch removes the logic to parse OVMF metadata when using IGVM
configuration and applies the required extra fields from the IGMV
configuration.

Signed-off-by: Roy Hopkins <roy.hopkins@suse.com>
  • Loading branch information
roy-hopkins committed Jan 4, 2024
1 parent 658f023 commit d8452dd
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 53 deletions.
26 changes: 14 additions & 12 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@

extern crate alloc;

use core::slice;

use crate::acpi::tables::{load_acpi_cpu_info, ACPICPUInfo};
use crate::address::PhysAddr;
use crate::error::SvsmError;
use crate::fw_cfg::FwCfg;
use crate::fw_meta::SevFWMetaData;
use crate::fw_meta::{parse_fw_meta_data, SevFWMetaData};
use crate::igvm_params::IgvmParams;
use crate::mm::{PAGE_SIZE, SIZE_1G};
use crate::mm::{PerCPUPageMappingGuard, PAGE_SIZE, SIZE_1G};
use crate::serial::SERIAL_PORT;
use crate::utils::MemoryRegion;
use alloc::vec::Vec;
Expand Down Expand Up @@ -74,19 +76,19 @@ impl<'a> SvsmConfig<'a> {
}
}

pub fn get_fw_metadata_address(&self) -> Option<PhysAddr> {
pub fn get_fw_metadata(&self) -> Option<SevFWMetaData> {
match self {
SvsmConfig::FirmwareConfig(_) => {
// The metadata location always starts at 32 bytes below 4GB
Some(PhysAddr::from((4 * SIZE_1G) - PAGE_SIZE))
// Map the metadata location which is defined by the firmware config
let guard =
PerCPUPageMappingGuard::create_4k(PhysAddr::from(4 * SIZE_1G - PAGE_SIZE))
.expect("Failed to map FW metadata page");
let vstart = guard.virt_addr().as_ptr::<u8>();
// Safety: we just mapped a page, so the size must hold. The type
// of the slice elements is `u8` so there are no alignment requirements.
let metadata = unsafe { slice::from_raw_parts(vstart, PAGE_SIZE) };
Some(parse_fw_meta_data(metadata).expect("Failed to parse FW SEV meta-data"))
}
SvsmConfig::IgvmConfig(igvm_params) => igvm_params.get_fw_metadata_address(),
}
}

pub fn get_fw_metadata(&self) -> Option<SevFWMetaData> {
match self {
SvsmConfig::FirmwareConfig(_) => None,
SvsmConfig::IgvmConfig(igvm_params) => igvm_params.get_fw_metadata(),
}
}
Expand Down
41 changes: 31 additions & 10 deletions src/igvm_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,6 @@ impl IgvmParams<'_> {
self.igvm_param_block.debug_serial_port
}

pub fn get_fw_metadata_address(&self) -> Option<PhysAddr> {
if !self.should_launch_fw() || self.igvm_param_block.firmware.metadata == 0 {
None
} else {
Some(PhysAddr::from(
self.igvm_param_block.firmware.metadata as u64,
))
}
}

pub fn get_fw_metadata(&self) -> Option<SevFWMetaData> {
if !self.should_launch_fw() {
None
Expand All @@ -174,6 +164,37 @@ impl IgvmParams<'_> {
));
}

if self.igvm_param_block.firmware.cpuid_page != 0 {
fw_meta.cpuid_page = Some(PhysAddr::new(
self.igvm_param_block
.firmware
.cpuid_page
.try_into()
.unwrap(),
));
}

for preval in 0..self.igvm_param_block.firmware.prevalidated_count as usize {
let base = PhysAddr::new(
self.igvm_param_block.firmware.prevalidated[preval]
.base
.try_into()
.unwrap(),
);
let size = self.igvm_param_block.firmware.prevalidated[preval].size as usize;
fw_meta.add_valid_mem(base, size);
}

if self.igvm_param_block.firmware.reset_addr != 0 {
fw_meta.reset_ip = Some(PhysAddr::new(
self.igvm_param_block
.firmware
.reset_addr
.try_into()
.unwrap(),
));
}

Some(fw_meta)
}
}
Expand Down
33 changes: 2 additions & 31 deletions src/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

extern crate alloc;

use svsm::fw_meta::{parse_fw_meta_data, print_fw_meta, validate_fw_memory, SevFWMetaData};
use svsm::fw_meta::{print_fw_meta, validate_fw_memory, SevFWMetaData};

use bootlib::kernel_launch::KernelLaunchInfo;
use core::arch::global_asm;
Expand Down Expand Up @@ -308,35 +308,6 @@ fn mapping_info_init(launch_info: &KernelLaunchInfo) {
);
}

fn map_and_parse_fw_meta(fw_metadata_phys: PhysAddr) -> Result<SevFWMetaData, SvsmError> {
// Map the metadata location which is defined by the firmware config
let guard = PerCPUPageMappingGuard::create_4k(fw_metadata_phys)?;
let vstart = guard.virt_addr().as_ptr::<u8>();
// Safety: we just mapped a page, so the size must hold. The type
// of the slice elements is `u8` so there are no alignment requirements.
let metadata = unsafe { slice::from_raw_parts(vstart, PAGE_SIZE) };
parse_fw_meta_data(metadata)
}

fn obtain_fw_metadata(config: &SvsmConfig) -> Option<SevFWMetaData> {
// First attempt to obtain the physical address of the firmware metadata
// descriptor.
match config.get_fw_metadata_address() {
Some(fw_metadata_phys) => {
// There is a firmware metadata descriptor, so parse it to obtain
// the firmware metadata.
let fw_meta = map_and_parse_fw_meta(fw_metadata_phys)
.unwrap_or_else(|e| panic!("Failed to parse FW SEV meta-data: {:#?}", e));
Some(fw_meta)
}
None => {
// There is no firmware metadata descriptor, so see if the
// configuration supplies the metadata directly.
config.get_fw_metadata()
}
}
}

#[no_mangle]
pub extern "C" fn svsm_start(li: &KernelLaunchInfo, vb_addr: usize) {
let launch_info: KernelLaunchInfo = *li;
Expand Down Expand Up @@ -481,7 +452,7 @@ pub extern "C" fn svsm_main() {

start_secondary_cpus(&cpus);

let fw_metadata = obtain_fw_metadata(&config);
let fw_metadata = config.get_fw_metadata();
if let Some(ref fw_meta) = fw_metadata {
print_fw_meta(fw_meta);

Expand Down

0 comments on commit d8452dd

Please sign in to comment.