mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-21 15:31:15 +00:00
arch: load initramfs and populate zero page
* load the initramfs File into the guest memory, aligned to page size * finally setup the initramfs address and its size into the boot params (in configure_64bit_boot) Signed-off-by: Damjan Georgievski <gdamjan@gmail.com>
This commit is contained in:
parent
1f9bc68c54
commit
6cce7b9560
@ -41,6 +41,8 @@ pub enum Error {
|
|||||||
StartInfoPastRamEnd,
|
StartInfoPastRamEnd,
|
||||||
/// Error writing hvm_start_info to guest memory.
|
/// Error writing hvm_start_info to guest memory.
|
||||||
StartInfoSetup,
|
StartInfoSetup,
|
||||||
|
/// Failed to compute initramfs address.
|
||||||
|
InitramfsAddress,
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
@ -76,8 +78,8 @@ pub mod x86_64;
|
|||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86_64::{
|
pub use x86_64::{
|
||||||
arch_memory_regions, configure_system, layout, layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START,
|
arch_memory_regions, configure_system, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||||
BootProtocol, EntryPoint,
|
layout::CMDLINE_START, BootProtocol, EntryPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||||
@ -86,3 +88,11 @@ fn pagesize() -> usize {
|
|||||||
// Trivially safe
|
// Trivially safe
|
||||||
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Type for passing information about the initramfs in the guest memory.
|
||||||
|
pub struct InitramfsConfig {
|
||||||
|
/// Load address of initramfs in guest memory
|
||||||
|
pub address: vm_memory::GuestAddress,
|
||||||
|
/// Size of initramfs in guest memory
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
@ -13,12 +13,14 @@ pub mod layout;
|
|||||||
mod mptable;
|
mod mptable;
|
||||||
pub mod regs;
|
pub mod regs;
|
||||||
|
|
||||||
|
use crate::InitramfsConfig;
|
||||||
use crate::RegionType;
|
use crate::RegionType;
|
||||||
use linux_loader::loader::bootparam::{boot_params, setup_header};
|
use linux_loader::loader::bootparam::{boot_params, setup_header};
|
||||||
use linux_loader::loader::start_info::{hvm_memmap_table_entry, hvm_start_info};
|
use linux_loader::loader::start_info::{hvm_memmap_table_entry, hvm_start_info};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestUsize,
|
Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion,
|
||||||
|
GuestUsize,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
@ -151,6 +153,7 @@ pub fn configure_system(
|
|||||||
guest_mem: &GuestMemoryMmap,
|
guest_mem: &GuestMemoryMmap,
|
||||||
cmdline_addr: GuestAddress,
|
cmdline_addr: GuestAddress,
|
||||||
cmdline_size: usize,
|
cmdline_size: usize,
|
||||||
|
initramfs: &Option<InitramfsConfig>,
|
||||||
num_cpus: u8,
|
num_cpus: u8,
|
||||||
setup_hdr: Option<setup_header>,
|
setup_hdr: Option<setup_header>,
|
||||||
rsdp_addr: Option<GuestAddress>,
|
rsdp_addr: Option<GuestAddress>,
|
||||||
@ -164,7 +167,14 @@ pub fn configure_system(
|
|||||||
configure_pvh(guest_mem, cmdline_addr, rsdp_addr)?;
|
configure_pvh(guest_mem, cmdline_addr, rsdp_addr)?;
|
||||||
}
|
}
|
||||||
BootProtocol::LinuxBoot => {
|
BootProtocol::LinuxBoot => {
|
||||||
configure_64bit_boot(guest_mem, cmdline_addr, cmdline_size, setup_hdr, rsdp_addr)?;
|
configure_64bit_boot(
|
||||||
|
guest_mem,
|
||||||
|
cmdline_addr,
|
||||||
|
cmdline_size,
|
||||||
|
initramfs,
|
||||||
|
setup_hdr,
|
||||||
|
rsdp_addr,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,6 +303,7 @@ fn configure_64bit_boot(
|
|||||||
guest_mem: &GuestMemoryMmap,
|
guest_mem: &GuestMemoryMmap,
|
||||||
cmdline_addr: GuestAddress,
|
cmdline_addr: GuestAddress,
|
||||||
cmdline_size: usize,
|
cmdline_size: usize,
|
||||||
|
initramfs: &Option<InitramfsConfig>,
|
||||||
setup_hdr: Option<setup_header>,
|
setup_hdr: Option<setup_header>,
|
||||||
rsdp_addr: Option<GuestAddress>,
|
rsdp_addr: Option<GuestAddress>,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
@ -319,6 +330,11 @@ fn configure_64bit_boot(
|
|||||||
params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
|
params.0.hdr.cmd_line_ptr = cmdline_addr.raw_value() as u32;
|
||||||
params.0.hdr.cmdline_size = cmdline_size as u32;
|
params.0.hdr.cmdline_size = cmdline_size as u32;
|
||||||
|
|
||||||
|
if let Some(initramfs_config) = initramfs {
|
||||||
|
params.0.hdr.ramdisk_image = initramfs_config.address.raw_value() as u32;
|
||||||
|
params.0.hdr.ramdisk_size = initramfs_config.size as u32;
|
||||||
|
}
|
||||||
|
|
||||||
add_e820_entry(&mut params.0, 0, layout::EBDA_START.raw_value(), E820_RAM)?;
|
add_e820_entry(&mut params.0, 0, layout::EBDA_START.raw_value(), E820_RAM)?;
|
||||||
|
|
||||||
let mem_end = guest_mem.last_addr();
|
let mem_end = guest_mem.last_addr();
|
||||||
@ -388,6 +404,25 @@ fn add_e820_entry(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the memory address where the initramfs could be loaded.
|
||||||
|
pub fn initramfs_load_addr(
|
||||||
|
guest_mem: &GuestMemoryMmap,
|
||||||
|
initramfs_size: usize,
|
||||||
|
) -> super::Result<u64> {
|
||||||
|
let first_region = guest_mem
|
||||||
|
.find_region(GuestAddress::new(0))
|
||||||
|
.ok_or(super::Error::InitramfsAddress)?;
|
||||||
|
// It's safe to cast to usize because the size of a region can't be greater than usize.
|
||||||
|
let lowmem_size = first_region.len() as usize;
|
||||||
|
|
||||||
|
if lowmem_size < initramfs_size {
|
||||||
|
return Err(super::Error::InitramfsAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
let aligned_addr: u64 = ((lowmem_size - initramfs_size) & !(crate::pagesize() - 1)) as u64;
|
||||||
|
Ok(aligned_addr)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -417,6 +452,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -437,6 +473,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -448,6 +485,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -468,6 +506,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -479,6 +518,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -499,6 +539,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -510,6 +551,7 @@ mod tests {
|
|||||||
&gm,
|
&gm,
|
||||||
GuestAddress(0),
|
GuestAddress(0),
|
||||||
0,
|
0,
|
||||||
|
&None,
|
||||||
no_vcpus,
|
no_vcpus,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -38,9 +38,10 @@ use kvm_ioctls::*;
|
|||||||
use linux_loader::cmdline::Cmdline;
|
use linux_loader::cmdline::Cmdline;
|
||||||
use linux_loader::loader::KernelLoader;
|
use linux_loader::loader::KernelLoader;
|
||||||
use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH};
|
use signal_hook::{iterator::Signals, SIGINT, SIGTERM, SIGWINCH};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io::{self, Seek, SeekFrom};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
@ -78,9 +79,15 @@ pub enum Error {
|
|||||||
/// Cannot open the kernel image
|
/// Cannot open the kernel image
|
||||||
KernelFile(io::Error),
|
KernelFile(io::Error),
|
||||||
|
|
||||||
|
/// Cannot open the initramfs image
|
||||||
|
InitramfsFile(io::Error),
|
||||||
|
|
||||||
/// Cannot load the kernel in memory
|
/// Cannot load the kernel in memory
|
||||||
KernelLoad(linux_loader::loader::Error),
|
KernelLoad(linux_loader::loader::Error),
|
||||||
|
|
||||||
|
/// Cannot load the initramfs in memory
|
||||||
|
InitramfsLoad,
|
||||||
|
|
||||||
/// Cannot load the command line in memory
|
/// Cannot load the command line in memory
|
||||||
LoadCmdLine(linux_loader::loader::Error),
|
LoadCmdLine(linux_loader::loader::Error),
|
||||||
|
|
||||||
@ -219,6 +226,7 @@ impl VmState {
|
|||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
kernel: File,
|
kernel: File,
|
||||||
|
initramfs: Option<File>,
|
||||||
threads: Vec<thread::JoinHandle<()>>,
|
threads: Vec<thread::JoinHandle<()>>,
|
||||||
device_manager: Arc<Mutex<DeviceManager>>,
|
device_manager: Arc<Mutex<DeviceManager>>,
|
||||||
config: Arc<Mutex<VmConfig>>,
|
config: Arc<Mutex<VmConfig>>,
|
||||||
@ -254,6 +262,11 @@ impl Vm {
|
|||||||
let kernel = File::open(&config.lock().unwrap().kernel.as_ref().unwrap().path)
|
let kernel = File::open(&config.lock().unwrap().kernel.as_ref().unwrap().path)
|
||||||
.map_err(Error::KernelFile)?;
|
.map_err(Error::KernelFile)?;
|
||||||
|
|
||||||
|
let initramfs = match &config.lock().unwrap().initramfs {
|
||||||
|
Some(initramfs) => Some(File::open(&initramfs.path).map_err(Error::InitramfsFile)?),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let fd: VmFd;
|
let fd: VmFd;
|
||||||
loop {
|
loop {
|
||||||
match kvm.create_vm() {
|
match kvm.create_vm() {
|
||||||
@ -377,6 +390,7 @@ impl Vm {
|
|||||||
|
|
||||||
Ok(Vm {
|
Ok(Vm {
|
||||||
kernel,
|
kernel,
|
||||||
|
initramfs,
|
||||||
device_manager,
|
device_manager,
|
||||||
config,
|
config,
|
||||||
on_tty,
|
on_tty,
|
||||||
@ -388,6 +402,28 @@ impl Vm {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_initramfs(&mut self, guest_mem: &GuestMemoryMmap) -> Result<arch::InitramfsConfig> {
|
||||||
|
let mut initramfs = self.initramfs.as_ref().unwrap();
|
||||||
|
let size: usize = initramfs
|
||||||
|
.seek(SeekFrom::End(0))
|
||||||
|
.map_err(|_| Error::InitramfsLoad)?
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
initramfs
|
||||||
|
.seek(SeekFrom::Start(0))
|
||||||
|
.map_err(|_| Error::InitramfsLoad)?;
|
||||||
|
|
||||||
|
let address =
|
||||||
|
arch::initramfs_load_addr(guest_mem, size).map_err(|_| Error::InitramfsLoad)?;
|
||||||
|
let address = GuestAddress(address);
|
||||||
|
|
||||||
|
guest_mem
|
||||||
|
.read_from(address, &mut initramfs, size)
|
||||||
|
.map_err(|_| Error::InitramfsLoad)?;
|
||||||
|
|
||||||
|
Ok(arch::InitramfsConfig { address, size })
|
||||||
|
}
|
||||||
|
|
||||||
fn load_kernel(&mut self) -> Result<EntryPoint> {
|
fn load_kernel(&mut self) -> Result<EntryPoint> {
|
||||||
let mut cmdline = Cmdline::new(arch::CMDLINE_MAX_SIZE);
|
let mut cmdline = Cmdline::new(arch::CMDLINE_MAX_SIZE);
|
||||||
cmdline
|
cmdline
|
||||||
@ -425,6 +461,12 @@ impl Vm {
|
|||||||
&cmdline_cstring,
|
&cmdline_cstring,
|
||||||
)
|
)
|
||||||
.map_err(Error::LoadCmdLine)?;
|
.map_err(Error::LoadCmdLine)?;
|
||||||
|
|
||||||
|
let initramfs_config = match self.initramfs {
|
||||||
|
Some(_) => Some(self.load_initramfs(mem.deref())?),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus();
|
let boot_vcpus = self.cpu_manager.lock().unwrap().boot_vcpus();
|
||||||
let _max_vcpus = self.cpu_manager.lock().unwrap().max_vcpus();
|
let _max_vcpus = self.cpu_manager.lock().unwrap().max_vcpus();
|
||||||
|
|
||||||
@ -447,6 +489,7 @@ impl Vm {
|
|||||||
&mem,
|
&mem,
|
||||||
arch::layout::CMDLINE_START,
|
arch::layout::CMDLINE_START,
|
||||||
cmdline_cstring.to_bytes().len() + 1,
|
cmdline_cstring.to_bytes().len() + 1,
|
||||||
|
&initramfs_config,
|
||||||
boot_vcpus,
|
boot_vcpus,
|
||||||
Some(hdr),
|
Some(hdr),
|
||||||
rsdp_addr,
|
rsdp_addr,
|
||||||
@ -481,6 +524,7 @@ impl Vm {
|
|||||||
&mem,
|
&mem,
|
||||||
arch::layout::CMDLINE_START,
|
arch::layout::CMDLINE_START,
|
||||||
cmdline_cstring.to_bytes().len() + 1,
|
cmdline_cstring.to_bytes().len() + 1,
|
||||||
|
&initramfs_config,
|
||||||
boot_vcpus,
|
boot_vcpus,
|
||||||
None,
|
None,
|
||||||
rsdp_addr,
|
rsdp_addr,
|
||||||
|
Loading…
Reference in New Issue
Block a user