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

openhcl/loader: move snp specific pages to new vtl2 reserved region #304

Merged
merged 3 commits into from
Nov 13, 2024
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
36 changes: 36 additions & 0 deletions openhcl/bootloader_fdt_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ pub struct ParsedBootDtInfo {
/// The ranges config regions are stored at.
#[inspect(iter_by_index)]
pub config_ranges: Vec<MemoryRange>,
/// The VTL2 reserved range.
pub vtl2_reserved_range: MemoryRange,
/// The ranges that were accepted at load time by the host on behalf of the
/// guest.
#[inspect(iter_by_index)]
Expand Down Expand Up @@ -201,6 +203,7 @@ struct OpenhclInfo {
config_ranges: Vec<MemoryRange>,
partition_memory_map: Vec<AddressRange>,
accepted_memory: Vec<MemoryRange>,
vtl2_reserved_range: MemoryRange,
vtl0_alias_map: Option<u64>,
memory_allocation_mode: MemoryAllocationMode,
isolation: IsolationType,
Expand Down Expand Up @@ -352,6 +355,25 @@ fn parse_openhcl(node: &Node<'_>) -> anyhow::Result<OpenhclInfo> {
})
.collect();

// Report the reserved range. There should only be one.
let vtl2_reserved_range = {
let mut reserved_range_iter = memory.iter().filter_map(|entry| {
if entry.vtl_usage() == MemoryVtlType::VTL2_RESERVED {
Some(*entry.range())
} else {
None
}
});

let reserved_range = reserved_range_iter.next().unwrap_or(MemoryRange::EMPTY);

if reserved_range_iter.next().is_some() {
bail!("multiple VTL2 reserved ranges found");
}

reserved_range
};

let vtl0_alias_map = try_find_property(node, "vtl0-alias-map")
.map(|prop| prop.read_u64(0).map_err(err_to_owned))
.transpose()
Expand All @@ -374,6 +396,7 @@ fn parse_openhcl(node: &Node<'_>) -> anyhow::Result<OpenhclInfo> {
config_ranges,
partition_memory_map: memory,
accepted_memory,
vtl2_reserved_range,
vtl0_alias_map,
memory_allocation_mode,
isolation,
Expand Down Expand Up @@ -469,6 +492,7 @@ impl ParsedBootDtInfo {
let mut vtl0_alias_map = None;
let mut memory_allocation_mode = MemoryAllocationMode::Host;
let mut isolation = IsolationType::None;
let mut vtl2_reserved_range = MemoryRange::EMPTY;

let parser = Parser::new(raw)
.map_err(err_to_owned)
Expand Down Expand Up @@ -497,6 +521,7 @@ impl ParsedBootDtInfo {
vtl0_mmio: n_vtl0_mmio,
config_ranges: n_config_ranges,
partition_memory_map: n_partition_memory_map,
vtl2_reserved_range: n_vtl2_reserved_range,
accepted_memory: n_accepted_memory,
vtl0_alias_map: n_vtl0_alias_map,
memory_allocation_mode: n_memory_allocation_mode,
Expand All @@ -509,6 +534,7 @@ impl ParsedBootDtInfo {
vtl0_alias_map = n_vtl0_alias_map;
memory_allocation_mode = n_memory_allocation_mode;
isolation = n_isolation;
vtl2_reserved_range = n_vtl2_reserved_range;
}

_ if child.name.starts_with("memory@") => {
Expand Down Expand Up @@ -540,6 +566,7 @@ impl ParsedBootDtInfo {
gic,
memory_allocation_mode,
isolation,
vtl2_reserved_range,
})
}
}
Expand Down Expand Up @@ -854,6 +881,14 @@ mod tests {
vtl_usage: MemoryVtlType::VTL2_CONFIG,
igvm_type: MemoryMapEntryType::VTL2_PROTECTABLE,
}),
AddressRange::Memory(Memory {
range: MemoryRangeWithNode {
range: MemoryRange::new(0x40000..0x50000),
vnode: 1,
},
vtl_usage: MemoryVtlType::VTL2_RESERVED,
igvm_type: MemoryMapEntryType::VTL2_PROTECTABLE,
}),
AddressRange::Memory(Memory {
range: MemoryRangeWithNode {
range: MemoryRange::new(0x1000000..0x2000000),
Expand Down Expand Up @@ -890,6 +925,7 @@ mod tests {
mmio_size: Some(0x2000),
},
isolation: IsolationType::Vbs,
vtl2_reserved_range: MemoryRange::new(0x40000..0x50000),
};

let dt = build_dt(&orig_info).unwrap();
Expand Down
1 change: 1 addition & 0 deletions openhcl/openhcl_boot/src/dt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ pub fn write_dt(
ReservedMemoryType::Vtl2Config => MemoryVtlType::VTL2_CONFIG,
ReservedMemoryType::SidecarImage => MemoryVtlType::VTL2_SIDECAR_IMAGE,
ReservedMemoryType::SidecarNode => MemoryVtlType::VTL2_SIDECAR_NODE,
ReservedMemoryType::Vtl2Reserved => MemoryVtlType::VTL2_RESERVED,
},
)
}),
Expand Down
5 changes: 5 additions & 0 deletions openhcl/openhcl_boot/src/host_params/dt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ impl PartitionInfo {
vtl2_ram: _,
vtl2_full_config_region: vtl2_config_region,
vtl2_config_region_reclaim: vtl2_config_region_reclaim_struct,
vtl2_reserved_region,
partition_ram: _,
isolation,
bsp_reg,
Expand All @@ -466,6 +467,10 @@ impl PartitionInfo {
);
*vtl2_config_region_reclaim_struct = vtl2_config_region_reclaim;
assert!(vtl2_config_region.contains(&vtl2_config_region_reclaim));
*vtl2_reserved_region = MemoryRange::new(
params.vtl2_reserved_region_start
..(params.vtl2_reserved_region_start + params.vtl2_reserved_region_size),
);
*bsp_reg = parsed.boot_cpuid_phys;
cpus.extend(parsed.cpus.iter().copied());
*com3_serial = parsed.com3_serial;
Expand Down
6 changes: 5 additions & 1 deletion openhcl/openhcl_boot/src/host_params/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ pub struct PartitionInfo {
/// Additional ram that can be reclaimed from the parameter region. Today,
/// this is the whole device tree provided by the host.
pub vtl2_config_region_reclaim: MemoryRange,
/// The full memory map provided by the host.
/// The vtl2 reserved region, that is reserved to both the kernel and
/// usermode.
pub vtl2_reserved_region: MemoryRange,
/// The full memory map provided by the host.
pub partition_ram: ArrayVec<MemoryEntry, MAX_PARTITION_RAM_RANGES>,
/// The partiton's isolation type.
pub isolation: IsolationType,
Expand Down Expand Up @@ -87,6 +90,7 @@ impl PartitionInfo {
vtl2_ram: ArrayVec::new_const(),
vtl2_full_config_region: MemoryRange::EMPTY,
vtl2_config_region_reclaim: MemoryRange::EMPTY,
vtl2_reserved_region: MemoryRange::EMPTY,
partition_ram: ArrayVec::new_const(),
isolation: IsolationType::None,
bsp_reg: 0,
Expand Down
19 changes: 15 additions & 4 deletions openhcl/openhcl_boot/src/host_params/shim_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ pub struct ShimParams {
pub parameter_region_start: u64,
/// The size of the parameter region.
pub parameter_region_size: u64,
/// The base address of the VTL2 reserved region.
pub vtl2_reserved_region_start: u64,
/// The size of the VTL2 reserved region.
pub vtl2_reserved_region_size: u64,
/// Isolation type supported by the boot shim.
pub isolation_type: IsolationType,
pub sidecar_entry_address: u64,
Expand All @@ -120,6 +124,8 @@ impl ShimParams {
memory_size,
parameter_region_offset,
parameter_region_size,
vtl2_reserved_region_offset,
vtl2_reserved_region_size,
sidecar_offset,
sidecar_size,
sidecar_entry_offset,
Expand Down Expand Up @@ -148,6 +154,9 @@ impl ShimParams {
memory_size,
parameter_region_start: shim_base_address.wrapping_add_signed(parameter_region_offset),
parameter_region_size,
vtl2_reserved_region_start: shim_base_address
.wrapping_add_signed(vtl2_reserved_region_offset),
vtl2_reserved_region_size,
isolation_type,
sidecar_entry_address: shim_base_address.wrapping_add_signed(sidecar_entry_offset),
sidecar_base: shim_base_address.wrapping_add_signed(sidecar_offset),
Expand All @@ -163,15 +172,17 @@ impl ShimParams {
/// Get the base address of the secrets page.
#[cfg(target_arch = "x86_64")]
pub fn secrets_start(&self) -> u64 {
self.parameter_region_start
+ loader_defs::paravisor::PARAVISOR_CONFIG_SECRETS_PAGE_INDEX * hvdef::HV_PAGE_SIZE
self.vtl2_reserved_region_start
+ loader_defs::paravisor::PARAVISOR_RESERVED_VTL2_SNP_SECRETS_PAGE_INDEX
* hvdef::HV_PAGE_SIZE
}

/// Get the size of the CPUID page.
#[cfg(target_arch = "x86_64")]
pub fn cpuid_start(&self) -> u64 {
self.parameter_region_start
+ loader_defs::paravisor::PARAVISOR_CONFIG_CPUID_PAGE_INDEX * hvdef::HV_PAGE_SIZE
self.vtl2_reserved_region_start
+ loader_defs::paravisor::PARAVISOR_RESERVED_VTL2_SNP_CPUID_PAGE_INDEX
* hvdef::HV_PAGE_SIZE
}

/// Get the base address of the host provided device tree.
Expand Down
11 changes: 11 additions & 0 deletions openhcl/openhcl_boot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ pub const MAX_RESERVED_MEM_RANGES: usize = 3 + sidecar_defs::MAX_NODES;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum ReservedMemoryType {
Vtl2Config,
Vtl2Reserved,
SidecarImage,
SidecarNode,
}
Expand All @@ -322,6 +323,15 @@ fn reserved_memory_regions(
)
}));
}

// Add the VTL2 reserved region, if it exists.
if !partition_info.vtl2_reserved_region.is_empty() {
reserved.push((
partition_info.vtl2_reserved_region,
ReservedMemoryType::Vtl2Reserved,
));
}

reserved
.as_mut()
.sort_unstable_by_key(|(r, _typ)| r.start());
Expand Down Expand Up @@ -855,6 +865,7 @@ mod test {
vtl2_ram: ArrayVec::new(),
vtl2_full_config_region: MemoryRange::EMPTY,
vtl2_config_region_reclaim: MemoryRange::EMPTY,
vtl2_reserved_region: MemoryRange::EMPTY,
partition_ram: ArrayVec::new(),
isolation: IsolationType::None,
bsp_reg: cpus[0].reg as u32,
Expand Down
63 changes: 36 additions & 27 deletions openhcl/underhill_core/src/loader/vtl2_config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ use bootloader_fdt_parser::ParsedBootDtInfo;
use hvdef::HV_PAGE_SIZE;
use inspect::Inspect;
use loader_defs::paravisor::ParavisorMeasuredVtl2Config;
use loader_defs::paravisor::PARAVISOR_CONFIG_CPUID_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_CONFIG_CPUID_SIZE_PAGES;
use loader_defs::paravisor::PARAVISOR_CONFIG_PPTT_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_CONFIG_SECRETS_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_CONFIG_SECRETS_SIZE_PAGES;
use loader_defs::paravisor::PARAVISOR_CONFIG_SLIT_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_MEASURED_VTL2_CONFIG_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_RESERVED_VTL2_SNP_CPUID_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_RESERVED_VTL2_SNP_CPUID_SIZE_PAGES;
use loader_defs::paravisor::PARAVISOR_RESERVED_VTL2_SNP_SECRETS_PAGE_INDEX;
use loader_defs::paravisor::PARAVISOR_RESERVED_VTL2_SNP_SECRETS_SIZE_PAGES;
use memory_range::MemoryRange;
use sparse_mmap::SparseMapping;
use vm_topology::memory::MemoryRangeWithNode;
Expand Down Expand Up @@ -88,16 +88,17 @@ impl MeasuredVtl2Info {
}

#[derive(Debug)]
/// Map of the portion of memory that contains the VTL2 parameters.
/// Map of the portion of memory that contains the VTL2 parameters to read.
///
/// On drop, this mapping zeroes out the specified config ranges.
/// If configured, on drop this mapping zeroes out the specified config ranges.
struct Vtl2ParamsMap<'a> {
mapping: SparseMapping,
zero_on_drop: bool,
ranges: &'a [MemoryRange],
}

impl<'a> Vtl2ParamsMap<'a> {
fn new(config_ranges: &'a [MemoryRange]) -> anyhow::Result<Self> {
fn new(config_ranges: &'a [MemoryRange], zero_on_drop: bool) -> anyhow::Result<Self> {
// No overlaps.
// TODO: Move this check to host_fdt_parser?
if let Some((l, r)) = config_ranges
Expand All @@ -121,7 +122,7 @@ impl<'a> Vtl2ParamsMap<'a> {

let dev_mem = fs_err::OpenOptions::new()
.read(true)
.write(true)
.write(zero_on_drop)
.open("/dev/mem")?;
for range in config_ranges {
mapping
Expand All @@ -130,14 +131,15 @@ impl<'a> Vtl2ParamsMap<'a> {
range.len() as usize,
dev_mem.file(),
range.start(),
true,
zero_on_drop,
)
.context("failed to memory map igvm parameters")?;
}

Ok(Self {
mapping,
ranges: config_ranges,
zero_on_drop,
})
}

Expand All @@ -152,25 +154,27 @@ impl<'a> Vtl2ParamsMap<'a> {

impl Drop for Vtl2ParamsMap<'_> {
fn drop(&mut self) {
let base = self
.ranges
.first()
.expect("already checked that there is at least one range")
.start();

for range in self.ranges {
self.mapping
.fill_at((range.start() - base) as usize, 0, range.len() as usize)
.unwrap();
if self.zero_on_drop {
let base = self
.ranges
.first()
.expect("already checked that there is at least one range")
.start();

for range in self.ranges {
self.mapping
.fill_at((range.start() - base) as usize, 0, range.len() as usize)
.unwrap();
}
}
}
}

/// Reads the VTL 2 parameters from the vtl-boot-data region.
/// Reads the VTL 2 parameters from the config region and VTL2 reserved region.
pub fn read_vtl2_params() -> anyhow::Result<(RuntimeParameters, MeasuredVtl2Info)> {
let parsed_openhcl_boot = ParsedBootDtInfo::new().context("failed to parse openhcl_boot dt")?;

let mapping = Vtl2ParamsMap::new(&parsed_openhcl_boot.config_ranges)
let mapping = Vtl2ParamsMap::new(&parsed_openhcl_boot.config_ranges, true)
.context("failed to map igvm parameters")?;

// For the various ACPI tables, read the header to see how big the table
Expand Down Expand Up @@ -216,21 +220,26 @@ pub fn read_vtl2_params() -> anyhow::Result<(RuntimeParameters, MeasuredVtl2Info
}
};

// Read SNP specific information from the reserved region.
let (cvm_cpuid_info, snp_secrets) = {
if parsed_openhcl_boot.isolation == IsolationType::Snp {
let ranges = &[parsed_openhcl_boot.vtl2_reserved_range];
let reserved_mapping =
Vtl2ParamsMap::new(ranges, false).context("failed to map vtl2 reserved region")?;

let mut cpuid_pages: Vec<u8> =
vec![0; (HV_PAGE_SIZE * PARAVISOR_CONFIG_CPUID_SIZE_PAGES) as usize];
mapping
vec![0; (PARAVISOR_RESERVED_VTL2_SNP_CPUID_SIZE_PAGES * HV_PAGE_SIZE) as usize];
reserved_mapping
.read_at(
(PARAVISOR_CONFIG_CPUID_PAGE_INDEX * HV_PAGE_SIZE) as usize,
(PARAVISOR_RESERVED_VTL2_SNP_CPUID_PAGE_INDEX * HV_PAGE_SIZE) as usize,
cpuid_pages.as_mut_slice(),
)
.context("failed to read cpuid pages")?;
let mut secrets =
vec![0; (HV_PAGE_SIZE * PARAVISOR_CONFIG_SECRETS_SIZE_PAGES) as usize];
mapping
vec![0; (PARAVISOR_RESERVED_VTL2_SNP_SECRETS_SIZE_PAGES * HV_PAGE_SIZE) as usize];
reserved_mapping
.read_at(
(HV_PAGE_SIZE * PARAVISOR_CONFIG_SECRETS_PAGE_INDEX) as usize,
(PARAVISOR_RESERVED_VTL2_SNP_SECRETS_PAGE_INDEX * HV_PAGE_SIZE) as usize,
secrets.as_mut_slice(),
)
.context("failed to read secrets page")?;
Expand Down
Loading