loader.rs0.00%
1
// Copyright 2024 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
pub mod elf;16
#[path = "firmware/firmware.rs"]17
pub mod firmware;18
#[path = "linux/linux.rs"]19
pub mod linux;20
#[cfg(target_arch = "x86_64")]21
#[path = "xen/xen.rs"]22
pub mod xen;23
24
use std::ffi::CString;25
use std::ops::Range;26
use std::path::Path;27
28
use serde::Deserialize;29
use snafu::Snafu;30
31
#[cfg(target_arch = "x86_64")]32
use crate::arch::reg::{DtReg, DtRegVal, SegReg, SegRegVal};33
use crate::arch::reg::{Reg, SReg};34
use crate::errors::{DebugTrace, trace_error};35
use crate::mem::{MemRegionEntry, MemRegionType};36
37
#[derive(Debug, Default, PartialEq, Eq, Deserialize)]38
pub 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)]46
pub enum Executable {47
Linux(Box<Path>),48
#[cfg(target_arch = "x86_64")]49
Pvh(Box<Path>),50
}51
52
#[derive(Debug, Clone, Default)]53
pub 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)))]66
pub 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
100
pub type Result<T, E = Error> = std::result::Result<T, E>;101
102
pub 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