use vm_memory::{Bytes, GuestMemory};
use std::fmt;
use crate::configurator::{BootConfigurator, BootParams, Error as BootConfiguratorError, Result};
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
FDTPastRamEnd,
WriteFDTToMemory,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
let desc = match self {
FDTPastRamEnd => "FDT does not fit in guest memory.",
WriteFDTToMemory => "error writing FDT in guest memory.",
};
write!(f, "Device Tree Boot Configurator: {}", desc)
}
}
impl std::error::Error for Error {}
impl From<Error> for BootConfiguratorError {
fn from(err: Error) -> Self {
BootConfiguratorError::Fdt(err)
}
}
pub struct FdtBootConfigurator {}
impl BootConfigurator for FdtBootConfigurator {
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::FDTPastRamEnd)?;
guest_memory
.write_slice(params.header.as_slice(), params.header_start)
.map_err(|_| Error::WriteFDTToMemory.into())
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::undocumented_unsafe_blocks)]
use super::*;
use vm_memory::{Address, ByteValued, GuestAddress, GuestMemoryMmap};
const FDT_MAX_SIZE: usize = 0x20;
const MEM_SIZE: u64 = 0x100_0000;
fn create_guest_mem() -> GuestMemoryMmap {
GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
}
#[derive(Clone, Copy, Default)]
struct FdtPlaceholder([u8; FDT_MAX_SIZE]);
unsafe impl ByteValued for FdtPlaceholder {}
#[test]
fn test_configure_fdt_boot() {
let fdt = FdtPlaceholder([0u8; FDT_MAX_SIZE]);
let guest_memory = create_guest_mem();
let fdt_addr = GuestAddress(guest_memory.last_addr().raw_value() - FDT_MAX_SIZE as u64 + 1);
assert_eq!(
FdtBootConfigurator::write_bootparams::<GuestMemoryMmap>(
&BootParams::new::<FdtPlaceholder>(&fdt, fdt_addr),
&guest_memory,
)
.err(),
Some(Error::FDTPastRamEnd.into())
);
let fdt_addr = GuestAddress(guest_memory.last_addr().raw_value() - FDT_MAX_SIZE as u64);
assert!(FdtBootConfigurator::write_bootparams::<GuestMemoryMmap>(
&BootParams::new::<FdtPlaceholder>(&fdt, fdt_addr),
&guest_memory,
)
.is_ok());
}
#[test]
fn test_error_messages() {
assert_eq!(
format!("{}", Error::FDTPastRamEnd),
"Device Tree Boot Configurator: FDT does not fit in guest memory."
);
assert_eq!(
format!("{}", Error::WriteFDTToMemory),
"Device Tree Boot Configurator: error writing FDT in guest memory."
);
}
}