blob: a0d2b14c2b7e2de130cef7f9c9fc605a74a91f60 [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;
18use crate::fdt;
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000019use aarch64_paging::MapError;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000020use core::num::NonZeroUsize;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000021use core::result;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000022use core::slice;
23use log::debug;
Alice Wang93ee98a2023-06-08 08:20:39 +000024use log::error;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000025use log::info;
26use log::warn;
Pierre-Clément Tosi3d4c5c32023-05-31 16:57:06 +000027use vmbase::{
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000028 layout::{self, crosvm},
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000029 memory::{init_shared_pool, map_data, map_rodata, resize_available_memory, PageTable},
Pierre-Clément Tosi3d4c5c32023-05-31 16:57:06 +000030};
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000031
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000032pub fn init_page_table() -> result::Result<PageTable, MapError> {
Alice Wangee5b1802023-06-07 07:41:54 +000033 let mut page_table = PageTable::default();
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000034
35 // Stack and scratch ranges are explicitly zeroed and flushed before jumping to payload,
36 // so dirty state management can be omitted.
Pierre-Clément Tosi0b02a2b2024-11-28 22:48:27 +000037 page_table.map_data(&layout::data_bss_range().into())?;
38 page_table.map_data(&layout::eh_stack_range().into())?;
Pierre-Clément Tosieba83162024-11-02 12:11:48 +000039 page_table.map_data(&layout::stack_range().into())?;
Alice Wanga3931aa2023-07-05 12:52:09 +000040 page_table.map_code(&layout::text_range().into())?;
41 page_table.map_rodata(&layout::rodata_range().into())?;
Pierre-Clément Tosi38a36212024-06-06 11:30:39 +010042 if let Err(e) = page_table.map_device(&layout::console_uart_page().into()) {
Alice Wang807fa592023-06-02 09:54:43 +000043 error!("Failed to remap the UART as a dynamic page table entry: {e}");
44 return Err(e);
45 }
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000046 Ok(page_table)
47}
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000048
49pub(crate) struct MemorySlices<'a> {
50 pub fdt: &'a mut libfdt::Fdt,
51 pub kernel: &'a [u8],
52 pub ramdisk: Option<&'a [u8]>,
53}
54
55impl<'a> MemorySlices<'a> {
56 pub fn new(
57 fdt: usize,
58 kernel: usize,
59 kernel_size: usize,
60 vm_dtbo: Option<&mut [u8]>,
61 vm_ref_dt: Option<&[u8]>,
62 ) -> Result<Self, RebootReason> {
63 let fdt_size = NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap();
64 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
65 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
66 // overwrite with the template DT and apply the DTBO.
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000067 map_data(fdt, fdt_size).map_err(|e| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000068 error!("Failed to allocate the FDT range: {e}");
69 RebootReason::InternalError
70 })?;
71
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000072 // SAFETY: map_data validated the range to be in main memory, mapped, and not overlap.
73 let fdt = unsafe { slice::from_raw_parts_mut(fdt as *mut u8, fdt_size.into()) };
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000074
75 let info = fdt::sanitize_device_tree(fdt, vm_dtbo, vm_ref_dt)?;
76 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
77 error!("Failed to load sanitized FDT: {e}");
78 RebootReason::InvalidFdt
79 })?;
80 debug!("Fdt passed validation!");
81
82 let memory_range = info.memory_range;
83 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000084 resize_available_memory(&memory_range).map_err(|e| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000085 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
86 RebootReason::InvalidFdt
87 })?;
88
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000089 init_shared_pool(info.swiotlb_info.fixed_range()).map_err(|e| {
90 error!("Failed to initialize shared pool: {e}");
91 RebootReason::InternalError
92 })?;
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000093
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000094 let (kernel_start, kernel_size) = if let Some(r) = info.kernel_range {
95 let size = r.len().try_into().map_err(|_| {
96 error!("Invalid kernel size: {:#x}", r.len());
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +000097 RebootReason::InternalError
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000098 })?;
99 (r.start, size)
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000100 } else if cfg!(feature = "legacy") {
101 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000102 let size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000103 error!("Invalid kernel size: {kernel_size:#x}");
104 RebootReason::InvalidPayload
105 })?;
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000106 (kernel, size)
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000107 } else {
108 error!("Failed to locate the kernel from the DT");
109 return Err(RebootReason::InvalidPayload);
110 };
111
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000112 map_rodata(kernel_start, kernel_size).map_err(|e| {
113 error!("Failed to map kernel range: {e}");
114 RebootReason::InternalError
115 })?;
116
117 let kernel = kernel_start as *const u8;
118 // SAFETY: map_rodata validated the range to be in main memory, mapped, and not overlap.
119 let kernel = unsafe { slice::from_raw_parts(kernel, kernel_size.into()) };
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000120
121 let ramdisk = if let Some(r) = info.initrd_range {
122 debug!("Located ramdisk at {r:?}");
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000123 let ramdisk_size = r.len().try_into().map_err(|_| {
124 error!("Invalid ramdisk size: {:#x}", r.len());
125 RebootReason::InvalidRamdisk
126 })?;
127 map_rodata(r.start, ramdisk_size).map_err(|e| {
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000128 error!("Failed to obtain the initrd range: {e}");
129 RebootReason::InvalidRamdisk
130 })?;
131
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000132 // SAFETY: map_rodata validated the range to be in main memory, mapped, and not
133 // overlap.
Pierre-Clément Tosi462bdf42024-10-30 17:46:23 +0000134 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
135 } else {
136 info!("Couldn't locate the ramdisk from the device tree");
137 None
138 };
139
140 Ok(Self { fdt, kernel, ramdisk })
141 }
142}