Skip to content

Commit

Permalink
configurator: BootParams struct
Browse files Browse the repository at this point in the history
Added a new generic struct that encapsulates boot parameters
expressed as ByteValued structs in:
* header: section of the parameters that is necessary regardless
  of boot protocol. For Linux, it's the boot_params struct; for
  PVH, it's the start_info; for ARM+FDT, it's the device tree
  blob.
* sections: vector of additional boot parameters written at a
  different address than the header. Unused for Linux & FDT. For
  PVH, it's the memory map table.
* modules: vector of module boot configurations, written at a
  different address than the header and sections. Unused for
  Linux & FDT. For PVH, it's (optionally) a vector of 1
  modlist_entry containing the initrd configuration, if any.

Signed-off-by: Alexandra Iordache <aghecen@amazon.com>
  • Loading branch information
Alexandra Iordache committed Apr 9, 2020
1 parent 83cc093 commit 89de317
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 74 deletions.
16 changes: 6 additions & 10 deletions src/configurator/aarch64/fdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

//! Traits and structs for loading the device tree.

use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory};
use vm_memory::{ByteValued, Bytes, GuestMemory};

use std::error::Error as StdError;
use std::fmt;

use super::super::{BootConfigurator, Error as BootConfiguratorError, Result};
use crate::configurator::{BootConfigurator, BootParams, Error as BootConfiguratorError, Result};

/// Errors specific to the device tree boot protocol configuration.
#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -51,22 +51,18 @@ impl BootConfigurator for FdtBootConfigurator {
///
/// # Arguments
///
/// * `fdt` - flattened device tree.
/// * `sections` - unused.
/// * `params` - boot parameters containing the FDT.
/// * `guest_memory` - guest's physical memory.
fn write_bootparams<T, S, M>(
fdt: (T, GuestAddress),
_sections: Option<(Vec<S>, GuestAddress)>,
guest_memory: &M,
) -> Result<()>
fn write_bootparams<T, S, R, M>(params: BootParams<T, S, R>, guest_memory: &M) -> Result<()>
where
T: ByteValued,
S: ByteValued,
R: ByteValued,
M: GuestMemory,
{
// The VMM has filled an FDT and passed it as a `ByteValued` object.
guest_memory
.write_obj(fdt.0, fdt.1)
.write_obj(params.header.header, params.header.address)
.map_err(|_| Error::WriteFDTToMemory.into())
}
}
107 changes: 89 additions & 18 deletions src/configurator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,98 @@ pub trait BootConfigurator {
///
/// # Arguments
///
/// * `header` - header section of the boot parameters and address where to write it in guest
/// memory. The first element must be a POD struct that implements [`ByteValued`].
/// For the Linux protocol it's the [`boot_params`] struct, and for PVH the
/// [`hvm_start_info`] struct.
/// * `sections` - vector of sections that compose the boot parameters and address where to
/// write them in guest memory. Unused for the Linux protocol. For PVH, it's the
/// memory map table represented as a vector of [`hvm_memmap_table_entry`]. Must
/// be a `Vec` of POD data structs that implement [`ByteValued`].
/// * `params` - struct containing the header section of the boot parameters, additional
/// sections and modules, and their associated addresses in guest memory. These
/// vary with the boot protocol used.
/// * `guest_memory` - guest's physical memory.
///
/// [`boot_params`]: ../loader/bootparam/struct.boot_e820_entry.html
/// [`hvm_memmap_table_entry`]: ../loader/elf/start_info/struct.hvm_memmap_table_entry.html
/// [`hvm_start_info`]: ../loader/elf/start_info/struct.hvm_start_info.html
/// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html
fn write_bootparams<T, S, M>(
header: (T, GuestAddress),
sections: Option<(Vec<S>, GuestAddress)>,
guest_memory: &M,
) -> Result<()>
fn write_bootparams<T, S, R, M>(params: BootParams<T, S, R>, guest_memory: &M) -> Result<()>
where
T: ByteValued,
S: ByteValued,
R: ByteValued,
M: GuestMemory;
}

/// Header section of the boot parameters and associated guest memory address.
///
/// For the Linux boot protocol, it contains a [`boot_params`] struct and the zero page address.
/// For the PVH boot protocol, it contains a [`hvm_start_info`] struct and its address.
///
/// [`boot_params`]: ../loader/bootparam/struct.boot_params.html
/// [`hvm_start_info`]: ../loader/elf/start_info/struct.hvm_start_info.html
pub struct BootHeader<T: ByteValued> {
/// Header section of the boot parameters.
pub header: T,
/// Address where it will be written in guest memory.
pub address: GuestAddress,
}

/// Sections of the boot parameters and associated guest memory address.
///
/// Unused for the Linux boot protocol.
/// For the PVH boot protocol, they're used to specify both the memory map table in
/// [`hvm_memmap_table_entry`] structs, and, optionally, boot modules in [`hvm_modlist_entry`]
/// structs.
///
/// [`hvm_memmap_table_entry`]: ../loader/elf/start_info/struct.hvm_memmap_table_entry.html
/// [`hvm_modlist_entry`]: ../loader/elf/start_info/struct.hvm_modlist_entry.html
pub struct BootSections<T: ByteValued> {
/// Data sections of the boot parameters.
pub sections: Vec<T>,
/// Address where they will be written in guest memory.
pub address: GuestAddress,
}

