diff --git a/src/cli/config/config.template.yaml b/src/cli/config/config.template.yaml index 59baa6b..73dfaad 100644 --- a/src/cli/config/config.template.yaml +++ b/src/cli/config/config.template.yaml @@ -1,4 +1,4 @@ language: rust -env_path: /home/charley/polytech/cloudlet/src/cli/config/example.env -code_path: /home/charley/polytech/cloudlet/src/cli/src/main.rs +env_path: /path/cloudlet/src/cli/config/example.env +code_path: /path/cloudlet/src/cli/src/main.rs log_level: debug diff --git a/src/vmm/src/args.rs b/src/vmm/src/args.rs index 0c694b8..fcfca2d 100644 --- a/src/vmm/src/args.rs +++ b/src/vmm/src/args.rs @@ -13,6 +13,10 @@ pub struct CliArguments { #[arg(short, long, env)] pub kernel: PathBuf, + /// Path to the cpio archive to use as the initramfs. + #[arg(short, long, env)] + pub initramfs: Option, + /// Number of virtual CPUs assigned to the guest. #[clap(short, long, env, default_value = "1")] pub cpus: u8, diff --git a/src/vmm/src/core/kernel.rs b/src/vmm/src/core/kernel.rs index b9e66ec..c9b82ea 100644 --- a/src/vmm/src/core/kernel.rs +++ b/src/vmm/src/core/kernel.rs @@ -7,10 +7,10 @@ use linux_loader::bootparam::boot_params; use linux_loader::cmdline::Cmdline; use linux_loader::configurator::{linux::LinuxBootConfigurator, BootConfigurator, BootParams}; use linux_loader::loader::{elf::Elf, load_cmdline, KernelLoader, KernelLoaderResult}; -use std::fs::File; +use std::fs::{self, File}; use std::path::PathBuf; use std::result; -use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryMmap}; +use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap}; // x86_64 boot constants. See https://www.kernel.org/doc/Documentation/x86/boot.txt for the full // documentation. @@ -98,6 +98,25 @@ pub fn build_bootparams( Ok(params) } +/// Load the initramfs into guest memory. Returns a tuple containing the address +/// where the initramfs was loaded, and its size. +/// +/// # Arguments +/// +/// * `guest_memory` - guest memory +/// * `start_addr` - the address where to start looking for a place to store the initramfs +/// * `data` - the initramfs data +fn load_initramfs(mem: &GuestMemoryMmap, start_addr: u64, data: Vec) -> Result<(u32, u32)> { + let addr = GuestAddress(start_addr); + + mem.checked_offset(addr, data.len()) + .ok_or(Error::InitramfsLoad)?; + mem.write_slice(data.as_slice(), addr) + .map_err(|_| Error::InitramfsLoad)?; + + Ok((addr.raw_value() as u32, data.len() as u32)) +} + /// Set guest kernel up. /// /// # Arguments @@ -107,6 +126,7 @@ pub fn build_bootparams( pub fn kernel_setup( guest_memory: &GuestMemoryMmap, kernel_path: PathBuf, + initramfs_path: Option, ) -> Result { let mut kernel_image = File::open(kernel_path).map_err(Error::IO)?; let zero_page_addr = GuestAddress(ZEROPG_START); @@ -138,6 +158,18 @@ pub fn kernel_setup( ) .map_err(Error::KernelLoad)?; + // Handle the initramfs. + if let Some(initramfs_path) = initramfs_path { + // Load the initramfs into guest memory. + let initramfs = fs::read(initramfs_path).map_err(Error::IO)?; + let (initramfs_addr, initramfs_size) = + load_initramfs(guest_memory, kernel_load.kernel_end, initramfs)?; + + // Add the initramfs to the boot parameters. + bootparams.hdr.ramdisk_image = initramfs_addr; + bootparams.hdr.ramdisk_size = initramfs_size; + } + // Write the boot parameters in the zeropage. LinuxBootConfigurator::write_bootparams::( &BootParams::new::(&bootparams, zero_page_addr), diff --git a/src/vmm/src/core/mod.rs b/src/vmm/src/core/mod.rs index abdad5e..34531ac 100644 --- a/src/vmm/src/core/mod.rs +++ b/src/vmm/src/core/mod.rs @@ -27,6 +27,8 @@ pub enum Error { Cmdline(linux_loader::cmdline::Error), /// Failed to load kernel. KernelLoad(loader::Error), + /// Failed to load the initramfs. + InitramfsLoad, /// Invalid E820 configuration. E820Configuration, /// Highmem start address is past the guest memory end. diff --git a/src/vmm/src/core/vmm.rs b/src/vmm/src/core/vmm.rs index 5b8e21e..023dbfb 100644 --- a/src/vmm/src/core/vmm.rs +++ b/src/vmm/src/core/vmm.rs @@ -12,7 +12,7 @@ use std::io; use std::net::Ipv4Addr; use std::os::unix::io::AsRawFd; use std::os::unix::prelude::RawFd; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use std::thread; use tracing::info; @@ -214,9 +214,20 @@ impl VMM { /// * `num_vcpus` Number of virtual CPUs /// * `mem_size_mb` Memory size (in MB) /// * `kernel_path` Path to a Linux kernel - pub fn configure(&mut self, num_vcpus: u8, mem_size_mb: u32, kernel_path: &Path) -> Result<()> { + /// * `initramfs_path` Path to an initramfs + pub fn configure( + &mut self, + num_vcpus: u8, + mem_size_mb: u32, + kernel_path: &Path, + initramfs_path: &Option, + ) -> Result<()> { self.configure_memory(mem_size_mb)?; - let kernel_load = kernel::kernel_setup(&self.guest_memory, kernel_path.to_path_buf())?; + let kernel_load = kernel::kernel_setup( + &self.guest_memory, + kernel_path.to_path_buf(), + initramfs_path.clone(), + )?; self.configure_io()?; self.configure_vcpus(num_vcpus, kernel_load)?; diff --git a/src/vmm/src/main.rs b/src/vmm/src/main.rs index 7599367..c0f008d 100644 --- a/src/vmm/src/main.rs +++ b/src/vmm/src/main.rs @@ -30,7 +30,7 @@ fn main() -> Result<(), Error> { let mut vmm = VMM::new(args.network_host_ip, args.network_host_netmask).map_err(Error::VmmNew)?; - vmm.configure(args.cpus, args.memory, &args.kernel) + vmm.configure(args.cpus, args.memory, &args.kernel, &args.initramfs) .map_err(Error::VmmConfigure)?; // Run the VMM