From 1af92d21adfab105e05146625d7dace58892612d Mon Sep 17 00:00:00 2001 From: Alexandra Iordache Date: Fri, 6 Mar 2020 21:01:15 +0200 Subject: [PATCH] cosmetic changes & doctests Signed-off-by: Alexandra Iordache --- coverage_config_aarch64.json | 2 +- coverage_config_x86_64.json | 2 +- src/cmdline/mod.rs | 103 ++++++++++++++++++++++++++++------- src/lib.rs | 9 ++- src/loader/mod.rs | 61 +++++++++++++++------ 5 files changed, 134 insertions(+), 43 deletions(-) diff --git a/coverage_config_aarch64.json b/coverage_config_aarch64.json index e43a17d0..d2ce0ac0 100644 --- a/coverage_config_aarch64.json +++ b/coverage_config_aarch64.json @@ -1,5 +1,5 @@ { - "coverage_score": 80.3, + "coverage_score": 80.4, "exclude_path": "", "crate_features": "" } diff --git a/coverage_config_x86_64.json b/coverage_config_x86_64.json index fe626856..c466612b 100644 --- a/coverage_config_x86_64.json +++ b/coverage_config_x86_64.json @@ -1,5 +1,5 @@ { - "coverage_score": 78.5, + "coverage_score": 78.7, "exclude_path": "", "crate_features": "" } diff --git a/src/cmdline/mod.rs b/src/cmdline/mod.rs index abeb095f..012ee4d4 100644 --- a/src/cmdline/mod.rs +++ b/src/cmdline/mod.rs @@ -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, @@ -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 = result::Result; fn valid_char(c: char) -> bool { @@ -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 { @@ -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>(&mut self, key: T, val: T) -> Result<()> { let k = key.as_ref(); let v = val.as_ref(); @@ -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>(&mut self, slug: T) -> Result<()> { let s = slug.as_ref(); valid_str(s)?; @@ -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() } @@ -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()); @@ -170,7 +231,7 @@ 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()); @@ -178,7 +239,7 @@ mod tests { } #[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)); @@ -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)); @@ -199,7 +260,7 @@ 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)); @@ -207,7 +268,7 @@ mod tests { } #[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()); @@ -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)); diff --git a/src/lib.rs b/src/lib.rs index 688d7fbc..0630764b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/loader/mod.rs b/src/loader/mod.rs index 73767a68..7d7a91be 100644 --- a/src/loader/mod.rs +++ b/src/loader/mod.rs @@ -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; @@ -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 = std::result::Result; impl StdError for Error { @@ -126,13 +127,13 @@ impl From 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, /// This field optionally holds the address of a PVH entry point, indicating that @@ -141,10 +142,18 @@ pub struct KernelLoaderResult { pub pvh_entry_addr: Option, } -/// 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( guest_mem: &M, kernel_start: Option, @@ -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( guest_mem: &M, guest_addr: GuestAddress, @@ -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!( @@ -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!(