diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d66b8c0c00..2c624bc06da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - Documentation for Logger API Requests in `docs/api_requests/logger.md`. - Documentation for Actions API Requests in `docs/api_requests/actions.md`. - Documentation for MMDS in `docs/mmds.md`. +- Support for booting from bzImage-format kernels +- Support for loading initrd as well as kernel ### Changed diff --git a/api_server/src/request/boot_source.rs b/api_server/src/request/boot_source.rs index 5f07e22ded9..048022d55e1 100644 --- a/api_server/src/request/boot_source.rs +++ b/api_server/src/request/boot_source.rs @@ -32,10 +32,12 @@ mod tests { fn test_into_parsed_request() { let body = BootSourceConfig { kernel_image_path: String::from("/foo/bar"), + initrd_path: None, boot_args: Some(String::from("foobar")), }; let same_body = BootSourceConfig { kernel_image_path: String::from("/foo/bar"), + initrd_path: None, boot_args: Some(String::from("foobar")), }; let (sender, receiver) = oneshot::channel(); diff --git a/api_server/swagger/firecracker.yaml b/api_server/swagger/firecracker.yaml index d6e711e1f6a..c1194aef5d1 100644 --- a/api_server/swagger/firecracker.yaml +++ b/api_server/swagger/firecracker.yaml @@ -311,6 +311,9 @@ definitions: kernel_image_path: type: string description: Host level path to the kernel image used to boot the guest + initrd_path: + type: string + description: Host level path to the initrd image used to boot the guest boot_args: type: string description: Kernel boot arguments diff --git a/kernel/src/loader/mod.rs b/kernel/src/loader/mod.rs index e182a22f37a..ec95a724f28 100644 --- a/kernel/src/loader/mod.rs +++ b/kernel/src/loader/mod.rs @@ -24,13 +24,20 @@ pub enum Error { CommandLineOverflow, InvalidElfMagicNumber, InvalidEntryAddress, + InvalidLinuxMagicNumber, InvalidProgramHeaderSize, InvalidProgramHeaderOffset, InvalidProgramHeaderAddress, + LinuxNot64Bit, ReadElfHeader, + ReadInitrd, ReadKernelImage, + ReadLinuxHeader, ReadProgramHeader, + SeekInitrd, + SeekKernelEnd, SeekKernelStart, + SeekLinuxHeader, SeekElfStart, SeekProgramHeader, } @@ -44,7 +51,7 @@ pub type Result = std::result::Result; /// * `kernel_image` - Input vmlinux image. /// /// Returns the entry address of the kernel. -pub fn load_kernel(guest_mem: &GuestMemory, kernel_image: &mut F) -> Result +fn load_elf64(guest_mem: &GuestMemory, kernel_image: &mut F) -> Result where F: Read + Seek, { @@ -111,6 +118,66 @@ where Ok(GuestAddress(ehdr.e_entry as usize)) } +/// Loads a kernel from a 64-bit vmlinuz bzImage to a slice +/// +/// # Arguments +/// +/// * `guest_mem` - The guest memory region the kernel is written to. +/// * `kernel_image` - Input vmlinuz image. +/// +/// Returns the entry address of the kernel. +fn load_bzimage(guest_mem: &GuestMemory, kernel_image: &mut F) -> Result +where + F: Read + Seek, +{ + const BZIMAGE_HEADER_OFFSET: u64 = 0x1f1; + const BZIMAGE_HEADER_MAGIC: u32 = 0x53726448; + const BZIMAGE_LOAD_ADDRESS: usize = 0x100000; + const BZIMAGE_64BIT_ENTRY_ADDRESS: usize = BZIMAGE_LOAD_ADDRESS + 0x200; + + let mut header: x86_64::bootparam::setup_header = Default::default(); + + /* Read and check the header. */ + kernel_image + .seek(SeekFrom::Start(BZIMAGE_HEADER_OFFSET)) + .map_err(|_| Error::SeekLinuxHeader)?; + unsafe { + // read_struct is safe when reading a POD struct. It can be used and dropped without issue. + sys_util::read_struct(kernel_image, &mut header).map_err(|_| Error::ReadLinuxHeader)?; + } + if header.header != BZIMAGE_HEADER_MAGIC { + return Err(Error::InvalidLinuxMagicNumber); + } + if (header.xloadflags as u32 & x86_64::bootparam::XLF_KERNEL_64) == 0 { + return Err(Error::LinuxNot64Bit); + } + + /* Find the protected-mode code in the file. */ + let load_bytes = header.syssize as usize * 16; + let load_offset = if header.setup_sects == 0 { + 5 * 512 + } else { + (header.setup_sects as u64 + 1) * 512 + }; + + /* Load it at the default bzImage load address. */ + kernel_image + .seek(SeekFrom::Start(load_offset)) + .map_err(|_| Error::SeekKernelStart)?; + guest_mem + .read_to_memory(GuestAddress(BZIMAGE_LOAD_ADDRESS), kernel_image, load_bytes) + .map_err(|_| Error::ReadKernelImage)?; + + Ok(GuestAddress(BZIMAGE_64BIT_ENTRY_ADDRESS)) +} + +pub fn load_kernel(guest_mem: &GuestMemory, kernel_image: &mut F) -> Result +where + F: Read + Seek, +{ + load_elf64(guest_mem, kernel_image).or_else(|_| load_bzimage(guest_mem, kernel_image)) +} + /// Writes the command line string to the given memory slice. /// /// # Arguments @@ -142,6 +209,37 @@ pub fn load_cmdline( Ok(()) } +/// Loads the initrd from a file into the given memory slice. +/// +/// * `guest_mem` - The guest memory region the initrd is written to. +/// * `initrd_image` - Input initrd image. +/// +/// Returns the entry address of the initrd and its length as a tuple +pub fn load_initrd( + guest_mem: &GuestMemory, + initrd_image: &mut F, +) -> Result<(GuestAddress, usize)> +where + F: Read + Seek, +{ + // This works for bzImage kernels because they load at 1MiB and have 16MiB init space. + // In practice works for many ELF kernels too because they load at 16MiB. + // Ought to have an allocator in guest_mem to find an empty spot. + const INITRD_LOAD_ADDRESS: usize = 0x3000000; // 48 MiB + + let load_bytes = initrd_image + .seek(SeekFrom::End(0)) + .map_err(|_| Error::SeekInitrd)? as usize; + initrd_image + .seek(SeekFrom::Start(0)) + .map_err(|_| Error::SeekInitrd)?; + guest_mem + .read_to_memory(GuestAddress(INITRD_LOAD_ADDRESS), initrd_image, load_bytes) + .map_err(|_| Error::ReadInitrd)?; + + Ok((GuestAddress(INITRD_LOAD_ADDRESS), load_bytes)) +} + #[cfg(test)] mod tests { use super::*; @@ -220,7 +318,7 @@ mod tests { bad_image[0x1] = 0x33; assert_eq!( Err(Error::InvalidElfMagicNumber), - load_kernel(&gm, &mut Cursor::new(&bad_image)) + load_elf64(&gm, &mut Cursor::new(&bad_image)) ); } @@ -232,7 +330,7 @@ mod tests { bad_image[0x5] = 2; assert_eq!( Err(Error::BigEndianElfOnLittle), - load_kernel(&gm, &mut Cursor::new(&bad_image)) + load_elf64(&gm, &mut Cursor::new(&bad_image)) ); } @@ -244,6 +342,45 @@ mod tests { bad_image[0x20] = 0x10; assert_eq!( Err(Error::InvalidProgramHeaderOffset), + load_elf64(&gm, &mut Cursor::new(&bad_image)) + ); + } + + // bare skeleton of a bzImage-compatible file. + fn make_bz() -> Vec { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("test_bzImage.bin")); + v + } + + #[test] + fn load_bz() { + let gm = create_guest_mem(); + let image = make_bz(); + assert_eq!( + Ok(GuestAddress(0x100200)), + load_kernel(&gm, &mut Cursor::new(&image)) + ); + } + + #[test] + fn bad_bz_magic() { + let gm = create_guest_mem(); + let mut bad_image = make_bz(); + bad_image[0x203] = 0x0; + assert_eq!( + Err(Error::InvalidLinuxMagicNumber), + load_kernel(&gm, &mut Cursor::new(&bad_image)) + ); + } + + #[test] + fn bad_bz_32bit() { + let gm = create_guest_mem(); + let mut bad_image = make_bz(); + bad_image[0x236] = 0x2; + assert_eq!( + Err(Error::LinuxNot64Bit), load_kernel(&gm, &mut Cursor::new(&bad_image)) ); } diff --git a/kernel/src/loader/test_bzImage.bin b/kernel/src/loader/test_bzImage.bin new file mode 100644 index 00000000000..f0521a668e6 Binary files /dev/null and b/kernel/src/loader/test_bzImage.bin differ diff --git a/tests/README.md b/tests/README.md index a6258e93b6f..2d0bf52417c 100644 --- a/tests/README.md +++ b/tests/README.md @@ -76,7 +76,7 @@ Tests can be added in any (existing or new) sub-directory of `tests/`, in files named `test_*.py`. Fixtures can be used to quickly build Firecracker microvm integration tests -that run on all microvm images in `s3://spec.firecracker/microvm-images/`. +that run on all microvm images in `s3://spec.ccfc.min/img/`. For example, the test below makes use of the `test_microvm_any` fixture and will be run on every microvm image in the bucket, each as a separate test case. @@ -102,14 +102,15 @@ To see what fixtures are available, inspect `conftest.py`. ## Adding Microvm Images -Simply place the microvm image under `s3://spec.firecracker/microvm-images/`. +Simply place the microvm image under `s3://spec.ccfc.min/img/`. The layout is: ``` tree -s3:///microvm-images/ +s3:///img/ / kernel/ vmlinux.bin + initrd.img fsfiles/ rootfs.ext4 @@ -119,7 +120,7 @@ s3:///microvm-images/ ... ``` -Then, tag `` with: +Then, tag `/` with: ``` json TagSet = [{"key": "capability:", "value": ""}, ...] diff --git a/tests/framework/microvm.py b/tests/framework/microvm.py index 91fa6c01656..f80531619d1 100644 --- a/tests/framework/microvm.py +++ b/tests/framework/microvm.py @@ -54,7 +54,8 @@ def __init__( self._kernel_path = os.path.join(self._path, MICROVM_KERNEL_RELPATH) self._fsfiles_path = os.path.join(self._path, MICROVM_FSFILES_RELPATH) self._kernel_file = '' - self._rootfs_file = '' + self._initrd_file = None + self._rootfs_file = None # The binaries this microvm will use to start. self._fc_binary_path = fc_binary_path @@ -156,6 +157,16 @@ def kernel_file(self, path): """Set the path to the kernel file.""" self._kernel_file = path + @property + def initrd_file(self): + """Return the name of the initrd file used by this microVM to boot.""" + return self._initrd_file + + @initrd_file.setter + def initrd_file(self, path): + """Set the path to the initrd file.""" + self._initrd_file = path + @property def rootfs_file(self): """Return the path to the image this microVM can boot into.""" @@ -204,6 +215,7 @@ def setup(self): / kernel/ + .... fsfiles/ @@ -328,12 +340,18 @@ def basic_config( ) # Add a kernel to start booting from. - response = self.boot.put( - kernel_image_path=self.create_jailed_resource(self.kernel_file) - ) + if self.initrd_file is not None: + response = self.boot.put( + initrd_path=self.create_jailed_resource(self.initrd_file), + kernel_image_path=self.create_jailed_resource(self.kernel_file) + ) + else: + response = self.boot.put( + kernel_image_path=self.create_jailed_resource(self.kernel_file) + ) assert self._api_session.is_good_response(response.status_code) - if add_root_device: + if add_root_device and self.rootfs_file is not None: # Add the root file system with rw permissions. response = self.drive.put( drive_id='rootfs', diff --git a/tests/framework/resources.py b/tests/framework/resources.py index db13cd37d0b..52f9a884028 100644 --- a/tests/framework/resources.py +++ b/tests/framework/resources.py @@ -88,12 +88,15 @@ def get(cls): @staticmethod def create_json( boot_args=None, - kernel_image_path=None + kernel_image_path=None, + initrd_path=None ): """Compose the json associated to this type of API request.""" datax = {} if kernel_image_path is not None: datax['kernel_image_path'] = kernel_image_path + if initrd_path is not None: + datax['initrd_path'] = initrd_path if boot_args is not None: datax['boot_args'] = boot_args return datax diff --git a/tests/framework/s3fetcher.py b/tests/framework/s3fetcher.py index 31b5515bcf9..c9bd8d66cb7 100644 --- a/tests/framework/s3fetcher.py +++ b/tests/framework/s3fetcher.py @@ -56,6 +56,7 @@ class MicrovmImageS3Fetcher: MICROVM_IMAGE_KERNEL_RELPATH = 'kernel/' MICROVM_IMAGE_BLOCKDEV_RELPATH = 'fsfiles/' MICROVM_IMAGE_KERNEL_FILE_SUFFIX = r'vmlinux.bin' + MICROVM_IMAGE_INITRD_FILE_SUFFIX = r'initrd.img' MICROVM_IMAGE_ROOTFS_FILE_SUFFIX = r'rootfs.ext4' MICROVM_IMAGE_SSH_KEY_SUFFIX = r'.id_rsa' @@ -166,6 +167,9 @@ def get_microvm_image(self, microvm_image_name, microvm): if resource_key.endswith(self.MICROVM_IMAGE_KERNEL_FILE_SUFFIX): microvm.kernel_file = microvm_dest_path + if resource_key.endswith(self.MICROVM_IMAGE_INITRD_FILE_SUFFIX): + microvm.initrd_file = microvm_dest_path + if resource_key.endswith(self.MICROVM_IMAGE_ROOTFS_FILE_SUFFIX): microvm.rootfs_file = microvm_dest_path diff --git a/tests/integration_tests/performance/test_boottime.py b/tests/integration_tests/performance/test_boottime.py index dddf51a9bf1..1d6c98312ba 100644 --- a/tests/integration_tests/performance/test_boottime.py +++ b/tests/integration_tests/performance/test_boottime.py @@ -12,6 +12,8 @@ # The maximum acceptable boot time in us. MAX_BOOT_TIME_US = 150000 +MAX_BZIMAGE_BOOT_TIME_US = 1000000 +MAX_INITRD_BOOT_TIME_US = 2000000 # TODO: Keep a `current` boot time in S3 and validate we don't regress # Regex for obtaining boot time from some string. TIMESTAMP_LOG_REGEX = r'Guest-boot-time\s+\=\s+(\d+)\s+us' @@ -20,7 +22,11 @@ @pytest.mark.timeout(120) def test_microvm_boottime_no_network(test_microvm_with_boottime): """Check guest boottime of microvm without network.""" - boottime_us = _test_microvm_boottime(test_microvm_with_boottime, None) + boottime_us = _test_microvm_boottime( + test_microvm_with_boottime, + None, + MAX_BOOT_TIME_US + ) print("Boot time with no network is: " + str(boottime_us) + " us") @@ -31,14 +37,36 @@ def test_microvm_boottime_with_network( """Check guest boottime of microvm with network.""" boottime_us = _test_microvm_boottime( test_microvm_with_boottime, - network_config + network_config, + MAX_BOOT_TIME_US ) print("Boot time with network configured is: " + str(boottime_us) + " us") +def test_microvm_boottime_bzimage(test_microvm_with_bzimage): + """Check guest boottime of microvm from bzImage kernel.""" + boottime_us = _test_microvm_boottime( + test_microvm_with_bzimage, + None, + MAX_BZIMAGE_BOOT_TIME_US + ) + print("Boot time with bzimage is: " + str(boottime_us) + " us") + + +def test_microvm_boottime_initrd(test_microvm_with_initrd): + """Check guest boottime of microvm with initrd.""" + boottime_us = _test_microvm_boottime( + test_microvm_with_initrd, + None, + MAX_INITRD_BOOT_TIME_US + ) + print("Boot time with initrd is: " + str(boottime_us) + " us") + + def _test_microvm_boottime( microvm, - net_config + net_config, + time_limit_us ): """Assert that we meet the minimum boot time. @@ -69,7 +97,7 @@ def _test_microvm_boottime( assert microvm.api_session.is_good_response(response.status_code) microvm.start() - time.sleep(0.4) + time.sleep(0.25 + time_limit_us / 1000000.0) lines = log_fifo.sequential_reader(20) boot_time_us = 0 @@ -79,5 +107,5 @@ def _test_microvm_boottime( boot_time_us = int(timestamps[0]) assert boot_time_us > 0 - assert boot_time_us < MAX_BOOT_TIME_US + assert boot_time_us < time_limit_us return boot_time_us diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 0b01fd4363d..73cc12daa47 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -509,6 +509,7 @@ impl Drop for EpollContext { struct KernelConfig { cmdline: kernel_cmdline::Cmdline, kernel_file: File, + initrd_file: Option, cmdline_addr: GuestAddress, } @@ -1056,6 +1057,13 @@ impl Vmm { .map_err(|e| StartMicrovmError::Loader(e))?; kernel_loader::load_cmdline(vm_memory, kernel_config.cmdline_addr, &cmdline_cstring) .map_err(|e| StartMicrovmError::Loader(e))?; + let (initrd_addr, initrd_size) = + if let Some(ref mut initrd_file) = kernel_config.initrd_file { + kernel_loader::load_initrd(vm_memory, initrd_file) + .map_err(|e| StartMicrovmError::Loader(e))? + } else { + (GuestAddress(0), 0) + }; // The vcpu_count has a default value. We shouldn't have gotten to this point without // having set the vcpu count. @@ -1067,6 +1075,8 @@ impl Vmm { vm_memory, kernel_config.cmdline_addr, cmdline_cstring.to_bytes().len() + 1, + initrd_addr, + initrd_size, vcpu_count, ) .map_err(|e| StartMicrovmError::ConfigureSystem(e))?; @@ -1352,6 +1362,7 @@ impl Vmm { fn configure_boot_source( &mut self, kernel_image_path: String, + initrd_path: Option, kernel_cmdline: Option, ) -> std::result::Result { if self.is_instance_initialized() { @@ -1364,6 +1375,19 @@ impl Vmm { let kernel_file = File::open(kernel_image_path).map_err(|_| { VmmActionError::BootSource(ErrorKind::User, BootSourceConfigError::InvalidKernelPath) })?; + + let initrd_file = match initrd_path { + None => None, + Some(path) => Some({ + File::open(path).map_err(|_| { + VmmActionError::BootSource( + ErrorKind::User, + BootSourceConfigError::InvalidInitrdPath, + ) + })? + }), + }; + let mut cmdline = kernel_cmdline::Cmdline::new(x86_64::layout::CMDLINE_MAX_SIZE); cmdline .insert_str(kernel_cmdline.unwrap_or(String::from(DEFAULT_KERNEL_CMDLINE))) @@ -1376,6 +1400,7 @@ impl Vmm { let kernel_config = KernelConfig { kernel_file, + initrd_file, cmdline, cmdline_addr: GuestAddress(x86_64::layout::CMDLINE_START), }; @@ -1668,6 +1693,7 @@ impl Vmm { Vmm::send_response( self.configure_boot_source( boot_source_body.kernel_image_path, + boot_source_body.initrd_path, boot_source_body.boot_args, ), sender, @@ -1835,6 +1861,7 @@ mod tests { let kernel_cfg = KernelConfig { cmdline, kernel_file, + initrd_file: None, cmdline_addr: GuestAddress(x86_64::layout::CMDLINE_START), }; self.configure_kernel(kernel_cfg); @@ -2357,6 +2384,7 @@ mod tests { cmdline_addr: dummy_addr, cmdline: kernel_cmdline::Cmdline::new(10), kernel_file: tempfile::tempfile().unwrap(), + initrd_file: None, }); assert!(vmm.check_health().is_ok()); } @@ -2524,28 +2552,44 @@ mod tests { // Test invalid kernel path. assert!(vmm - .configure_boot_source(String::from("dummy-path"), None) + .configure_boot_source(String::from("dummy-path"), None, None) .is_err()); // Test valid kernel path and invalid cmdline. let kernel_file = NamedTempFile::new().expect("Failed to create temporary kernel file."); let kernel_path = String::from(kernel_file.path().to_path_buf().to_str().unwrap()); + let initrd_file = NamedTempFile::new().expect("Failed to create temporary initrd file."); + let initrd_path = String::from(initrd_file.path().to_path_buf().to_str().unwrap()); let invalid_cmdline = String::from_utf8(vec![b'X'; x86_64::layout::CMDLINE_MAX_SIZE + 1]).unwrap(); assert!(vmm - .configure_boot_source(kernel_path.clone(), Some(invalid_cmdline)) + .configure_boot_source(kernel_path.clone(), None, Some(invalid_cmdline)) .is_err()); // Test valid configuration. - assert!(vmm.configure_boot_source(kernel_path.clone(), None).is_ok()); assert!(vmm - .configure_boot_source(kernel_path.clone(), Some(String::from("reboot=k"))) + .configure_boot_source(kernel_path.clone(), None, None) + .is_ok()); + assert!(vmm + .configure_boot_source(kernel_path.clone(), None, Some(String::from("reboot=k"))) + .is_ok()); + + // Test valid configuration + initrd. + assert!(vmm + .configure_boot_source(kernel_path.clone(), Some(initrd_path.clone()), None) + .is_ok()); + assert!(vmm + .configure_boot_source( + kernel_path.clone(), + Some(initrd_path.clone()), + Some(String::from("reboot=k")) + ) .is_ok()); // Test valid configuration after boot (should fail). vmm.set_instance_state(InstanceState::Running); assert!(vmm - .configure_boot_source(kernel_path.clone(), None) + .configure_boot_source(kernel_path.clone(), None, None) .is_err()); } diff --git a/vmm/src/vmm_config/boot_source.rs b/vmm/src/vmm_config/boot_source.rs index de9d19e69d1..6f786e0e6ca 100644 --- a/vmm/src/vmm_config/boot_source.rs +++ b/vmm/src/vmm_config/boot_source.rs @@ -10,6 +10,8 @@ use std::fmt::{Display, Formatter, Result}; pub struct BootSourceConfig { /// Path of the kernel image. pub kernel_image_path: String, + /// Path of the initrd, if there is one. + pub initrd_path: Option, /// The boot arguments to pass to the kernel. If this field is uninitialized, the default /// kernel command line is used: `reboot=k panic=1 pci=off nomodules 8250.nr_uarts=0`. #[serde(skip_serializing_if = "Option::is_none")] @@ -21,6 +23,8 @@ pub struct BootSourceConfig { pub enum BootSourceConfigError { /// The kernel file cannot be opened. InvalidKernelPath, + /// The initrd file cannot be opened. + InvalidInitrdPath, /// The kernel command line is invalid. InvalidKernelCommandLine, /// The boot source cannot be update post boot. @@ -36,6 +40,11 @@ impl Display for BootSourceConfigError { "The kernel file cannot be opened due to invalid kernel path or \ invalid permissions.", ), + InvalidInitrdPath => write!( + f, + "The initrd file cannot be opened due to invalid path or \ + invalid permissions.", + ), InvalidKernelCommandLine => write!(f, "The kernel command line is invalid!"), UpdateNotAllowedPostBoot => { write!(f, "The update operation is not allowed after boot.") diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 59a76a8c2ba..8b94cbb6285 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -16,7 +16,7 @@ extern crate sys_util; #[allow(non_upper_case_globals)] #[allow(non_camel_case_types)] #[allow(non_snake_case)] -mod bootparam; +pub mod bootparam; // boot_params is just a series of ints, it is safe to initialize it. unsafe impl memory_model::DataInit for bootparam::boot_params {} @@ -114,12 +114,16 @@ pub fn configure_system( guest_mem: &GuestMemory, cmdline_addr: GuestAddress, cmdline_size: usize, + initrd_addr: GuestAddress, + initrd_size: usize, num_cpus: u8, ) -> Result<()> { const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; const KERNEL_HDR_MAGIC: u32 = 0x53726448; const KERNEL_LOADER_OTHER: u8 = 0xff; + /* These should come from the kernel's own header */ const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000; // Must be non-zero. + const KERNEL_INIT_SIZE: u32 = 0x1000000; // Must be non-zero. let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS); let end_32bit_gap_start = GuestAddress(get_32bit_gap_start()); @@ -136,6 +140,9 @@ pub fn configure_system( params.hdr.cmd_line_ptr = cmdline_addr.offset() as u32; params.hdr.cmdline_size = cmdline_size as u32; params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES; + params.hdr.init_size = KERNEL_INIT_SIZE; + params.hdr.ramdisk_image = initrd_addr.offset() as u32; + params.hdr.ramdisk_size = initrd_size as u32; add_e820_entry(&mut params, 0, layout::EBDA_START, E820_RAM)?; @@ -223,25 +230,25 @@ mod tests { fn test_system_configuration() { let no_vcpus = 4; let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); - assert!(configure_system(&gm, GuestAddress(0), 0, 1).is_err()); + assert!(configure_system(&gm, GuestAddress(0), 0, GuestAddress(0), 0, 1).is_err()); // Now assigning some memory that falls before the 32bit memory hole. let mem_size = 128 << 20; let arch_mem_regions = arch_memory_regions(mem_size); let gm = GuestMemory::new(&arch_mem_regions).unwrap(); - configure_system(&gm, GuestAddress(0), 0, no_vcpus).unwrap(); + configure_system(&gm, GuestAddress(0), 0, GuestAddress(0), 0, no_vcpus).unwrap(); // Now assigning some memory that is equal to the start of the 32bit memory hole. let mem_size = 3328 << 20; let arch_mem_regions = arch_memory_regions(mem_size); let gm = GuestMemory::new(&arch_mem_regions).unwrap(); - configure_system(&gm, GuestAddress(0), 0, no_vcpus).unwrap(); + configure_system(&gm, GuestAddress(0), 0, GuestAddress(0), 0, no_vcpus).unwrap(); // Now assigning some memory that falls after the 32bit memory hole. let mem_size = 3330 << 20; let arch_mem_regions = arch_memory_regions(mem_size); let gm = GuestMemory::new(&arch_mem_regions).unwrap(); - configure_system(&gm, GuestAddress(0), 0, no_vcpus).unwrap(); + configure_system(&gm, GuestAddress(0), 0, GuestAddress(0), 0, no_vcpus).unwrap(); } #[test]