Skip to content

Commit

Permalink
cosmetic changes & doctests
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandra Iordache <[email protected]>
  • Loading branch information
Alexandra Iordache committed May 25, 2020
1 parent bd01b6d commit 7cb4ee8
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 43 deletions.
2 changes: 1 addition & 1 deletion coverage_config_aarch64.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"coverage_score": 80.3,
"coverage_score": 80.4,
"exclude_path": "",
"crate_features": ""
}
2 changes: 1 addition & 1 deletion coverage_config_x86_64.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"coverage_score": 78.5,
"coverage_score": 78.7,
"exclude_path": "",
"crate_features": ""
}
103 changes: 82 additions & 21 deletions src/cmdline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::fmt;
use std::result;

/// The error type for command line building operations.
#[derive(PartialEq, Debug)]
#[derive(Debug, PartialEq)]
pub enum Error {
/// Operation would have resulted in a non-printable ASCII character.
InvalidAscii,
Expand All @@ -30,16 +30,17 @@ impl fmt::Display for Error {
f,
"{}",
match *self {
Error::InvalidAscii => "string contains non-printable ASCII character",
Error::HasSpace => "string contains a space",
Error::HasEquals => "string contains an equals sign",
Error::TooLarge => "inserting string would make command line too long",
Error::InvalidAscii => "String contains a non-printable ASCII character.",
Error::HasSpace => "String contains a space.",
Error::HasEquals => "String contains an equals sign.",
Error::TooLarge => "Inserting string would make command line too long.",
}
)
}
}

/// Specialized Result type for command line operations.
/// Specialized [`Result`] type for command line operations.
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
pub type Result<T> = result::Result<T, Error>;

fn valid_char(c: char) -> bool {
Expand Down Expand Up @@ -69,17 +70,37 @@ fn valid_element(s: &str) -> Result<()> {
}
}

/// A builder for a kernel command line string that validates the string as its being built. A
/// `CString` can be constructed from this directly using `CString::new`.
#[derive(Clone)]
/// A builder for a kernel command line string that validates the string as it's being built.
/// A `CString` can be constructed from this directly using `CString::new`.
///
/// # Examples
///
/// ```rust
/// # use linux_loader::cmdline::*;
/// # use std::ffi::CString;
/// let cl = Cmdline::new(100);
/// let cl_cstring = CString::new(cl).unwrap();
/// assert_eq!(cl_cstring.to_str().unwrap(), "");
/// ```
pub struct Cmdline {
line: String,
capacity: usize,
}

