blob: a663008df0defe7d5d7afa1c1c01f77bd882a550 [file] [log] [blame]
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +00001// Copyright 2022, The Android Open Source Project
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// http://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
15//! Low-level allocation and tracking of main memory.
16
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000017use crate::entry::RebootReason;
Pierre-Clément Tosi92778802024-11-19 17:36:14 +000018use crate::fdt::{read_initrd_range_from, read_kernel_range_from};
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000019use core::num::NonZeroUsize;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000020use core::slice;
21use log::debug;
Alice Wang93ee98a2023-06-08 08:20:39 +000022use log::error;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000023use log::info;
24use log::warn;
Pierre-Clément Tosi3d4c5c32023-05-31 16:57:06 +000025use vmbase::{
Pierre-Clément Tosiae071612024-11-02 13:13:34 +000026 layout::crosvm,
Pierre-Clément Tosi92778802024-11-19 17:36:14 +000027 memory::{map_data, map_rodata, resize_available_memory},
Pierre-Clément Tosi3d4c5c32023-05-31 16:57:06 +000028};
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000029
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000030pub(crate) struct MemorySlices<'a> {
31 pub fdt: &'a mut libfdt::Fdt,
32 pub kernel: &'a [u8],
33 pub ramdisk: Option<&'a [u8]>,
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +000034 pub dice_chain: Option<&'a [u8]>,
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000035}
36
37impl<'a> MemorySlices<'a> {
Pierre-Clément Tosi92778802024-11-19 17:36:14 +000038 pub fn new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason> {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000039 let fdt_size = NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap();
40 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
41 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
42 // overwrite with the template DT and apply the DTBO.
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000043 map_data(fdt, fdt_size).map_err(|e| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000044 error!("Failed to allocate the FDT range: {e}");
45 RebootReason::InternalError
46 })?;
47
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000048 // SAFETY: map_data validated the range to be in main memory, mapped, and not overlap.
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000049 let untrusted_fdt = unsafe { slice::from_raw_parts_mut(fdt as *mut u8, fdt_size.into()) };
50 let untrusted_fdt = libfdt::Fdt::from_mut_slice(untrusted_fdt).map_err(|e| {
51 error!("Failed to load input FDT: {e}");
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000052 RebootReason::InvalidFdt
53 })?;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000054
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000055 let memory_range = untrusted_fdt.first_memory_range().map_err(|e| {
56 error!("Failed to read memory range from DT: {e}");
57 RebootReason::InvalidFdt
58 })?;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000059 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000060 resize_available_memory(&memory_range).map_err(|e| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000061 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
62 RebootReason::InvalidFdt
63 })?;
64
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000065 let kernel_range = read_kernel_range_from(untrusted_fdt).map_err(|e| {
66 error!("Failed to read kernel range: {e}");
67 RebootReason::InvalidFdt
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000068 })?;
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000069 let (kernel_start, kernel_size) = if let Some(r) = kernel_range {
70 (r.start, r.len())
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000071 } else if cfg!(feature = "legacy") {
72 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000073 (kernel, kernel_size)
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000074 } else {
75 error!("Failed to locate the kernel from the DT");
76 return Err(RebootReason::InvalidPayload);
77 };
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000078 let kernel_size = kernel_size.try_into().map_err(|_| {
79 error!("Invalid kernel size: {kernel_size:#x}");
80 RebootReason::InvalidPayload
81 })?;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000082
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000083 map_rodata(kernel_start, kernel_size).map_err(|e| {
84 error!("Failed to map kernel range: {e}");
85 RebootReason::InternalError
86 })?;
87
88 let kernel = kernel_start as *const u8;
89 // SAFETY: map_rodata validated the range to be in main memory, mapped, and not overlap.
90 let kernel = unsafe { slice::from_raw_parts(kernel, kernel_size.into()) };
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000091
Pierre-Clément Tosi0d4c09b2024-11-19 17:32:15 +000092 let initrd_range = read_initrd_range_from(untrusted_fdt).map_err(|e| {
93 error!("Failed to read initrd range: {e}");
94 RebootReason::InvalidFdt
95 })?;
96 let ramdisk = if let Some(r) = initrd_range {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000097 debug!("Located ramdisk at {r:?}");
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000098 let ramdisk_size = r.len().try_into().map_err(|_| {
99 error!("Invalid ramdisk size: {:#x}", r.len());
100 RebootReason::InvalidRamdisk
101 })?;
102 map_rodata(r.start, ramdisk_size).map_err(|e| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000103 error!("Failed to obtain the initrd range: {e}");
104 RebootReason::InvalidRamdisk
105 })?;
106
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000107 // SAFETY: map_rodata validated the range to be in main memory, mapped, and not
108 // overlap.
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000109 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
110 } else {
111 info!("Couldn't locate the ramdisk from the device tree");
112 None
113 };
114
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000115 let dice_chain = None;
116
117 Ok(Self { fdt: untrusted_fdt, kernel, ramdisk, dice_chain })
118 }
119
120 pub fn add_dice_chain(&mut self, dice_chain: &'a [u8]) {
121 self.dice_chain = Some(dice_chain)
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000122 }
123}