linux_loader/configurator/x86_64/linux.rs
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
15use vm_memory::{Bytes, GuestMemory};
16
17use crate::configurator::{BootConfigurator, BootParams, Error as BootConfiguratorError, Result};
18
19use std::fmt;
20
21/// Boot configurator for the Linux boot protocol.
22pub struct LinuxBootConfigurator {}
23
24/// Errors specific to the Linux boot protocol configuration.
25#[derive(Debug, PartialEq, Eq)]
26pub enum Error {
27 /// The zero page extends past the end of guest memory.
28 ZeroPagePastRamEnd,
29 /// Error writing to the zero page of guest memory.
30 ZeroPageSetup,
31}
32
33impl fmt::Display for Error {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 use Error::*;
36 let desc = match self {
37 ZeroPagePastRamEnd => "the zero page extends past the end of guest memory.",
38 ZeroPageSetup => "error writing to the zero page of guest memory.",
39 };
40
41 write!(f, "Linux Boot Configurator: {}", desc,)
42 }
43}
44
45impl std::error::Error for Error {}
46
47impl From<Error> for BootConfiguratorError {
48 fn from(err: Error) -> Self {
49 BootConfiguratorError::Linux(err)
50 }
51}
52
53impl BootConfigurator for LinuxBootConfigurator {
54 /// Writes the boot parameters (configured elsewhere) into guest memory.
55 ///
56 /// # Arguments
57 ///
58 /// * `params` - boot parameters. The header contains a [`boot_params`] struct. The `sections`
59 /// and `modules` are unused.
60 /// * `guest_memory` - guest's physical memory.
61 ///
62 /// # Examples
63 ///
64 /// ```rust
65 /// # extern crate vm_memory;
66 /// # use linux_loader::configurator::{BootConfigurator, BootParams};
67 /// # use linux_loader::configurator::linux::LinuxBootConfigurator;
68 /// # use linux_loader::loader::bootparam::boot_params;
69 /// # use vm_memory::{Address, ByteValued, GuestMemory, GuestMemoryMmap, GuestAddress};
70 /// # const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
71 /// # const KERNEL_HDR_MAGIC: u32 = 0x53726448;
72 /// # const KERNEL_LOADER_OTHER: u8 = 0xff;
73 /// # const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000;
74 /// # const MEM_SIZE: u64 = 0x100_0000;
75 /// # fn create_guest_memory() -> GuestMemoryMmap {
76 /// # GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
77 /// # }
78 /// fn build_bootparams() -> boot_params {
79 /// let mut params = boot_params::default();
80 /// params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
81 /// params.hdr.header = KERNEL_HDR_MAGIC;
82 /// params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
83 /// params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
84 /// params
85 /// }
86 ///
87 /// fn main() {
88 /// # let zero_page_addr = GuestAddress(0x30000);
89 /// let guest_memory = create_guest_memory();
90 /// let params = build_bootparams();
91 /// let mut bootparams = BootParams::new::<boot_params>(¶ms, zero_page_addr);
92 /// LinuxBootConfigurator::write_bootparams::<GuestMemoryMmap>(&bootparams, &guest_memory)
93 /// .unwrap();
94 /// }
95 /// ```
96 ///
97 /// [`boot_params`]: ../loader/bootparam/struct.boot_params.html
98 fn write_bootparams<M>(params: &BootParams, guest_memory: &M) -> Result<()>
99 where
100 M: GuestMemory,
101 {
102 // The VMM has filled a `boot_params` struct and its e820 map.
103 // This will be written in guest memory at the zero page.
104 guest_memory
105 .checked_offset(params.header_start, params.header.len())
106 .ok_or(Error::ZeroPagePastRamEnd)?;
107 guest_memory
108 .write_slice(params.header.as_slice(), params.header_start)
109 .map_err(|_| Error::ZeroPageSetup)?;
110
111 Ok(())
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use crate::loader_gen::bootparam::boot_params;
119 use std::mem;
120 use vm_memory::{Address, GuestAddress, GuestMemoryMmap};
121
122 const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
123 const KERNEL_HDR_MAGIC: u32 = 0x53726448;
124 const KERNEL_LOADER_OTHER: u8 = 0xff;
125 const KERNEL_MIN_ALIGNMENT_BYTES: u32 = 0x1000000;
126 const MEM_SIZE: u64 = 0x100_0000;
127
128 fn create_guest_mem() -> GuestMemoryMmap {
129 GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
130 }
131
132 fn build_bootparams_common() -> boot_params {
133 let mut params = boot_params::default();
134 params.hdr.boot_flag = KERNEL_BOOT_FLAG_MAGIC;
135 params.hdr.header = KERNEL_HDR_MAGIC;
136 params.hdr.kernel_alignment = KERNEL_MIN_ALIGNMENT_BYTES;
137 params.hdr.type_of_loader = KERNEL_LOADER_OTHER;
138 params
139 }
140
141 #[test]
142 fn test_configure_linux_boot() {
143 let zero_page_addr = GuestAddress(0x30000);
144
145 let params = build_bootparams_common();
146 // This is where we'd append e820 entries, cmdline, PCI, ACPI etc.
147
148 let guest_memory = create_guest_mem();
149
150 // Error case: boot params don't fit in guest memory (zero page address too close to end).
151 let bad_zeropg_addr = GuestAddress(
152 guest_memory.last_addr().raw_value() - mem::size_of::<boot_params>() as u64 + 1,
153 );
154 let mut bootparams = BootParams::new::<boot_params>(¶ms, bad_zeropg_addr);
155 assert_eq!(
156 LinuxBootConfigurator::write_bootparams::<GuestMemoryMmap>(&bootparams, &guest_memory,)
157 .err(),
158 Some(Error::ZeroPagePastRamEnd.into()),
159 );
160
161 // Success case.
162 bootparams.header_start = zero_page_addr;
163 assert!(LinuxBootConfigurator::write_bootparams::<GuestMemoryMmap>(
164 &bootparams,
165 &guest_memory,
166 )
167 .is_ok());
168 }
169
170 #[test]
171 fn test_error_messages() {
172 assert_eq!(
173 format!("{}", Error::ZeroPagePastRamEnd),
174 "Linux Boot Configurator: the zero page extends past the end of guest memory."
175 );
176 assert_eq!(
177 format!("{}", Error::ZeroPageSetup),
178 "Linux Boot Configurator: error writing to the zero page of guest memory."
179 );
180 }
181}