-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
write bootparams in memory for Linux & PVH protos
This commit introduces a new configurator module that takes boot parameters created in the VMM (boot_params / start_info + e820 map) and writes them into guest memory. The module is meant to be extended in order to include *building* the boot parameters as well. Fixes #15 Signed-off-by: Alexandra Iordache <[email protected]>
- Loading branch information
1 parent
43d1c51
commit b446c4a
Showing
7 changed files
with
555 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause | ||
|
||
//! Traits and structs for configuring and loading boot parameters on `aarch64`. | ||
#![cfg(target_arch = "aarch64")] | ||
|
||
use std::error::Error as StdError; | ||
use std::fmt; | ||
|
||
/// Placeholder error type. | ||
#[derive(Debug, PartialEq)] | ||
pub enum Error { | ||
/// Placeholder error value. | ||
Placeholder, | ||
} | ||
|
||
impl StdError for Error { | ||
fn description(&self) -> &str { | ||
unimplemented!() | ||
} | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { | ||
unimplemented!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright © 2020, Oracle and/or its affiliates. | ||
// | ||
// Copyright (c) 2019 Intel Corporation. All rights reserved. | ||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// | ||
// Copyright 2017 The Chromium OS Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE-BSD-3-Clause file. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause | ||
|
||
//! Traits and structs for configuring and loading boot parameters. | ||
//! - [BootConfigurator](trait.BootConfigurator.html): configure boot parameters. | ||
//! - [LinuxBootConfigurator](linux/struct.LinuxBootConfigurator.html): Linux boot protocol | ||
//! parameters configurator. | ||
//! - [PvhBootConfigurator](pvh/struct.PvhBootConfigurator.html): PVH boot protocol parameters | ||
//! configurator. | ||
use vm_memory::{ByteValued, GuestAddress, GuestMemory}; | ||
|
||
use std::error::Error as StdError; | ||
use std::fmt; | ||
|
||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
mod x86_64; | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
pub use x86_64::*; | ||
|
||
#[cfg(target_arch = "aarch64")] | ||
mod aarch64; | ||
#[cfg(target_arch = "aarch64")] | ||
pub use aarch64::Error as ArmError; | ||
|
||
/// Errors specific to boot protocol configuration. | ||
#[derive(Debug, PartialEq)] | ||
pub enum Error { | ||
/// Errors specific to the Linux boot protocol configuration. | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
Linux(linux::Error), | ||
/// Errors specific to the PVH boot protocol configuration. | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
Pvh(pvh::Error), | ||
/// Errors specific to device tree boot configuration. | ||
#[cfg(target_arch = "aarch64")] | ||
Arm(ArmError), | ||
} | ||
|
||
impl StdError for Error { | ||
fn description(&self) -> &str { | ||
use Error::*; | ||
match self { | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
Linux(ref e) => e.description(), | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
Pvh(ref e) => e.description(), | ||
#[cfg(target_arch = "aarch64")] | ||
Arm(ref e) => e.description(), | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!( | ||
f, | ||
"Boot Configurator Error: {}", | ||
StdError::description(self) | ||
) | ||
} | ||
} | ||
|
||
/// A specialized `Result` type for the boot configurator. | ||
pub type Result<T> = std::result::Result<T, Error>; | ||
|
||
/// Trait that defines interfaces for building (TBD) and configuring boot parameters. | ||
/// | ||
/// Currently, this trait exposes a single function which writes user-provided boot parameters into | ||
/// guest memory at the user-specified addresses. It's meant to be called after the kernel is | ||
/// loaded and after the boot parameters are built externally (in the VMM). | ||
/// | ||
/// This trait will be extended with additional functionality to build boot parameters. | ||
pub trait BootConfigurator { | ||
/// Writes the boot parameters (configured elsewhere) into guest memory. | ||
/// | ||
/// The arguments are split into `header` and `sections` to accommodate different boot | ||
/// protocols like Linux boot and PVH. In Linux boot, the e820 map could be considered as | ||
/// `sections`, but it's already encapsulated in the `boot_params` and thus all the boot | ||
/// parameters are passed through a single struct. In PVH, the memory map table is separated | ||
/// from the `hvm_start_info` struct, therefore it's passed separately. | ||
/// | ||
/// # 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`]. | ||
/// * `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<()> | ||
where | ||
T: ByteValued, | ||
S: ByteValued, | ||
M: GuestMemory; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Copyright © 2020, Oracle and/or its affiliates. | ||
// | ||
// Copyright (c) 2019 Intel Corporation. All rights reserved. | ||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// | ||
// Copyright 2017 The Chromium OS Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE-BSD-3-Clause file. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause | ||
|
||
//! 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 super::super::{BootConfigurator, Error as BootConfiguratorError, Result}; | ||
use crate::loader::bootparam::boot_params; | ||
|
||
use std::error::Error as StdError; | ||
use std::fmt; | ||
use std::mem; | ||
|
||
/// Boot configurator for the Linux boot protocol. | ||
pub struct LinuxBootConfigurator {} | ||
|
||
/// Errors specific to the Linux boot protocol configuration. | ||
#[derive(Debug, PartialEq)] | ||
pub enum Error { | ||
/// The zero page extends past the end of guest memory. | ||
ZeroPagePastRamEnd, | ||
/// Error writing to the zero page of guest memory. | ||
ZeroPageSetup, | ||
} | ||
|
||
impl StdError for Error { | ||
fn description(&self) -> &str { | ||
use Error::*; | ||
match self { | ||
ZeroPagePastRamEnd => "The zero page extends past the end of guest memory.", | ||
ZeroPageSetup => "Error writing to the zero page of guest memory.", | ||
} | ||
} | ||
} | ||
|
||
impl fmt::Display for Error { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!( | ||
f, | ||
"Linux Boot Configurator Error: {}", | ||
StdError::description(self) | ||
) | ||
} | ||
} | ||
|
||
impl From<Error> for BootConfiguratorError { | ||
fn from(err: Error) -> Self { | ||
BootConfiguratorError::Linux(err) | ||
} | ||
} | ||
|
||
impl BootConfigurator for LinuxBootConfigurator { | ||
/// Writes the boot parameters (configured elsewhere) into guest memory. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `header` - boot parameters encapsulated in a [`boot_params`] struct. | ||
/// * `sections` - 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<()> | ||
where | ||
T: ByteValued, | ||
S: 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>()) | ||
.ok_or(Error::ZeroPagePastRamEnd)?; | ||
guest_memory | ||
.write_obj(header.0, header.1) | ||
.map_err(|_| Error::ZeroPageSetup)?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
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 = 0x1000000; | ||
|
||
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(); | ||
// This is where we'd append e820 entries, cmdline, PCI, ACPI etc. | ||
|
||
let guest_memory = create_guest_mem(); | ||
|
||
// Error case: boot params don't fit in guest memory (zero page address too close to end). | ||
let bad_zeropg_addr = GuestAddress( | ||
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, | ||
&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() | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright © 2020, Oracle and/or its affiliates. | ||
// | ||
// Copyright (c) 2019 Intel Corporation. All rights reserved. | ||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// | ||
// Copyright 2017 The Chromium OS Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE-BSD-3-Clause file. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause | ||
|
||
//! Traits and structs for configuring and loading boot parameters on `x86_64`. | ||
#![cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
|
||
pub mod linux; | ||
pub mod pvh; |
Oops, something went wrong.