17030b15eSMuminul Islam // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
27030b15eSMuminul Islam //
37030b15eSMuminul Islam // Copyright © 2023, Microsoft Corporation
47030b15eSMuminul Islam //
57030b15eSMuminul Islam use std::collections::HashMap;
67030b15eSMuminul Islam use std::ffi::CString;
761e57e1cSRuoqing He use std::io::{Read, Seek, SeekFrom};
87030b15eSMuminul Islam use std::mem::size_of;
97030b15eSMuminul Islam use std::sync::{Arc, Mutex};
107030b15eSMuminul Islam
1161e57e1cSRuoqing He use igvm::snp_defs::SevVmsa;
1261e57e1cSRuoqing He use igvm::{IgvmDirectiveHeader, IgvmFile, IgvmPlatformHeader, IsolationType};
1388a9f799SRob Bradford use igvm_defs::{
1488a9f799SRob Bradford IgvmPageDataType, IgvmPlatformType, IGVM_VHS_PARAMETER, IGVM_VHS_PARAMETER_INSERT,
1588a9f799SRob Bradford };
169b151d06SJinank Jain #[cfg(feature = "sev_snp")]
179b151d06SJinank Jain use igvm_defs::{MemoryMapEntryType, IGVM_VHS_MEMORY_MAP_ENTRY};
1888a9f799SRob Bradford use mshv_bindings::*;
1988a9f799SRob Bradford use thiserror::Error;
20af285696SRuoqing He use zerocopy::IntoBytes;
2188a9f799SRob Bradford
2288a9f799SRob Bradford use crate::cpu::CpuManager;
2361e57e1cSRuoqing He use crate::igvm::loader::Loader;
2461e57e1cSRuoqing He use crate::igvm::{BootPageAcceptance, IgvmLoadedInfo, StartupMemoryType, HV_PAGE_SIZE};
2588a9f799SRob Bradford use crate::memory_manager::MemoryManager;
2688a9f799SRob Bradford #[cfg(feature = "sev_snp")]
2788a9f799SRob Bradford use crate::GuestMemoryMmap;
289b151d06SJinank Jain
297030b15eSMuminul Islam #[derive(Debug, Error)]
307030b15eSMuminul Islam pub enum Error {
317030b15eSMuminul Islam #[error("command line is not a valid C string")]
327030b15eSMuminul Islam InvalidCommandLine(#[source] std::ffi::NulError),
337030b15eSMuminul Islam #[error("failed to read igvm file")]
347030b15eSMuminul Islam Igvm(#[source] std::io::Error),
357030b15eSMuminul Islam #[error("invalid igvm file")]
36f6d99d9aSWei Liu InvalidIgvmFile(#[source] igvm::Error),
379b151d06SJinank Jain #[error("invalid guest memory map")]
389b151d06SJinank Jain InvalidGuestMemmap(#[source] arch::Error),
397030b15eSMuminul Islam #[error("loader error")]
407030b15eSMuminul Islam Loader(#[source] crate::igvm::loader::Error),
417030b15eSMuminul Islam #[error("parameter too large for parameter area")]
427030b15eSMuminul Islam ParameterTooLarge,
43*d7edd9d5SPhilipp Schuster #[error("Error importing isolated pages")]
447030b15eSMuminul Islam ImportIsolatedPages(#[source] hypervisor::HypervisorVmError),
45*d7edd9d5SPhilipp Schuster #[error("Error completing importing isolated pages")]
467030b15eSMuminul Islam CompleteIsolatedImport(#[source] hypervisor::HypervisorVmError),
47*d7edd9d5SPhilipp Schuster #[error("Error decoding host data")]
481a4c890fSMuminul Islam FailedToDecodeHostData(#[source] hex::FromHexError),
497030b15eSMuminul Islam }
507030b15eSMuminul Islam
517030b15eSMuminul Islam #[allow(dead_code)]
527030b15eSMuminul Islam #[derive(Copy, Clone)]
537030b15eSMuminul Islam struct GpaPages {
547030b15eSMuminul Islam pub gpa: u64,
557030b15eSMuminul Islam pub page_type: u32,
567030b15eSMuminul Islam pub page_size: u32,
577030b15eSMuminul Islam }
587030b15eSMuminul Islam
597030b15eSMuminul Islam #[derive(Debug)]
607030b15eSMuminul Islam enum ParameterAreaState {
617030b15eSMuminul Islam /// Parameter area has been declared via a ParameterArea header.
627030b15eSMuminul Islam Allocated { data: Vec<u8>, max_size: u64 },
637030b15eSMuminul Islam /// Parameter area inserted and invalid to use.
647030b15eSMuminul Islam Inserted,
657030b15eSMuminul Islam }
667030b15eSMuminul Islam
679b151d06SJinank Jain #[cfg(feature = "sev_snp")]
igvm_memmap_from_ram_range(ram_range: (u64, u64)) -> IGVM_VHS_MEMORY_MAP_ENTRY689b151d06SJinank Jain fn igvm_memmap_from_ram_range(ram_range: (u64, u64)) -> IGVM_VHS_MEMORY_MAP_ENTRY {
699b151d06SJinank Jain assert!(ram_range.0 % HV_PAGE_SIZE == 0);
709b151d06SJinank Jain assert!((ram_range.1 - ram_range.0) % HV_PAGE_SIZE == 0);
719b151d06SJinank Jain
729b151d06SJinank Jain IGVM_VHS_MEMORY_MAP_ENTRY {
739b151d06SJinank Jain starting_gpa_page_number: ram_range.0 / HV_PAGE_SIZE,
749b151d06SJinank Jain number_of_pages: (ram_range.1 - ram_range.0) / HV_PAGE_SIZE,
759b151d06SJinank Jain entry_type: MemoryMapEntryType::MEMORY,
769b151d06SJinank Jain flags: 0,
779b151d06SJinank Jain reserved: 0,
789b151d06SJinank Jain }
799b151d06SJinank Jain }
809b151d06SJinank Jain
819b151d06SJinank Jain #[cfg(feature = "sev_snp")]
generate_memory_map( guest_mem: &GuestMemoryMmap, ) -> Result<Vec<IGVM_VHS_MEMORY_MAP_ENTRY>, Error>829b151d06SJinank Jain fn generate_memory_map(
839b151d06SJinank Jain guest_mem: &GuestMemoryMmap,
849b151d06SJinank Jain ) -> Result<Vec<IGVM_VHS_MEMORY_MAP_ENTRY>, Error> {
859b151d06SJinank Jain let mut memory_map = Vec::new();
869b151d06SJinank Jain
879b151d06SJinank Jain // Get usable physical memory ranges
88ce7db3f7SThomas Barrett let ram_ranges = arch::generate_ram_ranges(guest_mem).map_err(Error::InvalidGuestMemmap)?;
899b151d06SJinank Jain
90ce7db3f7SThomas Barrett for ram_range in ram_ranges {
91ce7db3f7SThomas Barrett memory_map.push(igvm_memmap_from_ram_range(ram_range));
929b151d06SJinank Jain }
939b151d06SJinank Jain
949b151d06SJinank Jain Ok(memory_map)
959b151d06SJinank Jain }
969b151d06SJinank Jain
977030b15eSMuminul Islam // Import a parameter to the given parameter area.
import_parameter( parameter_areas: &mut HashMap<u32, ParameterAreaState>, info: &IGVM_VHS_PARAMETER, parameter: &[u8], ) -> Result<(), Error>987030b15eSMuminul Islam fn import_parameter(
997030b15eSMuminul Islam parameter_areas: &mut HashMap<u32, ParameterAreaState>,
1007030b15eSMuminul Islam info: &IGVM_VHS_PARAMETER,
1017030b15eSMuminul Islam parameter: &[u8],
1027030b15eSMuminul Islam ) -> Result<(), Error> {
1037030b15eSMuminul Islam let (parameter_area, max_size) = match parameter_areas
1047030b15eSMuminul Islam .get_mut(&info.parameter_area_index)
1057030b15eSMuminul Islam .expect("parameter area should be present")
1067030b15eSMuminul Islam {
1077030b15eSMuminul Islam ParameterAreaState::Allocated { data, max_size } => (data, max_size),
1087030b15eSMuminul Islam ParameterAreaState::Inserted => panic!("igvmfile is not valid"),
1097030b15eSMuminul Islam };
1107030b15eSMuminul Islam let offset = info.byte_offset as usize;
1117030b15eSMuminul Islam let end_of_parameter = offset + parameter.len();
1127030b15eSMuminul Islam
1137030b15eSMuminul Islam if end_of_parameter > *max_size as usize {
1147030b15eSMuminul Islam // TODO: tracing for which parameter was too big?
1157030b15eSMuminul Islam return Err(Error::ParameterTooLarge);
1167030b15eSMuminul Islam }
1177030b15eSMuminul Islam
1187030b15eSMuminul Islam if parameter_area.len() < end_of_parameter {
1197030b15eSMuminul Islam parameter_area.resize(end_of_parameter, 0);
1207030b15eSMuminul Islam }
1217030b15eSMuminul Islam
1227030b15eSMuminul Islam parameter_area[offset..end_of_parameter].copy_from_slice(parameter);
1237030b15eSMuminul Islam Ok(())
1247030b15eSMuminul Islam }
1257030b15eSMuminul Islam
1267030b15eSMuminul Islam ///
1277030b15eSMuminul Islam /// Load the given IGVM file to guest memory.
1287030b15eSMuminul Islam /// Right now it only supports SNP based isolation.
1297030b15eSMuminul Islam /// We can boot legacy VM with an igvm file without
1307030b15eSMuminul Islam /// any isolation.
1317030b15eSMuminul Islam ///
load_igvm( mut file: &std::fs::File, memory_manager: Arc<Mutex<MemoryManager>>, cpu_manager: Arc<Mutex<CpuManager>>, cmdline: &str, #[cfg(feature = "sev_snp")] host_data: &Option<String>, ) -> Result<Box<IgvmLoadedInfo>, Error>1327030b15eSMuminul Islam pub fn load_igvm(
1337030b15eSMuminul Islam mut file: &std::fs::File,
1347030b15eSMuminul Islam memory_manager: Arc<Mutex<MemoryManager>>,
1357030b15eSMuminul Islam cpu_manager: Arc<Mutex<CpuManager>>,
1367030b15eSMuminul Islam cmdline: &str,
1371a4c890fSMuminul Islam #[cfg(feature = "sev_snp")] host_data: &Option<String>,
1387030b15eSMuminul Islam ) -> Result<Box<IgvmLoadedInfo>, Error> {
1397030b15eSMuminul Islam let mut loaded_info: Box<IgvmLoadedInfo> = Box::default();
1407030b15eSMuminul Islam let command_line = CString::new(cmdline).map_err(Error::InvalidCommandLine)?;
1417030b15eSMuminul Islam let mut file_contents = Vec::new();
1427030b15eSMuminul Islam let memory = memory_manager.lock().as_ref().unwrap().guest_memory();
1437030b15eSMuminul Islam let mut gpas: Vec<GpaPages> = Vec::new();
1447030b15eSMuminul Islam let proc_count = cpu_manager.lock().unwrap().vcpus().len() as u32;
1457030b15eSMuminul Islam
1461a4c890fSMuminul Islam #[cfg(feature = "sev_snp")]
1471a4c890fSMuminul Islam let mut host_data_contents = [0; 32];
1481a4c890fSMuminul Islam #[cfg(feature = "sev_snp")]
1491a4c890fSMuminul Islam if let Some(host_data_str) = host_data {
1501a4c890fSMuminul Islam hex::decode_to_slice(host_data_str, &mut host_data_contents as &mut [u8])
1511a4c890fSMuminul Islam .map_err(Error::FailedToDecodeHostData)?;
1521a4c890fSMuminul Islam }
1531a4c890fSMuminul Islam
1547030b15eSMuminul Islam file.seek(SeekFrom::Start(0)).map_err(Error::Igvm)?;
1557030b15eSMuminul Islam file.read_to_end(&mut file_contents).map_err(Error::Igvm)?;
1567030b15eSMuminul Islam
1577030b15eSMuminul Islam let igvm_file = IgvmFile::new_from_binary(&file_contents, Some(IsolationType::Snp))
1587030b15eSMuminul Islam .map_err(Error::InvalidIgvmFile)?;
1597030b15eSMuminul Islam
1607030b15eSMuminul Islam let mask = match &igvm_file.platforms()[0] {
1617030b15eSMuminul Islam IgvmPlatformHeader::SupportedPlatform(info) => {
1627030b15eSMuminul Islam debug_assert!(info.platform_type == IgvmPlatformType::SEV_SNP);
1637030b15eSMuminul Islam info.compatibility_mask
1647030b15eSMuminul Islam }
1657030b15eSMuminul Islam };
1667030b15eSMuminul Islam
1677030b15eSMuminul Islam let mut loader = Loader::new(memory);
1687030b15eSMuminul Islam
1697030b15eSMuminul Islam let mut parameter_areas: HashMap<u32, ParameterAreaState> = HashMap::new();
1707030b15eSMuminul Islam
1717030b15eSMuminul Islam for header in igvm_file.directives() {
1727030b15eSMuminul Islam debug_assert!(header.compatibility_mask().unwrap_or(mask) & mask == mask);
1737030b15eSMuminul Islam
1747030b15eSMuminul Islam match header {
1757030b15eSMuminul Islam IgvmDirectiveHeader::PageData {
1767030b15eSMuminul Islam gpa,
1777030b15eSMuminul Islam compatibility_mask: _,
1787030b15eSMuminul Islam flags,
1797030b15eSMuminul Islam data_type,
1807030b15eSMuminul Islam data,
1817030b15eSMuminul Islam } => {
1827030b15eSMuminul Islam debug_assert!(data.len() as u64 % HV_PAGE_SIZE == 0);
1837030b15eSMuminul Islam
1847030b15eSMuminul Islam // TODO: only 4k or empty page data supported right now
1857030b15eSMuminul Islam assert!(data.len() as u64 == HV_PAGE_SIZE || data.is_empty());
1867030b15eSMuminul Islam
1877030b15eSMuminul Islam let acceptance = match *data_type {
1887030b15eSMuminul Islam IgvmPageDataType::NORMAL => {
1897030b15eSMuminul Islam if flags.unmeasured() {
1907030b15eSMuminul Islam gpas.push(GpaPages {
1917030b15eSMuminul Islam gpa: *gpa,
1927030b15eSMuminul Islam page_type: hv_isolated_page_type_HV_ISOLATED_PAGE_TYPE_UNMEASURED,
1937030b15eSMuminul Islam page_size: hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
1947030b15eSMuminul Islam });
1957030b15eSMuminul Islam BootPageAcceptance::ExclusiveUnmeasured
1967030b15eSMuminul Islam } else {
1977030b15eSMuminul Islam gpas.push(GpaPages {
1987030b15eSMuminul Islam gpa: *gpa,
1997030b15eSMuminul Islam page_type: hv_isolated_page_type_HV_ISOLATED_PAGE_TYPE_NORMAL,
2007030b15eSMuminul Islam page_size: hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
2017030b15eSMuminul Islam });
2027030b15eSMuminul Islam BootPageAcceptance::Exclusive
2037030b15eSMuminul Islam }
2047030b15eSMuminul Islam }
2057030b15eSMuminul Islam IgvmPageDataType::SECRETS => {
2067030b15eSMuminul Islam gpas.push(GpaPages {
2077030b15eSMuminul Islam gpa: *gpa,
2087030b15eSMuminul Islam page_type: hv_isolated_page_type_HV_ISOLATED_PAGE_TYPE_SECRETS,
2097030b15eSMuminul Islam page_size: hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
2107030b15eSMuminul Islam });
2117030b15eSMuminul Islam BootPageAcceptance::SecretsPage
2127030b15eSMuminul Islam }
2137030b15eSMuminul Islam IgvmPageDataType::CPUID_DATA => {
2147030b15eSMuminul Islam // SAFETY: CPUID is readonly
2157030b15eSMuminul Islam unsafe {
2167030b15eSMuminul Islam let cpuid_page_p: *mut hv_psp_cpuid_page =
2177030b15eSMuminul Islam data.as_ptr() as *mut hv_psp_cpuid_page; // as *mut hv_psp_cpuid_page;
2187030b15eSMuminul Islam let cpuid_page: &mut hv_psp_cpuid_page = &mut *cpuid_page_p;
2197030b15eSMuminul Islam for i in 0..cpuid_page.count {
2207030b15eSMuminul Islam let leaf = cpuid_page.cpuid_leaf_info[i as usize];
2217030b15eSMuminul Islam let mut in_leaf = cpu_manager
2227030b15eSMuminul Islam .lock()
2237030b15eSMuminul Islam .unwrap()
2247030b15eSMuminul Islam .get_cpuid_leaf(
2257030b15eSMuminul Islam 0,
2267030b15eSMuminul Islam leaf.eax_in,
2277030b15eSMuminul Islam leaf.ecx_in,
2287030b15eSMuminul Islam leaf.xfem_in,
2297030b15eSMuminul Islam leaf.xss_in,
2307030b15eSMuminul Islam )
2317030b15eSMuminul Islam .unwrap();
2327030b15eSMuminul Islam if leaf.eax_in == 1 {
2337030b15eSMuminul Islam in_leaf[2] &= 0x7FFFFFFF;
2347030b15eSMuminul Islam }
2357030b15eSMuminul Islam cpuid_page.cpuid_leaf_info[i as usize].eax_out = in_leaf[0];
2367030b15eSMuminul Islam cpuid_page.cpuid_leaf_info[i as usize].ebx_out = in_leaf[1];
2377030b15eSMuminul Islam cpuid_page.cpuid_leaf_info[i as usize].ecx_out = in_leaf[2];
2387030b15eSMuminul Islam cpuid_page.cpuid_leaf_info[i as usize].edx_out = in_leaf[3];
2397030b15eSMuminul Islam }
2407030b15eSMuminul Islam }
2417030b15eSMuminul Islam gpas.push(GpaPages {
2427030b15eSMuminul Islam gpa: *gpa,
2437030b15eSMuminul Islam page_type: hv_isolated_page_type_HV_ISOLATED_PAGE_TYPE_CPUID,
2447030b15eSMuminul Islam page_size: hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
2457030b15eSMuminul Islam });
2467030b15eSMuminul Islam BootPageAcceptance::CpuidPage
2477030b15eSMuminul Islam }
2487030b15eSMuminul Islam // TODO: other data types SNP / TDX only, unsupported
2497030b15eSMuminul Islam _ => todo!("unsupported IgvmPageDataType"),
2507030b15eSMuminul Islam };
2517030b15eSMuminul Islam
2527030b15eSMuminul Islam loader
2537030b15eSMuminul Islam .import_pages(gpa / HV_PAGE_SIZE, 1, acceptance, data)
2547030b15eSMuminul Islam .map_err(Error::Loader)?;
2557030b15eSMuminul Islam }
2567030b15eSMuminul Islam IgvmDirectiveHeader::ParameterArea {
2577030b15eSMuminul Islam number_of_bytes,
2587030b15eSMuminul Islam parameter_area_index,
2597030b15eSMuminul Islam initial_data,
2607030b15eSMuminul Islam } => {
2617030b15eSMuminul Islam debug_assert!(number_of_bytes % HV_PAGE_SIZE == 0);
2627030b15eSMuminul Islam debug_assert!(
2637030b15eSMuminul Islam initial_data.is_empty() || initial_data.len() as u64 == *number_of_bytes
2647030b15eSMuminul Islam );
2657030b15eSMuminul Islam
2667030b15eSMuminul Islam // Allocate a new parameter area. It must not be already used.
2677030b15eSMuminul Islam if parameter_areas
2687030b15eSMuminul Islam .insert(
2697030b15eSMuminul Islam *parameter_area_index,
2707030b15eSMuminul Islam ParameterAreaState::Allocated {
2717030b15eSMuminul Islam data: initial_data.clone(),
2727030b15eSMuminul Islam max_size: *number_of_bytes,
2737030b15eSMuminul Islam },
2747030b15eSMuminul Islam )
2757030b15eSMuminul Islam .is_some()
2767030b15eSMuminul Islam {
2777030b15eSMuminul Islam panic!("IgvmFile is not valid, invalid invariant");
2787030b15eSMuminul Islam }
2797030b15eSMuminul Islam }
2807030b15eSMuminul Islam IgvmDirectiveHeader::VpCount(info) => {
2817030b15eSMuminul Islam import_parameter(&mut parameter_areas, info, proc_count.as_bytes())?;
2827030b15eSMuminul Islam }
2837030b15eSMuminul Islam IgvmDirectiveHeader::MmioRanges(_info) => {
2847030b15eSMuminul Islam todo!("unsupported IgvmPageDataType");
2857030b15eSMuminul Islam }
2867030b15eSMuminul Islam IgvmDirectiveHeader::MemoryMap(_info) => {
2879b151d06SJinank Jain #[cfg(feature = "sev_snp")]
2889b151d06SJinank Jain {
2899b151d06SJinank Jain let guest_mem = memory_manager.lock().unwrap().boot_guest_memory();
2909b151d06SJinank Jain let memory_map = generate_memory_map(&guest_mem)?;
2919b151d06SJinank Jain import_parameter(&mut parameter_areas, _info, memory_map.as_bytes())?;
2929b151d06SJinank Jain }
2939b151d06SJinank Jain
2949b151d06SJinank Jain #[cfg(not(feature = "sev_snp"))]
2957030b15eSMuminul Islam todo!("Not implemented");
2967030b15eSMuminul Islam }
2977030b15eSMuminul Islam IgvmDirectiveHeader::CommandLine(info) => {
2987030b15eSMuminul Islam import_parameter(&mut parameter_areas, info, command_line.as_bytes_with_nul())?;
2997030b15eSMuminul Islam }
3007030b15eSMuminul Islam IgvmDirectiveHeader::RequiredMemory {
3017030b15eSMuminul Islam gpa,
3027030b15eSMuminul Islam compatibility_mask: _,
3037030b15eSMuminul Islam number_of_bytes,
3047030b15eSMuminul Islam vtl2_protectable: _,
3057030b15eSMuminul Islam } => {
3067030b15eSMuminul Islam let memory_type = StartupMemoryType::Ram;
3077030b15eSMuminul Islam loaded_info.gpas.push(*gpa);
3087030b15eSMuminul Islam loader
3097030b15eSMuminul Islam .verify_startup_memory_available(
3107030b15eSMuminul Islam gpa / HV_PAGE_SIZE,
3117030b15eSMuminul Islam *number_of_bytes as u64 / HV_PAGE_SIZE,
3127030b15eSMuminul Islam memory_type,
3137030b15eSMuminul Islam )
3147030b15eSMuminul Islam .map_err(Error::Loader)?;
3157030b15eSMuminul Islam }
3167030b15eSMuminul Islam IgvmDirectiveHeader::SnpVpContext {
3177030b15eSMuminul Islam gpa,
3187030b15eSMuminul Islam compatibility_mask: _,
3197030b15eSMuminul Islam vp_index,
3207030b15eSMuminul Islam vmsa,
3217030b15eSMuminul Islam } => {
3227030b15eSMuminul Islam assert_eq!(gpa % HV_PAGE_SIZE, 0);
3237030b15eSMuminul Islam let mut data: [u8; 4096] = [0; 4096];
3247030b15eSMuminul Islam let len = size_of::<SevVmsa>();
3257030b15eSMuminul Islam loaded_info.vmsa_gpa = *gpa;
3267030b15eSMuminul Islam loaded_info.vmsa = **vmsa;
3277030b15eSMuminul Islam // Only supported for index zero
3287030b15eSMuminul Islam if *vp_index == 0 {
3297030b15eSMuminul Islam data[..len].copy_from_slice(vmsa.as_bytes());
3307030b15eSMuminul Islam loader
3317030b15eSMuminul Islam .import_pages(gpa / HV_PAGE_SIZE, 1, BootPageAcceptance::VpContext, &data)
3327030b15eSMuminul Islam .map_err(Error::Loader)?;
3337030b15eSMuminul Islam }
3347030b15eSMuminul Islam
3357030b15eSMuminul Islam gpas.push(GpaPages {
3367030b15eSMuminul Islam gpa: *gpa,
3377030b15eSMuminul Islam page_type: hv_isolated_page_type_HV_ISOLATED_PAGE_TYPE_VMSA,
3387030b15eSMuminul Islam page_size: hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
3397030b15eSMuminul Islam });
3407030b15eSMuminul Islam }
3417030b15eSMuminul Islam IgvmDirectiveHeader::SnpIdBlock {
3427030b15eSMuminul Islam compatibility_mask,
3437030b15eSMuminul Islam author_key_enabled,
3447030b15eSMuminul Islam reserved,
3457030b15eSMuminul Islam ld,
3467030b15eSMuminul Islam family_id,
3477030b15eSMuminul Islam image_id,
3487030b15eSMuminul Islam version,
3497030b15eSMuminul Islam guest_svn,
3507030b15eSMuminul Islam id_key_algorithm,
3517030b15eSMuminul Islam author_key_algorithm,
3527030b15eSMuminul Islam id_key_signature,
3537030b15eSMuminul Islam id_public_key,
3547030b15eSMuminul Islam author_key_signature,
3557030b15eSMuminul Islam author_public_key,
3567030b15eSMuminul Islam } => {
3577030b15eSMuminul Islam loaded_info.snp_id_block.compatibility_mask = *compatibility_mask;
3587030b15eSMuminul Islam loaded_info.snp_id_block.author_key_enabled = *author_key_enabled;
35921979897SJinank Jain loaded_info.snp_id_block.reserved = *reserved;
36021979897SJinank Jain loaded_info.snp_id_block.ld = *ld;
36121979897SJinank Jain loaded_info.snp_id_block.family_id = *family_id;
36221979897SJinank Jain loaded_info.snp_id_block.image_id = *image_id;
3637030b15eSMuminul Islam loaded_info.snp_id_block.version = *version;
3647030b15eSMuminul Islam loaded_info.snp_id_block.guest_svn = *guest_svn;
3657030b15eSMuminul Islam loaded_info.snp_id_block.id_key_algorithm = *id_key_algorithm;
3667030b15eSMuminul Islam loaded_info.snp_id_block.author_key_algorithm = *author_key_algorithm;
3677030b15eSMuminul Islam loaded_info.snp_id_block.id_key_signature = **id_key_signature;
3687030b15eSMuminul Islam loaded_info.snp_id_block.id_public_key = **id_public_key;
3697030b15eSMuminul Islam loaded_info.snp_id_block.author_key_signature = **author_key_signature;
3707030b15eSMuminul Islam loaded_info.snp_id_block.author_public_key = **author_public_key;
3717030b15eSMuminul Islam }
3727030b15eSMuminul Islam IgvmDirectiveHeader::X64VbsVpContext {
3737030b15eSMuminul Islam vtl: _,
3747030b15eSMuminul Islam registers: _,
3757030b15eSMuminul Islam compatibility_mask: _,
3767030b15eSMuminul Islam } => {
3777030b15eSMuminul Islam todo!("VbsVpContext not supported");
3787030b15eSMuminul Islam }
3797030b15eSMuminul Islam IgvmDirectiveHeader::VbsMeasurement { .. } => {
3807030b15eSMuminul Islam todo!("VbsMeasurement not supported")
3817030b15eSMuminul Islam }
3827030b15eSMuminul Islam IgvmDirectiveHeader::ParameterInsert(IGVM_VHS_PARAMETER_INSERT {
3837030b15eSMuminul Islam gpa,
3847030b15eSMuminul Islam compatibility_mask: _,
3857030b15eSMuminul Islam parameter_area_index,
3867030b15eSMuminul Islam }) => {
3877030b15eSMuminul Islam debug_assert!(gpa % HV_PAGE_SIZE == 0);
3887030b15eSMuminul Islam
3897030b15eSMuminul Islam let area = parameter_areas
3907030b15eSMuminul Islam .get_mut(parameter_area_index)
3917030b15eSMuminul Islam .expect("igvmfile should be valid");
3927030b15eSMuminul Islam match area {
3937030b15eSMuminul Islam ParameterAreaState::Allocated { data, max_size } => loader
3947030b15eSMuminul Islam .import_pages(
3957030b15eSMuminul Islam gpa / HV_PAGE_SIZE,
3967030b15eSMuminul Islam *max_size / HV_PAGE_SIZE,
3977030b15eSMuminul Islam BootPageAcceptance::ExclusiveUnmeasured,
3987030b15eSMuminul Islam data,
3997030b15eSMuminul Islam )
4007030b15eSMuminul Islam .map_err(Error::Loader)?,
4017030b15eSMuminul Islam ParameterAreaState::Inserted => panic!("igvmfile is invalid, multiple insert"),
4027030b15eSMuminul Islam }
4037030b15eSMuminul Islam *area = ParameterAreaState::Inserted;
4047030b15eSMuminul Islam gpas.push(GpaPages {
4057030b15eSMuminul Islam gpa: *gpa,
4067030b15eSMuminul Islam page_type: hv_isolated_page_type_HV_ISOLATED_PAGE_TYPE_UNMEASURED,
4077030b15eSMuminul Islam page_size: hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
4087030b15eSMuminul Islam });
4097030b15eSMuminul Islam }
4107030b15eSMuminul Islam IgvmDirectiveHeader::ErrorRange { .. } => {
4117030b15eSMuminul Islam todo!("Error Range not supported")
4127030b15eSMuminul Islam }
4137030b15eSMuminul Islam _ => {
4147030b15eSMuminul Islam todo!("Header not supported!!")
4157030b15eSMuminul Islam }
4167030b15eSMuminul Islam }
4177030b15eSMuminul Islam }
4187030b15eSMuminul Islam
419433d4ddcSMuminul Islam #[cfg(feature = "sev_snp")]
420433d4ddcSMuminul Islam {
421433d4ddcSMuminul Islam use std::time::Instant;
422433d4ddcSMuminul Islam
423dc68a6e3SMuminul Islam let mut now = Instant::now();
424433d4ddcSMuminul Islam
425433d4ddcSMuminul Islam // Sort the gpas to group them by the page type
426433d4ddcSMuminul Islam gpas.sort_by(|a, b| a.gpa.cmp(&b.gpa));
427433d4ddcSMuminul Islam
428433d4ddcSMuminul Islam let gpas_grouped = gpas
429433d4ddcSMuminul Islam .iter()
430433d4ddcSMuminul Islam .fold(Vec::<Vec<GpaPages>>::new(), |mut acc, gpa| {
431433d4ddcSMuminul Islam if let Some(last_vec) = acc.last_mut() {
432433d4ddcSMuminul Islam if last_vec[0].page_type == gpa.page_type {
433433d4ddcSMuminul Islam last_vec.push(*gpa);
434433d4ddcSMuminul Islam return acc;
435433d4ddcSMuminul Islam }
436433d4ddcSMuminul Islam }
437433d4ddcSMuminul Islam acc.push(vec![*gpa]);
438433d4ddcSMuminul Islam acc
439433d4ddcSMuminul Islam });
440433d4ddcSMuminul Islam
441433d4ddcSMuminul Islam // Import the pages as a group(by page type) of PFNs to reduce the
442433d4ddcSMuminul Islam // hypercall.
443433d4ddcSMuminul Islam for group in gpas_grouped.iter() {
444433d4ddcSMuminul Islam info!(
445433d4ddcSMuminul Islam "Importing {} page{}",
446433d4ddcSMuminul Islam group.len(),
447433d4ddcSMuminul Islam if group.len() > 1 { "s" } else { "" }
448433d4ddcSMuminul Islam );
449433d4ddcSMuminul Islam // Convert the gpa into PFN as MSHV hypercall takes an array
450433d4ddcSMuminul Islam // of PFN for importing the isolated pages
451433d4ddcSMuminul Islam let pfns: Vec<u64> = group
452433d4ddcSMuminul Islam .iter()
453433d4ddcSMuminul Islam .map(|gpa| gpa.gpa >> HV_HYP_PAGE_SHIFT)
454433d4ddcSMuminul Islam .collect();
455433d4ddcSMuminul Islam memory_manager
456433d4ddcSMuminul Islam .lock()
457433d4ddcSMuminul Islam .unwrap()
458433d4ddcSMuminul Islam .vm
459433d4ddcSMuminul Islam .import_isolated_pages(
460433d4ddcSMuminul Islam group[0].page_type,
461433d4ddcSMuminul Islam hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
462433d4ddcSMuminul Islam &pfns,
463433d4ddcSMuminul Islam )
464433d4ddcSMuminul Islam .map_err(Error::ImportIsolatedPages)?;
465433d4ddcSMuminul Islam }
466433d4ddcSMuminul Islam
467433d4ddcSMuminul Islam info!(
468433d4ddcSMuminul Islam "Time it took to for hashing pages {:.2?} and page_count {:?}",
469433d4ddcSMuminul Islam now.elapsed(),
470433d4ddcSMuminul Islam gpas.len()
471433d4ddcSMuminul Islam );
472dc68a6e3SMuminul Islam
473dc68a6e3SMuminul Islam now = Instant::now();
474dc68a6e3SMuminul Islam // Call Complete Isolated Import since we are done importing isolated pages
475dc68a6e3SMuminul Islam memory_manager
476dc68a6e3SMuminul Islam .lock()
477dc68a6e3SMuminul Islam .unwrap()
478dc68a6e3SMuminul Islam .vm
4791a4c890fSMuminul Islam .complete_isolated_import(loaded_info.snp_id_block, host_data_contents, 1)
480dc68a6e3SMuminul Islam .map_err(Error::CompleteIsolatedImport)?;
481dc68a6e3SMuminul Islam
482dc68a6e3SMuminul Islam info!(
483dc68a6e3SMuminul Islam "Time it took to for launch complete command {:.2?}",
484dc68a6e3SMuminul Islam now.elapsed()
485dc68a6e3SMuminul Islam );
486433d4ddcSMuminul Islam }
487433d4ddcSMuminul Islam
4887030b15eSMuminul Islam debug!("Dumping the contents of VMSA page: {:x?}", loaded_info.vmsa);
4897030b15eSMuminul Islam Ok(loaded_info)
4907030b15eSMuminul Islam }
491