Skip to content

Commit b446c4a

Browse files
Alexandra Iordacheandreeaflorescu
authored andcommitted
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 <aghecen@amazon.com>
1 parent 43d1c51 commit b446c4a

File tree

7 files changed

+555
-0
lines changed

7 files changed

+555
-0
lines changed

src/configurator/aarch64/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
4+
5+
//! Traits and structs for configuring and loading boot parameters on `aarch64`.
6+
7+
#![cfg(target_arch = "aarch64")]
8+
9+
use std::error::Error as StdError;
10+
use std::fmt;
11+
12+
/// Placeholder error type.
13+
#[derive(Debug, PartialEq)]
14+
pub enum Error {
15+
/// Placeholder error value.
16+
Placeholder,
17+
}
18+
19+
impl StdError for Error {
20+
fn description(&self) -> &str {
21+
unimplemented!()
22+
}
23+
}
24+
25+
impl fmt::Display for Error {
26+
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
27+
unimplemented!()
28+
}
29+
}

src/configurator/mod.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright © 2020, Oracle and/or its affiliates.
2+
//
3+
// Copyright (c) 2019 Intel Corporation. All rights reserved.
4+
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
//
6+
// Copyright 2017 The Chromium OS Authors. All rights reserved.
7+
// Use of this source code is governed by a BSD-style license that can be
8+
// found in the LICENSE-BSD-3-Clause file.
9+
//
10+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
11+
12+
//! Traits and structs for configuring and loading boot parameters.
13+
//! - [BootConfigurator](trait.BootConfigurator.html): configure boot parameters.
14+
//! - [LinuxBootConfigurator](linux/struct.LinuxBootConfigurator.html): Linux boot protocol
15+
//! parameters configurator.
16+
//! - [PvhBootConfigurator](pvh/struct.PvhBootConfigurator.html): PVH boot protocol parameters
17+
//! configurator.
18+
19+
use vm_memory::{ByteValued, GuestAddress, GuestMemory};
20+
21+
use std::error::Error as StdError;
22+
use std::fmt;
23+
24+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
25+
mod x86_64;
26+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
27+
pub use x86_64::*;
28+
29+
#[cfg(target_arch = "aarch64")]
30+
mod aarch64;
31+
#[cfg(target_arch = "aarch64")]
32+
pub use aarch64::Error as ArmError;
33+
34+
/// Errors specific to boot protocol configuration.
35+
#[derive(Debug, PartialEq)]
36+
pub enum Error {
37+
/// Errors specific to the Linux boot protocol configuration.
38+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
39+
Linux(linux::Error),
40+
/// Errors specific to the PVH boot protocol configuration.
41+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
42+
Pvh(pvh::Error),
43+
/// Errors specific to device tree boot configuration.
44+
#[cfg(target_arch = "aarch64")]
45+
Arm(ArmError),
46+
}
47+
48+
impl StdError for Error {
49+
fn description(&self) -> &str {
50+
use Error::*;
51+
match self {
52+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
53+
Linux(ref e) => e.description(),
54+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
55+
Pvh(ref e) => e.description(),
56+
#[cfg(target_arch = "aarch64")]
57+
Arm(ref e) => e.description(),
58+
}
59+
}
60+
}
61+
62+
impl fmt::Display for Error {
63+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64+
write!(
65+
f,
66+
"Boot Configurator Error: {}",
67+
StdError::description(self)
68+
)
69+
}
70+
}
71+
72+
/// A specialized `Result` type for the boot configurator.
73+
pub type Result<T> = std::result::Result<T, Error>;
74+
75+
/// Trait that defines interfaces for building (TBD) and configuring boot parameters.
76+
///
77+
/// Currently, this trait exposes a single function which writes user-provided boot parameters into
78+
/// guest memory at the user-specified addresses. It's meant to be called after the kernel is
79+
/// loaded and after the boot parameters are built externally (in the VMM).
80+
///
81+
/// This trait will be extended with additional functionality to build boot parameters.
82+
pub trait BootConfigurator {
83+
/// Writes the boot parameters (configured elsewhere) into guest memory.
84+
///
85+
/// The arguments are split into `header` and `sections` to accommodate different boot
86+
/// protocols like Linux boot and PVH. In Linux boot, the e820 map could be considered as
87+
/// `sections`, but it's already encapsulated in the `boot_params` and thus all the boot
88+
/// parameters are passed through a single struct. In PVH, the memory map table is separated
89+
/// from the `hvm_start_info` struct, therefore it's passed separately.
90+
///
91+
/// # Arguments
92+
///
93+
/// * `header` - header section of the boot parameters and address where to write it in guest
94+
/// memory. The first element must be a POD struct that implements [`ByteValued`].
95+
/// For the Linux protocol it's the [`boot_params`] struct, and for PVH the
96+
/// [`hvm_start_info`] struct.
97+
/// * `sections` - vector of sections that compose the boot parameters and address where to
98+
/// write them in guest memory. Unused for the Linux protocol. For PVH, it's the
99+
/// memory map table represented as a vector of [`hvm_memmap_table_entry`]. Must
100+
/// be a `Vec` of POD data structs that implement [`ByteValued`].
101+
/// * `guest_memory` - guest's physical memory.
102+
///
103+
/// [`boot_params`]: ../loader/bootparam/struct.boot_e820_entry.html
104+
/// [`hvm_memmap_table_entry`]: ../loader/elf/start_info/struct.hvm_memmap_table_entry.html
105+
/// [`hvm_start_info`]: ../loader/elf/start_info/struct.hvm_start_info.html
106+
/// [`ByteValued`]: https://docs.rs/vm-memory/latest/vm_memory/bytes/trait.ByteValued.html
107+
fn write_bootparams<T, S, M>(
108+
header: (T, GuestAddress),
109+
sections: Option<(Vec<S>, GuestAddress)>,
110+
guest_memory: &M,
111+
) -> Result<()>
112+
where
113+
T: ByteValued,
114+
S: ByteValued,
115+
M: GuestMemory;
116+
}