impl Cmdline {
/// Constructs an empty Cmdline with the given capacity, which includes the nul terminator.
/// Capacity must be greater than 0.
/// Constructs an empty [`Cmdline`] with the given capacity, including the nul terminator.
///
/// # Arguments
///
/// * `capacity` - Command line capacity. Must be greater than 0.
///
/// # Examples
///
/// ```rust
/// # use linux_loader::cmdline::*;
/// let cl = Cmdline::new(100);
/// ```
/// [`Cmdline`]: struct.Cmdline.html
pub fn new(capacity: usize) -> Cmdline {
assert_ne!(capacity, 0);
Cmdline {
Expand Down Expand Up @@ -109,7 +130,23 @@ impl Cmdline {
assert!(self.line.len() < self.capacity);
}

/// Validates and inserts a key value pair into this command line
/// Validates and inserts a key-value pair into this command line.
///
/// # Arguments
///
/// * `key` - Key to be inserted in the command line string.
/// * `val` - Value corresponding to `key`.
///
/// # Examples
///
/// ```rust
/// # use linux_loader::cmdline::*;
/// # use std::ffi::CString;
/// let mut cl = Cmdline::new(100);
/// cl.insert("foo", "bar");
/// let cl_cstring = CString::new(cl).unwrap();
/// assert_eq!(cl_cstring.to_str().unwrap(), "foo=bar");
/// ```
pub fn insert<T: AsRef<str>>(&mut self, key: T, val: T) -> Result<()> {
let k = key.as_ref();
let v = val.as_ref();
Expand All @@ -127,7 +164,22 @@ impl Cmdline {
Ok(())
}

/// Validates and inserts a string to the end of the current command line
/// Validates and inserts a string to the end of the current command line.
///
/// # Arguments
///
/// * `slug` - String to be appended to the command line.
///
/// # Examples
///
/// ```rust
/// # use linux_loader::cmdline::*;
/// # use std::ffi::CString;
/// let mut cl = Cmdline::new(100);
/// cl.insert_str("foobar");
/// let cl_cstring = CString::new(cl).unwrap();
/// assert_eq!(cl_cstring.to_str().unwrap(), "foobar");
/// ```
pub fn insert_str<T: AsRef<str>>(&mut self, slug: T) -> Result<()> {
let s = slug.as_ref();
valid_str(s)?;
Expand All @@ -141,7 +193,16 @@ impl Cmdline {
Ok(())
}

/// Returns the cmdline in progress without nul termination
/// Returns the string representation of the command line without the nul terminator.
///
/// # Examples
///
/// ```rust
/// # use linux_loader::cmdline::*;
/// let mut cl = Cmdline::new(10);
/// cl.insert_str("foobar");
/// assert_eq!(cl.as_str(), "foobar");
/// ```
pub fn as_str(&self) -> &str {
self.line.as_str()
}
Expand All @@ -159,7 +220,7 @@ mod tests {
use std::ffi::CString;

#[test]
fn insert_hello_world() {
fn test_insert_hello_world() {
let mut cl = Cmdline::new(100);
assert_eq!(cl.as_str(), "");
assert!(cl.insert("hello", "world").is_ok());
Expand All @@ -170,15 +231,15 @@ mod tests {
}

#[test]
fn insert_multi() {
fn test_insert_multi() {
let mut cl = Cmdline::new(100);
assert!(cl.insert("hello", "world").is_ok());
assert!(cl.insert("foo", "bar").is_ok());
assert_eq!(cl.as_str(), "hello=world foo=bar");
}

#[test]
fn insert_space() {
fn test_insert_space() {
let mut cl = Cmdline::new(100);
assert_eq!(cl.insert("a ", "b"), Err(Error::HasSpace));
assert_eq!(cl.insert("a", "b "), Err(Error::HasSpace));
Expand All @@ -188,7 +249,7 @@ mod tests {
}

#[test]
fn insert_equals() {
fn test_insert_equals() {
let mut cl = Cmdline::new(100);
assert_eq!(cl.insert("a=", "b"), Err(Error::HasEquals));
assert_eq!(cl.insert("a", "b="), Err(Error::HasEquals));
Expand All @@ -199,15 +260,15 @@ mod tests {
}

#[test]
fn insert_emoji() {
fn test_insert_emoji() {
let mut cl = Cmdline::new(100);
assert_eq!(cl.insert("heart", "💖"), Err(Error::InvalidAscii));
assert_eq!(cl.insert("💖", "love"), Err(Error::InvalidAscii));
assert_eq!(cl.as_str(), "");
}

#[test]
fn insert_string() {
fn test_insert_string() {
let mut cl = Cmdline::new(13);
assert_eq!(cl.as_str(), "");
assert!(cl.insert_str("noapic").is_ok());
Expand All @@ -217,7 +278,7 @@ mod tests {
}

#[test]
fn insert_too_large() {
fn test_insert_too_large() {
let mut cl = Cmdline::new(4);
assert_eq!(cl.insert("hello", "world"), Err(Error::TooLarge));
assert_eq!(cl.insert("a", "world"), Err(Error::TooLarge));
Expand Down
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@
//!
//! This crate offers support for loading raw ELF (vmlinux), compressed
//! big zImage (bzImage) and PE (Image) kernel images.
//! ELF support includes the Linux and PVH boot protocols.
//! Support for any other kernel image format can be added by implementing
//! the KernelLoader.
//! the [`KernelLoader`] and [`BootConfigurator`].
//!
//! # Platform support
//!
//! - x86_64
//! - ARM64
//! - `x86_64`
//! - `ARM64`
//!
//! [`BootConfigurator`]: trait.BootConfigurator.html
//! [`KernelLoader`]: trait.KernelLoader.html
pub mod cmdline;
pub mod configurator;
Expand Down
61 changes: 44 additions & 17 deletions src/loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause

//! Traits and Structs for loading kernels into guest memory.
//! - [KernelLoader](trait.KernelLoader.html): load kernel image into guest memory
//! - [KernelLoaderResult](struct.KernelLoaderResult.html): the structure which loader
//! returns to VMM to assist zero page construction and boot environment setup
//! - [Elf](struct.Elf.html): elf image loader
//! - [BzImage](struct.BzImage.html): bzImage loader
//! Traits and structs for loading kernels into guest memory.
//! - [KernelLoader](trait.KernelLoader.html): load kernel image into guest memory.
//! - [KernelLoaderResult](struct.KernelLoaderResult.html): structure passed to the VMM to assist
//! zero page construction and boot environment setup.
//! - [Elf](struct.Elf.html): elf image loader.
//! - [BzImage](struct.BzImage.html): bzImage loader.
extern crate vm_memory;

Expand Down Expand Up @@ -71,7 +71,8 @@ pub enum Error {
MemoryOverflow,
}

/// A specialized `Result` type for the kernel loader.
/// A specialized [`Result`] type for the kernel loader.
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
pub type Result<T> = std::result::Result<T, Error>;

impl StdError for Error {
Expand Down Expand Up @@ -126,13 +127,13 @@ impl From<pe::Error> for Error {
/// the VMM.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct KernelLoaderResult {
/// Address in the guest memory where the kernel image starts to be loaded
/// Address in the guest memory where the kernel image starts to be loaded.
pub kernel_load: GuestAddress,
/// Offset in guest memory corresponding to the end of kernel image, in case that
/// device tree blob and initrd will be loaded adjacent to kernel image.
/// Offset in guest memory corresponding to the end of kernel image, in case the device tree
/// blob and initrd will be loaded adjacent to kernel image.
pub kernel_end: GuestUsize,
/// This field is only for bzImage following https://www.kernel.org/doc/Documentation/x86/boot.txt
/// VMM should make use of it to fill zero page for bzImage direct boot.
/// Configuration for the VMM to use to fill zero page for bzImage direct boot.
/// See https://www.kernel.org/doc/Documentation/x86/boot.txt.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub setup_header: Option<bootparam::setup_header>,
/// This field optionally holds the address of a PVH entry point, indicating that
Expand All @@ -141,10 +142,18 @@ pub struct KernelLoaderResult {
pub pvh_entry_addr: Option<GuestAddress>,
}

/// A kernel image loading support must implement the KernelLoader trait.
/// The only method to be implemented is the load one, returning a KernelLoaderResult structure.
/// Trait that specifies kernel image loading support.
pub trait KernelLoader {
/// How to load a specific kernel image format into the guest memory.
///
/// # Arguments
///
/// * `guest_mem`: [`GuestMemory`] to load the kernel in.
/// * `kernel_start`: Address in guest memory where the kernel is loaded.
/// * `kernel_image`: Kernel image to be loaded.
/// * `highmem_start_address`: Address where high memory starts.
///
/// [`GuestMemory`]: https://docs.rs/vm-memory/latest/vm_memory/guest_memory/trait.GuestMemory.html
fn load<F, M: GuestMemory>(
guest_mem: &M,
kernel_start: Option<GuestAddress>,
Expand All @@ -164,9 +173,27 @@ unsafe impl ByteValued for bootparam::boot_params {}
///
/// # Arguments
///
/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
/// * `guest_mem` - [`GuestMemory`] that will be partially overwritten by the command line.
/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
/// * `cmdline` - The kernel command line.
///
/// [`GuestMemory`]: https://docs.rs/vm-memory/latest/vm_memory/guest_memory/trait.GuestMemory.html
///
/// # Examples
///
/// ```rust
/// # extern crate vm_memory;
/// # use linux_loader::loader::*;
/// # use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
/// # use std::ffi::CStr;
/// let mem_size: usize = 0x1000000;
/// let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), mem_size)]).unwrap();
/// let cl = CStr::from_bytes_with_nul(b"foo=bar\0").unwrap();
/// let mut buf = vec![0u8;8];
/// let result = load_cmdline(&gm, GuestAddress(0x1000), &cl).unwrap();
/// gm.read_slice(buf.as_mut_slice(), GuestAddress(0x1000)).unwrap();
/// assert_eq!(buf.as_slice(), "foo=bar\0".as_bytes());
///
pub fn load_cmdline<M: GuestMemory>(
guest_mem: &M,
guest_addr: GuestAddress,
Expand Down Expand Up @@ -203,7 +230,7 @@ mod tests {
}

#[test]
fn cmdline_overflow() {
fn test_cmdline_overflow() {
let gm = create_guest_mem();
let cmdline_address = GuestAddress(MEM_SIZE - 5);
assert_eq!(
Expand All @@ -217,7 +244,7 @@ mod tests {
}

#[test]
fn cmdline_write_end() {
fn test_cmdline_write_end() {
let gm = create_guest_mem();
let mut cmdline_address = GuestAddress(45);
assert_eq!(
Expand Down

0 comments on commit 7cb4ee8

Please sign in to comment.