Alioth Code Coverage

loader.rs0.00%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub mod elf;
16#[path = "firmware/firmware.rs"]
17pub mod firmware;
18#[path = "linux/linux.rs"]
19pub mod linux;
20#[cfg(target_arch = "x86_64")]
21#[path = "xen/xen.rs"]
22pub mod xen;
23
24use std::ffi::CString;
25use std::ops::Range;
26use std::path::Path;
27
28use serde::Deserialize;
29use snafu::Snafu;
30
31#[cfg(target_arch = "x86_64")]
32use crate::arch::reg::{DtReg, DtRegVal, SegReg, SegRegVal};
33use crate::arch::reg::{Reg, SReg};
34use crate::errors::{DebugTrace, trace_error};
35use crate::mem::{MemRegionEntry, MemRegionType};
36
37#[derive(Debug, Default, PartialEq, Eq, Deserialize)]
38pub struct Payload {
39 pub firmware: Option<Box<Path>>,
40 pub executable: Option<Executable>,
41 pub initramfs: Option<Box<Path>>,
42 pub cmdline: Option<CString>,
43}
44
45#[derive(Debug, PartialEq, Eq, Deserialize)]
46pub enum Executable {
47 Linux(Box<Path>),
48 #[cfg(target_arch = "x86_64")]
49 Pvh(Box<Path>),
50}
51
52#[derive(Debug, Clone, Default)]
53pub struct InitState {
54 pub regs: Vec<(Reg, u64)>,
55 pub sregs: Vec<(SReg, u64)>,
56 #[cfg(target_arch = "x86_64")]
57 pub dt_regs: Vec<(DtReg, DtRegVal)>,
58 #[cfg(target_arch = "x86_64")]
59 pub seg_regs: Vec<(SegReg, SegRegVal)>,
60 pub initramfs: Option<Range<u64>>,
61}
62
63#[trace_error]
64#[derive(Snafu, DebugTrace)]
65#[snafu(module, context(suffix(false)))]
66pub enum Error {
67 #[snafu(display("Cannot access file {path:?}"))]
68 AccessFile {
69 path: Box<Path>,
70 error: std::io::Error,
71 },
72 #[snafu(display("Firmware image size is not 4-KiB aligned"))]
73 SizeNotAligned { size: u64 },
74 #[snafu(display("Failed to add a guest memory slot"))]
75 AddMemSlot { source: Box<crate::mem::Error> },
76 #[snafu(display("Failed to access guest memory"), context(false))]
77 RwMemory { source: Box<crate::mem::Error> },
78 #[snafu(display("Missing magic number {magic:#x}, found {found:#x}"))]
79 MissingMagic { magic: u64, found: u64 },
80 #[snafu(display("Cannot find payload entry point"))]
81 NoEntryPoint,
82 #[snafu(display("Not a 64-bit kernel"))]
83 Not64Bit,
84 #[snafu(display("Not a relocatable kernel"))]
85 NotRelocatable,
86 #[snafu(display("Kernel command line too long, length: {len}, limit: {limit}"))]
87 CmdLineTooLong { len: usize, limit: u64 },
88 #[snafu(display("Cannot find a memory region to load initramfs"))]
89 CannotLoadInitramfs,
90 #[snafu(display(
91 "{name} is too old, minimum supported version {min:#x}, found version {found:#x}"
92 ))]
93 TooOld {
94 name: &'static str,
95 min: u64,
96 found: u64,
97 },
98}
99
100pub type Result<T, E = Error> = std::result::Result<T, E>;
101
102pub fn search_initramfs_address(
103 entries: &[(u64, MemRegionEntry)],
104 size: u64,
105 addr_max: u64,
106) -> Result<u64, Error> {
107 for (start, entry) in entries.iter().rev() {
108 let region_max = entry.size - 1 + start;
109 let limit = std::cmp::min(region_max, addr_max);
110 if limit < size - 1 {
111 continue;
112 }
113 let load_addr = (limit - (size - 1)) & !0xfff;
114 if entry.type_ == MemRegionType::Ram && load_addr >= *start {
115 return Ok(load_addr);
116 }
117 }
118 error::CannotLoadInitramfs.fail()
119}
120