From b4a986dd222b6bb5d8d7108386c8407cc3ee5ddb Mon Sep 17 00:00:00 2001 From: Alexandra Iordache Date: Tue, 5 May 2020 14:29:25 +0300 Subject: [PATCH] rework BootParams struct for extensibility * boot parameters and corresponding addresses are separate fields in the struct, instead of packed in a tuple * sections and modules (for PVH boot) can be added one at a time and don't need to be of the same type Signed-off-by: Alexandra Iordache --- coverage_config_x86_64.json | 2 +- src/configurator/mod.rs | 494 ++++++++++++++++++++++++++++++- src/configurator/x86_64/linux.rs | 6 +- src/configurator/x86_64/pvh.rs | 27 +- 4 files changed, 500 insertions(+), 29 deletions(-) diff --git a/coverage_config_x86_64.json b/coverage_config_x86_64.json index f199c48b..fe626856 100644 --- a/coverage_config_x86_64.json +++ b/coverage_config_x86_64.json @@ -1,5 +1,5 @@ { - "coverage_score": 77.8, + "coverage_score": 78.5, "exclude_path": "", "crate_features": "" } diff --git a/src/configurator/mod.rs b/src/configurator/mod.rs index 628ae996..8d860ebb 100644 --- a/src/configurator/mod.rs +++ b/src/configurator/mod.rs @@ -16,7 +16,7 @@ //! - [PvhBootConfigurator](pvh/struct.PvhBootConfigurator.html): PVH boot protocol parameters //! configurator. -use vm_memory::{ByteValued, GuestAddress, GuestMemory}; +use vm_memory::{Address, ByteValued, GuestAddress, GuestMemory}; use std::error::Error as StdError; use std::fmt; @@ -30,6 +30,8 @@ pub use x86_64::*; mod aarch64; #[cfg(target_arch = "aarch64")] pub use aarch64::*; +use std::cmp::max; +use std::mem::size_of; /// Errors specific to boot protocol configuration. #[derive(Debug, PartialEq)] @@ -43,6 +45,13 @@ pub enum Error { /// Errors specific to device tree boot configuration. #[cfg(target_arch = "aarch64")] Fdt(fdt::Error), + + /// Boot parameter was specified without its starting address in guest memory. + MissingStartAddress, + /// Boot parameter address overflows. + Overflow, + /// Boot parameter address precedes the starting address. + InvalidAddress, } impl StdError for Error { @@ -55,6 +64,12 @@ impl StdError for Error { Pvh(ref e) => e.description(), #[cfg(target_arch = "aarch64")] Fdt(ref e) => e.description(), + + MissingStartAddress => { + "Boot parameter was specified without its starting address in guest memory." + } + Overflow => "Boot parameter address overflows.", + InvalidAddress => "Boot parameter address precedes the starting address.", } } } @@ -103,11 +118,17 @@ pub trait BootConfigurator { #[derive(Clone)] pub struct BootParams { /// "Header section", always written in guest memory irrespective of boot protocol. - pub header: (Vec, GuestAddress), + pub header: Vec, + /// Header section address. + pub header_start: GuestAddress, /// Optional sections containing boot configurations (e.g. E820 map). - pub sections: Option<(Vec, GuestAddress)>, + pub sections: Option>, + /// Sections starting address. + pub sections_start: Option, /// Optional modules specified at boot configuration time. - pub modules: Option<(Vec, GuestAddress)>, + pub modules: Option>, + /// Modules starting address. + pub modules_start: Option, } impl BootParams { @@ -118,16 +139,31 @@ impl BootParams { /// * `header` - [`ByteValued`] representation of mandatory boot parameters. /// * `header_addr` - address in guest memory where `header` will be written. /// + /// # Examples + /// + /// ```rust + /// # use linux_loader::configurator::BootParams; + /// # use linux_loader::loader::elf::start_info::hvm_start_info; + /// # use vm_memory::GuestAddress; + /// let boot_params = BootParams::new( + /// &hvm_start_info::default(), + /// GuestAddress(0x1000) + /// ); + /// ``` + /// /// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html pub fn new(header: &T, header_addr: GuestAddress) -> Self { BootParams { - header: (header.as_slice().to_vec(), header_addr), + header: header.as_slice().to_vec(), + header_start: header_addr, sections: None, + sections_start: None, modules: None, + modules_start: None, } } - /// Adds or overwrites the boot sections and associated memory address. + /// Sets or overwrites the boot sections and associated memory address. /// /// Unused on `aarch64` and for the Linux boot protocol. /// For the PVH boot protocol, the sections specify the memory map table in @@ -138,19 +174,105 @@ impl BootParams { /// * `sections` - vector of [`ByteValued`] boot configurations. /// * `sections_addr` - address where the sections will be written in guest memory. /// + /// # Examples + /// + /// ```rust + /// # use linux_loader::configurator::BootParams; + /// # use vm_memory::{ByteValued, GuestAddress}; + /// # #[derive(Clone, Copy, Default)] + /// # struct Header; + /// # unsafe impl ByteValued for Header {} + /// # #[derive(Clone, Copy, Default)] + /// # struct Section; + /// # unsafe impl ByteValued for Section {} + /// let mut boot_params = BootParams::new(&Header::default(), GuestAddress(0x1000)); + /// let mut sections: Vec
= vec![Section::default()]; + /// boot_params.set_sections(sections.as_slice(), GuestAddress(0x2000)); + /// // Another call overwrites the sections. + /// sections.clear(); + /// boot_params.set_sections(sections.as_slice(), GuestAddress(0x3000)); + /// assert_eq!(boot_params.sections.unwrap().len(), 0); + /// assert_eq!(boot_params.sections_start.unwrap(), GuestAddress(0x3000)); + /// ``` + /// /// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html /// [`hvm_memmap_table_entry`]: ../loader/elf/start_info/struct.hvm_memmap_table_entry.html - pub fn add_sections(&mut self, sections: &[T], sections_addr: GuestAddress) { - self.sections = Some(( + pub fn set_sections(&mut self, sections: &[T], sections_addr: GuestAddress) { + self.sections = Some( sections .iter() .flat_map(|section| section.as_slice().to_vec()) .collect(), - sections_addr, - )); + ); + self.sections_start = Some(sections_addr); } - /// Adds or overwrites the boot modules and associated memory address. + /// Adds a boot section at the specified address (if specified and valid), or appends it. + /// + /// It's up to the caller to ensure that the section will not overlap with existing content + /// or leave a gap past the current sections in the list. + /// + /// # Arguments + /// + /// * `section` - [`ByteValued`] boot section element. + /// * `section_addr` - optional address for the section in guest memory. + /// + /// # Returns + /// + /// Starting address of the section in guest memory, or an error. + /// + /// # Examples + /// + /// ```rust + /// # use linux_loader::configurator::BootParams; + /// # use vm_memory::{Address, GuestAddress, ByteValued}; + /// # use std::mem::size_of; + /// # #[derive(Clone, Copy, Default)] + /// # struct Header; + /// # unsafe impl ByteValued for Header {} + /// # #[derive(Clone, Copy, Default)] + /// # struct Section; + /// # unsafe impl ByteValued for Section {} + /// let mut boot_params = BootParams::new(&Header::default(), GuestAddress(0x1000)); + /// let section = Section::default(); + /// // Sections start address needs to be configured first. + /// assert!(boot_params.add_section::
(§ion, None).is_err()); + /// let sections_start = GuestAddress(0x2000); + /// assert!(boot_params.add_section::
( + /// §ion, Some(sections_start) + /// ).is_ok()); + /// // It can be overwritten... + /// assert_eq!(boot_params.add_section::
( + /// §ion, + /// Some(sections_start) + /// ).unwrap(), sections_start); + /// // But only if the address is valid. + /// assert!(boot_params.add_section::
( + /// §ion, + /// Some(sections_start.unchecked_sub(0x100)) + /// ).is_err()); + /// // Or appended... + /// assert_eq!( + /// boot_params.add_section::
(§ion, None).unwrap(), + /// sections_start.unchecked_add(size_of::
() as u64) + /// ); + /// ``` + /// + /// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html + pub fn add_section( + &mut self, + section: &T, + section_addr: Option, + ) -> Result { + Self::add_boot_parameter_to_list( + section, + section_addr, + &mut self.sections.get_or_insert(vec![]), + &mut self.sections_start, + ) + } + + /// Sets or overwrites the boot modules and associated memory address. /// /// Unused on `aarch64` and for the Linux boot protocol. /// For the PVH boot protocol, the modules are specified in [`hvm_modlist_entry`] structs. @@ -160,16 +282,129 @@ impl BootParams { /// * `modules` - vector of [`ByteValued`] boot configurations. /// * `modules_addr` - address where the modules will be written in guest memory. /// + /// # Examples + /// + /// ```rust + /// # use linux_loader::configurator::BootParams; + /// # #[derive(Clone, Copy, Default)] + /// # struct Header; + /// # unsafe impl ByteValued for Header {} + /// # #[derive(Clone, Copy, Default)] + /// # struct Module; + /// # unsafe impl ByteValued for Module {} + /// # use vm_memory::{GuestAddress, ByteValued}; + /// let mut boot_params = BootParams::new(&Header::default(), GuestAddress(0x1000)); + /// let mut modules: Vec = vec![Module::default()]; + /// boot_params.set_modules(modules.as_slice(), GuestAddress(0x2000)); + /// // Another call overwrites the sections. + /// modules.clear(); + /// boot_params.set_modules(modules.as_slice(), GuestAddress(0x3000)); + /// assert_eq!(boot_params.modules.unwrap().len(), 0); + /// assert_eq!(boot_params.modules_start.unwrap(), GuestAddress(0x3000)); + /// ``` + /// /// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html /// [`hvm_modlist_entry`]: ../loader/elf/start_info/struct.hvm_modlist_entry.html - pub fn add_modules(&mut self, modules: &[T], modules_addr: GuestAddress) { - self.modules = Some(( + pub fn set_modules(&mut self, modules: &[T], modules_addr: GuestAddress) { + self.modules = Some( modules .iter() .flat_map(|module| module.as_slice().to_vec()) .collect(), - modules_addr, - )); + ); + self.modules_start = Some(modules_addr); + } + + /// Adds a boot module at the specified address (if specified and valid), or appends it. + /// + /// It's up to the caller to ensure that the module will not overlap with existing content + /// or leave a gap past the current modules in the list. + /// + /// # Arguments + /// + /// * `module` - [`ByteValued`] boot module element. + /// * `module_addr` - optional address for the module in guest memory. + /// + /// # Returns + /// + /// Starting address of the module in guest memory, or an error. + /// + /// # Examples + /// + /// ```rust + /// # use linux_loader::configurator::BootParams; + /// # use vm_memory::{Address, GuestAddress, ByteValued}; + /// # use std::mem::size_of; + /// # #[derive(Clone, Copy, Default)] + /// # struct Header; + /// # unsafe impl ByteValued for Header {} + /// # #[derive(Clone, Copy, Default)] + /// # struct Module; + /// # unsafe impl ByteValued for Module {} + /// let mut boot_params = BootParams::new(&Header::default(), GuestAddress(0x1000)); + /// let module = Module::default(); + /// // Modules start address needs to be configured first. + /// assert!(boot_params.add_module::(&module, None).is_err()); + /// let modules_start = GuestAddress(0x2000); + /// assert!(boot_params.add_module::( + /// &module, Some(modules_start) + /// ).is_ok()); + /// // It can be overwritten... + /// assert_eq!(boot_params.add_module::( + /// &module, + /// Some(modules_start) + /// ).unwrap(), modules_start); + /// // But only if the address is valid. + /// assert!(boot_params.add_module::( + /// &module, + /// Some(modules_start.unchecked_sub(0x100)) + /// ).is_err()); + /// // Or appended... + /// assert_eq!( + /// boot_params.add_module::(&module, None).unwrap(), + /// modules_start.unchecked_add(size_of::() as u64) + /// ); + /// ``` + /// + /// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html + pub fn add_module( + &mut self, + module: &T, + module_addr: Option, + ) -> Result { + Self::add_boot_parameter_to_list( + module, + module_addr, + &mut self.modules.get_or_insert(vec![]), + &mut self.modules_start, + ) + } + + /// Adds a boot parameter (section or module) to a byte buffer. + /// + /// Initializes the buffer and corresponding starting address, if necessary. + fn add_boot_parameter_to_list( + elem: &T, + elem_start_opt: Option, + bytes_acc: &mut Vec, + list_start_opt: &mut Option, + ) -> Result { + if list_start_opt.is_none() { + *list_start_opt = elem_start_opt; + } + let list_start = list_start_opt.ok_or(Error::MissingStartAddress)?; + let elem_start = elem_start_opt.unwrap_or( + list_start + .checked_add(bytes_acc.len() as u64) + .ok_or(Error::Overflow)?, + ); + let elem_off = elem_start + .checked_offset_from(list_start) + .ok_or(Error::InvalidAddress)? as usize; + let elem_end = elem_off + size_of::(); + bytes_acc.resize(max(elem_end, bytes_acc.len()), 0); + bytes_acc.splice(elem_off..elem_end, elem.as_slice().iter().cloned()); + Ok(elem_start) } } @@ -177,6 +412,41 @@ impl BootParams { mod tests { use super::*; + #[derive(Clone, Copy, Default)] + struct Foobar { + _foo: [u8; 5], + } + + unsafe impl ByteValued for Foobar {} + + #[derive(Clone, Copy, Debug, Default, PartialEq)] + struct DummyHeader { + _dummy: u64, + } + + unsafe impl ByteValued for DummyHeader {} + + #[derive(Clone, Copy, Debug, Default, PartialEq)] + struct DummySection { + _dummy: u64, + } + + unsafe impl ByteValued for DummySection {} + + #[derive(Clone, Copy, Debug, Default, PartialEq)] + struct DummyModule { + _dummy: u64, + } + + unsafe impl ByteValued for DummyModule {} + + #[derive(Clone, Copy, Debug, Default, PartialEq)] + struct OtherDummyModule { + _dummy: u64, + } + + unsafe impl ByteValued for OtherDummyModule {} + #[test] fn test_error_messages() { #[cfg(target_arch = "x86_64")] @@ -222,5 +492,199 @@ mod tests { format!("{}", Error::Fdt(fdt::Error::WriteFDTToMemory)), "Boot Configurator Error: Error writing FDT in guest memory." ); + + assert_eq!( + format!("{}", Error::MissingStartAddress), + "Boot Configurator Error: \ + Boot parameter was specified without its starting address in guest memory." + ); + assert_eq!( + format!("{}", Error::Overflow), + "Boot Configurator Error: Boot parameter address overflows." + ); + assert_eq!( + format!("{}", Error::InvalidAddress), + "Boot Configurator Error: Boot parameter address precedes the starting address." + ); + } + + #[test] + fn test_bootparam_list_addition() { + let mut accumulator: Vec = vec![]; + let start = GuestAddress(0x1000); + let foo = Foobar::default(); + + // Error case: start address not specified. + assert_eq!( + format!( + "{:?}", + BootParams::add_boot_parameter_to_list(&foo, None, &mut accumulator, &mut None) + .err() + ), + "Some(MissingStartAddress)" + ); + + // Success case: start address is set, element address not specified - will be appended. + assert_eq!( + BootParams::add_boot_parameter_to_list(&foo, None, &mut accumulator, &mut Some(start)) + .unwrap(), + start + ); + assert_eq!(accumulator, foo.as_slice().to_vec()); + + // Success case: start address is unset, element address is specified. + let mut list_start_opt: Option = None; + assert_eq!( + BootParams::add_boot_parameter_to_list( + &foo, + Some(start), + &mut accumulator, + &mut list_start_opt + ) + .unwrap(), + start + ); + assert_eq!(list_start_opt, Some(start)); + assert_eq!(accumulator, foo.as_slice().to_vec()); + + // Error case: start address is set, element address is specified, but precedes start. + assert_eq!( + format!( + "{:?}", + BootParams::add_boot_parameter_to_list( + &foo, + Some(start.unchecked_sub(0x100)), + &mut accumulator, + &mut list_start_opt + ) + .err() + ), + "Some(InvalidAddress)" + ); + + // Success case: start address is set, element address is specified and valid. + + // Case 1: element falls in the middle of the accumulator. + accumulator.clear(); + // Start by adding 2 elements. + assert!(BootParams::add_boot_parameter_to_list( + &foo, + None, + &mut accumulator, + &mut list_start_opt + ) + .is_ok()); + assert!(BootParams::add_boot_parameter_to_list( + &Foobar { + _foo: [2, 2, 2, 3, 3] + }, + None, + &mut accumulator, + &mut list_start_opt + ) + .is_ok()); + // Sanity check. + #[rustfmt::skip] + assert_eq!( + accumulator, + &[ + 0, 0, 0, 0, 0, // elem 0 + 2, 2, 2, 3, 3, // elem 1 + ] + ); + + // Add a 3rd one that overlaps with the middle of element 1. + assert!(BootParams::add_boot_parameter_to_list( + &Foobar { _foo: [1u8; 5] }, + Some(start.unchecked_add(size_of::() as u64 + 3)), + &mut accumulator, + &mut list_start_opt + ) + .is_ok()); + #[rustfmt::skip] + assert_eq!( + accumulator, + &[ + 0, 0, 0, 0, 0, // elem 0 + 2, 2, 2, // elem 1 cut short + 1, 1, 1, 1, 1, // elem 2 + ] + ); + assert_eq!(accumulator.len(), 13) + } + + #[test] + fn test_bootparams() { + // Test building bootparams from header. + let hdr = DummyHeader::default(); + let hdr_addr = GuestAddress(0x1000); + let mut bootparams = BootParams::new(&hdr, hdr_addr); + assert_eq!(bootparams.header, hdr.as_slice()); + assert_eq!(bootparams.header_start, hdr_addr); + + // Test setting sections. + let sections = vec![DummySection::default(); 2]; + let sections_addr = GuestAddress(0x2000); + bootparams.set_sections::(sections.as_slice(), sections_addr); + assert_eq!( + bootparams.sections, + Some(vec![0u8; 2 * size_of::()]) + ); + assert_eq!(bootparams.sections_start, Some(sections_addr)); + + // Test overwriting sections. + let sections = vec![DummySection::default(); 3]; + let sections_addr = GuestAddress(0x3000); + bootparams.set_sections::(sections.as_slice(), sections_addr); + assert_eq!( + bootparams.sections, + Some(vec![0u8; 3 * size_of::()]) + ); + assert_eq!(bootparams.sections_start, Some(sections_addr)); + + // Test appending a new section. + assert_eq!( + bootparams.add_section::(&DummySection::default(), None), + Ok(sections_addr.unchecked_add(3 * size_of::() as u64)) + ); + assert_eq!( + bootparams.sections, + Some(vec![0u8; 4 * size_of::()]) + ); + assert_eq!(bootparams.sections_start, Some(sections_addr)); + + // Test setting modules. + let modules = vec![DummyModule::default(); 2]; + let modules_addr = GuestAddress(0x4000); + bootparams.set_modules::(modules.as_slice(), modules_addr); + assert_eq!( + bootparams.modules, + Some(vec![0u8; 2 * size_of::()]) + ); + assert_eq!(bootparams.modules_start, Some(modules_addr)); + + // Test overwriting modules. + let modules = vec![DummyModule::default(); 3]; + let modules_addr = GuestAddress(0x5000); + bootparams.set_modules::(modules.as_slice(), modules_addr); + assert_eq!( + bootparams.modules, + Some(vec![0u8; 3 * size_of::()]) + ); + assert_eq!(bootparams.modules_start, Some(modules_addr)); + + // Test appending a new module. + assert_eq!( + bootparams.add_module::(&DummyModule::default(), None), + Ok(modules_addr.unchecked_add(3 * size_of::() as u64)) + ); + + // Test appending a new module of a different type. + assert_eq!( + bootparams.add_module::(&OtherDummyModule::default(), None), + Ok(modules_addr.unchecked_add( + 3 * size_of::() as u64 + size_of::() as u64 + )) + ); } } diff --git a/src/configurator/x86_64/linux.rs b/src/configurator/x86_64/linux.rs index 51a7bcaf..b0b83760 100644 --- a/src/configurator/x86_64/linux.rs +++ b/src/configurator/x86_64/linux.rs @@ -74,10 +74,10 @@ impl BootConfigurator for LinuxBootConfigurator { // The VMM has filled a `boot_params` struct and its e820 map. // This will be written in guest memory at the zero page. guest_memory - .checked_offset(params.header.1, params.header.0.len()) + .checked_offset(params.header_start, params.header.len()) .ok_or(Error::ZeroPagePastRamEnd)?; guest_memory - .write_slice(params.header.0.as_slice(), params.header.1) + .write_slice(params.header.as_slice(), params.header_start) .map_err(|_| Error::ZeroPageSetup)?; Ok(()) @@ -134,7 +134,7 @@ mod tests { ); // Success case. - bootparams.header.1 = zero_page_addr; + bootparams.header_start = zero_page_addr; assert!(LinuxBootConfigurator::write_bootparams::( bootparams, &guest_memory, diff --git a/src/configurator/x86_64/pvh.rs b/src/configurator/x86_64/pvh.rs index af9b2911..1bdac3f4 100644 --- a/src/configurator/x86_64/pvh.rs +++ b/src/configurator/x86_64/pvh.rs @@ -26,6 +26,8 @@ pub struct PvhBootConfigurator {} /// Errors specific to the PVH boot protocol configuration. #[derive(Debug, PartialEq)] pub enum Error { + /// The starting address for the memory map wasn't passed to the boot configurator. + MemmapTableAddressMissing, /// No memory map wasn't passed to the boot configurator. MemmapTableMissing, /// The memory map table extends past the end of guest memory. @@ -42,6 +44,9 @@ impl StdError for Error { fn description(&self) -> &str { use Error::*; match self { + MemmapTableAddressMissing => { + "The starting address for the memory map wasn't passed to the boot configurator." + } MemmapTableMissing => "No memory map was passed to the boot configurator.", MemmapTablePastRamEnd => "The memory map table extends past the end of guest memory.", MemmapTableSetup => "Error writing memory map table to guest memory.", @@ -95,20 +100,22 @@ impl BootConfigurator for PvhBootConfigurator { // The `hvm_start_info` will be written at `addr` and the memmap entries at // `start_info.0.memmap_paddr`. let memmap = params.sections.ok_or(Error::MemmapTableMissing)?; - let header = params.header; + let memmap_addr = params + .sections_start + .ok_or(Error::MemmapTableAddressMissing)?; guest_memory - .checked_offset(memmap.1, memmap.0.len()) + .checked_offset(memmap_addr, memmap.len()) .ok_or(Error::MemmapTablePastRamEnd)?; guest_memory - .write_slice(memmap.0.as_slice(), memmap.1) + .write_slice(memmap.as_slice(), memmap_addr) .map_err(|_| Error::MemmapTableSetup)?; guest_memory - .checked_offset(header.1, header.0.len()) + .checked_offset(params.header_start, params.header.len()) .ok_or(Error::StartInfoPastRamEnd)?; guest_memory - .write_slice(header.0.as_slice(), header.1) + .write_slice(params.header.as_slice(), params.header_start) .map_err(|_| Error::StartInfoSetup)?; Ok(()) @@ -171,8 +178,8 @@ mod tests { let bad_start_info_addr = GuestAddress( guest_memory.last_addr().raw_value() - mem::size_of::() as u64 + 1, ); - boot_params.add_sections::(&memmap_entries, memmap_addr); - boot_params.header.1 = bad_start_info_addr; + boot_params.set_sections::(&memmap_entries, memmap_addr); + boot_params.header_start = bad_start_info_addr; assert_eq!( PvhBootConfigurator::write_bootparams::( boot_params.clone(), @@ -184,12 +191,12 @@ mod tests { // Error case: memory map doesn't fit in guest memory. let himem_start = GuestAddress(0x100000); - boot_params.header.1 = himem_start; + boot_params.header_start = himem_start; let bad_memmap_addr = GuestAddress( guest_memory.last_addr().raw_value() - mem::size_of::() as u64 + 1, ); - boot_params.add_sections::(&memmap_entries, bad_memmap_addr); + boot_params.set_sections::(&memmap_entries, bad_memmap_addr); assert_eq!( PvhBootConfigurator::write_bootparams::( @@ -200,7 +207,7 @@ mod tests { Some(Error::MemmapTablePastRamEnd.into()) ); - boot_params.add_sections::(&memmap_entries, memmap_addr); + boot_params.set_sections::(&memmap_entries, memmap_addr); assert!(PvhBootConfigurator::write_bootparams::( boot_params, &guest_memory,