xref: /cloud-hypervisor/vmm/src/igvm/igvm_loader.rs (revision d7edd9d51fbe16067f06ccb3014a012861a0c52b)
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