/// Boot parameters to be written in guest memory.
pub struct BootParams<T: ByteValued, S: ByteValued, R: ByteValued> {
/// "Header section", always written in guest memory irrespective of boot protocol.
pub header: BootHeader<T>,
/// Optional sections containing boot configurations (e.g. E820 map).
pub sections: Option<BootSections<S>>,
/// Optional modules specified at boot configuration time.
pub modules: Option<BootSections<R>>,
}

impl<T, S, R> BootParams<T, S, R>
where
T: ByteValued,
S: ByteValued,
R: ByteValued,
{
/// Aggregates boot parameters into a [`BootParams`](struct.BootParams.html) struct.
///
/// # Arguments
///
/// * `header` - [`ByteValued`] representation of mandatory boot parameters.
/// * `header_addr` - address in guest memory where `header` will be written.
/// * `sections` - optional list of [`ByteValued`] boot configurations and associated address.
/// * `modules` - optional list of [`ByteValued`] boot modules and associated address.
///
/// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html
pub fn new(
header: T,
header_addr: GuestAddress,
sections: Option<(Vec<S>, GuestAddress)>,
modules: Option<(Vec<R>, GuestAddress)>,
) -> Self {
Self {
header: BootHeader {
header,
address: header_addr,
},
sections: if let Some((sections, address)) = sections {
Some(BootSections { sections, address })
} else {
None
},
modules: if let Some((modules, address)) = modules {
Some(BootSections {
sections: modules,
address,
})
} else {
None
},
}
}
}
49 changes: 26 additions & 23 deletions src/configurator/x86_64/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
//! Traits and structs for configuring and loading boot parameters on `x86_64` using the Linux
//! boot protocol.

use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory};
use vm_memory::{ByteValued, Bytes, GuestMemory};

use super::super::{BootConfigurator, Error as BootConfiguratorError, Result};
use crate::configurator::{BootConfigurator, BootParams, Error as BootConfiguratorError, Result};
use crate::loader::bootparam::boot_params;

use std::error::Error as StdError;
Expand Down Expand Up @@ -64,28 +64,25 @@ impl BootConfigurator for LinuxBootConfigurator {
///
/// # Arguments
///
/// * `header` - boot parameters encapsulated in a [`boot_params`] struct.
/// * `sections` - unused.
/// * `params` - boot parameters. The header contains a [`boot_params`] struct. The `sections`
/// and `modules` are unused.
/// * `guest_memory` - guest's physical memory.
///
/// [`boot_params`]: ../loader/bootparam/struct.boot_e820_entry.html
fn write_bootparams<T, S, M>(
header: (T, GuestAddress),
_sections: Option<(Vec<S>, GuestAddress)>,
guest_memory: &M,
) -> Result<()>
/// [`boot_params`]: ../loader/bootparam/struct.boot_params.html
fn write_bootparams<T, S, R, M>(params: BootParams<T, S, R>, guest_memory: &M) -> Result<()>
where
T: ByteValued,
S: ByteValued,
R: ByteValued,
M: GuestMemory,
{
// The VMM has filled a `boot_params` struct and its e820 map.
// This will be written in guest memory at the zero page.
guest_memory
.checked_offset(header.1, mem::size_of::<boot_params>())
.checked_offset(params.header.address, mem::size_of::<boot_params>())
.ok_or(Error::ZeroPagePastRamEnd)?;
guest_memory
.write_obj(header.0, header.1)
.write_obj(params.header.header, params.header.address)
.map_err(|_| Error::ZeroPageSetup)?;

Ok(())
Expand Down Expand Up @@ -131,23 +128,29 @@ mod tests {
guest_memory.last_addr().raw_value() - mem::size_of::<boot_params>() as u64 + 1,
);
assert_eq!(
LinuxBootConfigurator::write_bootparams::<boot_params, boot_params, GuestMemoryMmap>(
(params, bad_zeropg_addr),
None,
LinuxBootConfigurator::write_bootparams::<
boot_params,
boot_params,
boot_params,
GuestMemoryMmap,
>(
BootParams::new(params, bad_zeropg_addr, None, None),
&guest_memory,
)
.err(),
Some(Error::ZeroPagePastRamEnd.into()),
);

// Success case.
assert!(
LinuxBootConfigurator::write_bootparams::<boot_params, boot_params, GuestMemoryMmap>(
(params, zero_page_addr),
None,
&guest_memory
)
.is_ok()
);
assert!(LinuxBootConfigurator::write_bootparams::<
boot_params,
boot_params,
boot_params,
GuestMemoryMmap,
>(
BootParams::new(params, zero_page_addr, None, None),
&guest_memory,
)
.is_ok());
}
}
Loading

0 comments on commit 89de317

Please sign in to comment.