src/configurator/x86_64/linux.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright © 2020, Oracle and/or its affiliates.
2+
//
3+
// Copyright (c) 2019 Intel Corporation. All rights reserved.
4+
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
//
6+
// Copyright 2017 The Chromium OS Authors. All rights reserved.
7+
// Use of this source code is governed by a BSD-style license that can be
8+
// found in the LICENSE-BSD-3-Clause file.
9+
//
10+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
11+
12+
//! Traits and structs for configuring and loading boot parameters on `x86_64` using the Linux
13+
//! boot protocol.
14+
15+
use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory};
16+
17+
use super::super::{BootConfigurator, Error as BootConfiguratorError, Result};
18+
use crate::loader::bootparam::boot_params;
19+
20+
use std::error::Error as StdError;
21+
use std::fmt;
22+
use std::mem;
23+
24+
/// Boot configurator for the Linux boot protocol.
25+
pub struct LinuxBootConfigurator {}
26+
27+
/// Errors specific to the Linux boot protocol configuration.
28+
#[derive(Debug, PartialEq)]
29+
pub enum Error {
30+
/// The zero page extends past the end of guest memory.
31+
ZeroPagePastRamEnd,
32+
/// Error writing to the zero page of guest memory.
33+
ZeroPageSetup,
34+
}
35+
36+
impl StdError for Error {
37+
fn description(&self) -> &str {
38+
use Error::*;
39+
match self {
40+
ZeroPagePastRamEnd => "The zero page extends past the end of guest memory.",
41+
ZeroPageSetup => "Error writing to the zero page of guest memory.",
42+
}
43+
}
44+
}
45+
46+
impl fmt::Display for Error {
47+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48+
write!(
49+
f,
50+
"Linux Boot Configurator Error: {}",
51+
StdError::description(self)
52+
)
53+
}
54+
}
55+
56+
impl From<Error> for BootConfiguratorError {
57+
fn from(err: Error) -> Self {
58+
BootConfiguratorError::Linux(err)
59+
}
60+
}
61+
62+
impl BootConfigurator for LinuxBootConfigurator {
63+
/// Writes the boot parameters (configured elsewhere) into guest memory.
64+
///
65+
/// # Arguments
66+
///
67+
/// * `header` - boot parameters encapsulated in a [`boot_params`] struct.
68+
/// * `sections` - unused.
69+
/// * `guest_memory` - guest's physical memory.
70+
///
71+
/// [`boot_params`]: ../loader/bootparam/struct.boot_e820_entry.html
72+
fn write_bootparams<T, S, M>(
73+
header: (T, GuestAddress),
74+
_sections: Option<(Vec<S>, GuestAddress)>,
75+
guest_memory: &M,
76+
) -> Result<()>
77+
where
78+
T: ByteValued,
79+
S: ByteValued,
80+
M: GuestMemory,
81+
{
82+
// The VMM has filled a `boot_params` struct and its e820 map.
83+
// This will be written in guest memory at the zero page.
84+
guest_memory
85+
.checked_offset(header.1, mem::size_of::<boot_params>())
86+
.ok_or(Error::ZeroPagePastRamEnd)?;
87+
guest_memory
88+
.write_obj(header.0, header.1)
89+
.map_err(|_| Error::ZeroPageSetup)?;
90+
91+
Ok(())
92+
}
93+
}
94+
95+
#[cfg(test)]
96+
mod tests {
97+
use super::*;
98+
use std::mem;
99+
use vm_memory::{Address, GuestAddress, GuestMemoryMmap};
100+
101+
const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
102+
const KERNEL_HDR_MAGIC: u32 = 0x53726448;
103+
const KERNEL_LOADER_OTHER: u8 = 0xff;
104+
const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000;
105+
const MEM_SIZE: u64 = 0x1000000;
106+
107+
fn create_guest_mem() -> GuestMemoryMmap {
108+
GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
109+
}
110+
111+
fn build_bootparams_common() -> boot_params {
112+
let mut params = boot_params::default();
113+
params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
114+
params.hdr.header = KERNEL_HDR_MAGIC;
115+
params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
116+
params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
117+
params
118+
}
119+
120+
#[test]
121+
fn test_configure_linux_boot() {
122+
let zero_page_addr = GuestAddress(0x30000);
123+
124+
let params = build_bootparams_common();
125+
// This is where we'd append e820 entries, cmdline, PCI, ACPI etc.
126+
127+
let guest_memory = create_guest_mem();
128+
129+
// Error case: boot params don't fit in guest memory (zero page address too close to end).
130+
let bad_zeropg_addr = GuestAddress(
131+
guest_memory.last_addr().raw_value() - mem::size_of::<boot_params>() as u64 + 1,
132+
);
133+
assert_eq!(
134+
LinuxBootConfigurator::write_bootparams::<boot_params, boot_params, GuestMemoryMmap>(
135+
(params, bad_zeropg_addr),
136+
None,
137+
&guest_memory,
138+
)
139+
.err(),
140+
Some(Error::ZeroPagePastRamEnd.into()),
141+
);
142+
143+
// Success case.
144+
assert!(
145+
LinuxBootConfigurator::write_bootparams::<boot_params, boot_params, GuestMemoryMmap>(
146+
(params, zero_page_addr),
147+
None,
148+
&guest_memory
149+
)
150+
.is_ok()
151+
);
152+
}
153+
}

src/configurator/x86_64/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright © 2020, Oracle and/or its affiliates.
2+
//
3+
// Copyright (c) 2019 Intel Corporation. All rights reserved.
4+
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
//
6+
// Copyright 2017 The Chromium OS Authors. All rights reserved.
7+
// Use of this source code is governed by a BSD-style license that can be
8+
// found in the LICENSE-BSD-3-Clause file.
9+
//
10+
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
11+
12+
//! Traits and structs for configuring and loading boot parameters on `x86_64`.
13+
14+
#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
15+
16+
pub mod linux;
17+
pub mod pvh;

0 commit comments

Comments
 (0)