use vm_memory::{Bytes, GuestMemory};
use crate::configurator::{BootConfigurator, BootParams, Error as BootConfiguratorError, Result};
use std::fmt;
pub struct LinuxBootConfigurator {}
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
ZeroPagePastRamEnd,
ZeroPageSetup,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
let desc = match self {
ZeroPagePastRamEnd => "the zero page extends past the end of guest memory.",
ZeroPageSetup => "error writing to the zero page of guest memory.",
};
write!(f, "Linux Boot Configurator: {}", desc,)
}
}
impl std::error::Error for Error {}
impl From<Error> for BootConfiguratorError {
fn from(err: Error) -> Self {
BootConfiguratorError::Linux(err)
}
}
impl BootConfigurator for LinuxBootConfigurator {
fn write_bootparams<M>(params: &BootParams, guest_memory: &M) -> Result<()>
where
M: GuestMemory,
{
guest_memory
.checked_offset(params.header_start, params.header.len())
.ok_or(Error::ZeroPagePastRamEnd)?;
guest_memory
.write_slice(params.header.as_slice(), params.header_start)
.map_err(|_| Error::ZeroPageSetup)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::loader_gen::bootparam::boot_params;
use std::mem;
use vm_memory::{Address, GuestAddress, GuestMemoryMmap};
const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
const KERNEL_HDR_MAGIC: u32 = 0x53726448;
const KERNEL_LOADER_OTHER: u8 = 0xff;
const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000;
const MEM_SIZE: u64 = 0x100_0000;
fn create_guest_mem() -> GuestMemoryMmap {
GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
}
fn build_bootparams_common() -> boot_params {
let mut params = boot_params::default();
params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
params.hdr.header = KERNEL_HDR_MAGIC;
params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
params
}
#[test]
fn test_configure_linux_boot() {
let zero_page_addr = GuestAddress(0x30000);
let params = build_bootparams_common();
let guest_memory = create_guest_mem();
let bad_zeropg_addr = GuestAddress(
guest_memory.last_addr().raw_value() - mem::size_of::<boot_params>() as u64 + 1,
);
let mut bootparams = BootParams::new::<boot_params>(¶ms, bad_zeropg_addr);
assert_eq!(
LinuxBootConfigurator::write_bootparams::<GuestMemoryMmap>(&bootparams, &guest_memory,)
.err(),
Some(Error::ZeroPagePastRamEnd.into()),
);
bootparams.header_start = zero_page_addr;
assert!(LinuxBootConfigurator::write_bootparams::<GuestMemoryMmap>(
&bootparams,
&guest_memory,
)
.is_ok());
}
#[test]
fn test_error_messages() {
assert_eq!(
format!("{}", Error::ZeroPagePastRamEnd),
"Linux Boot Configurator: the zero page extends past the end of guest memory."
);
assert_eq!(
format!("{}", Error::ZeroPageSetup),
"Linux Boot Configurator: error writing to the zero page of guest memory."
);
}
}