blob: c81b57cbdddade51c7ea05bc1a2eea8409e266e3 [file] [log] [blame]
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +01001// 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 entry and exit points of pvmfw.
16
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010017use crate::config;
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +010018use crate::crypto;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000019use crate::fdt;
Alice Wang93ee98a2023-06-08 08:20:39 +000020use crate::memory;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010021use core::arch::asm;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +010022use core::mem::{drop, size_of};
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000023use core::num::NonZeroUsize;
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010024use core::ops::Range;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010025use core::slice;
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +000026use hyp::{get_mem_sharer, get_mmio_guard};
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010027use log::debug;
28use log::error;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000029use log::info;
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010030use log::warn;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010031use log::LevelFilter;
Alice Wang4be4dd02023-06-07 07:50:40 +000032use vmbase::util::RangeExt as _;
Alice Wangeacb7382023-06-05 12:53:54 +000033use vmbase::{
Pierre-Clément Tosi6a4808c2023-06-29 09:19:38 +000034 configure_heap, console,
Alice Wang4c70d142023-06-06 11:52:33 +000035 layout::{self, crosvm},
Pierre-Clément Tosid3305482023-06-29 15:03:48 +000036 main,
Pierre-Clément Tosif3681e82023-06-22 11:38:22 +000037 memory::{min_dcache_line_size, MemoryTracker, MEMORY, SIZE_128KB, SIZE_4KB},
Alice Wangeacb7382023-06-05 12:53:54 +000038 power::reboot,
Pierre-Clément Tosi3e3d7332023-06-22 10:44:29 +000039 rand,
Alice Wangeacb7382023-06-05 12:53:54 +000040};
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010041use zeroize::Zeroize;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010042
43#[derive(Debug, Clone)]
Andrew Walbran19690632022-12-07 16:41:30 +000044pub enum RebootReason {
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010045 /// A malformed BCC was received.
46 InvalidBcc,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010047 /// An invalid configuration was appended to pvmfw.
48 InvalidConfig,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010049 /// An unexpected internal error happened.
50 InternalError,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000051 /// The provided FDT was invalid.
52 InvalidFdt,
53 /// The provided payload was invalid.
54 InvalidPayload,
55 /// The provided ramdisk was invalid.
56 InvalidRamdisk,
Alice Wang28cbcf12022-12-01 07:58:28 +000057 /// Failed to verify the payload.
58 PayloadVerificationError,
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000059 /// DICE layering process failed.
60 SecretDerivationError,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010061}
62
63main!(start);
Pierre-Clément Tosi6a4808c2023-06-29 09:19:38 +000064configure_heap!(SIZE_128KB);
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010065
66/// Entry point for pVM firmware.
67pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
68 // Limitations in this function:
69 // - can't access non-pvmfw memory (only statically-mapped memory)
70 // - can't access MMIO (therefore, no logging)
71
72 match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010073 Ok((entry, bcc)) => jump_to_payload(fdt_address, entry.try_into().unwrap(), bcc),
Pierre-Clément Tosid836b5b2022-12-05 10:49:38 +000074 Err(_) => reboot(), // TODO(b/220071963) propagate the reason back to the host.
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010075 }
76
77 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
78}
79
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000080struct MemorySlices<'a> {
81 fdt: &'a mut libfdt::Fdt,
82 kernel: &'a [u8],
83 ramdisk: Option<&'a [u8]>,
84}
85
86impl<'a> MemorySlices<'a> {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010087 fn new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason> {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000088 // SAFETY - SIZE_2MB is non-zero.
Alice Wange9ae5c42023-06-12 11:14:13 +000089 const FDT_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(crosvm::FDT_MAX_SIZE) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000090 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
91 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
92 // overwrite with the template DT and apply the DTBO.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010093 let range = MEMORY.lock().as_mut().unwrap().alloc_mut(fdt, FDT_SIZE).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000094 error!("Failed to allocate the FDT range: {e}");
95 RebootReason::InternalError
96 })?;
97
98 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
99 let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
100 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
101 error!("Failed to spawn the FDT wrapper: {e}");
102 RebootReason::InvalidFdt
103 })?;
104
Jiyong Park6a8789a2023-03-21 14:50:59 +0900105 let info = fdt::sanitize_device_tree(fdt)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000106 debug!("Fdt passed validation!");
107
Jiyong Park6a8789a2023-03-21 14:50:59 +0900108 let memory_range = info.memory_range;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000109 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100110 MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
111 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000112 RebootReason::InvalidFdt
113 })?;
114
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000115 if let Some(mem_sharer) = get_mem_sharer() {
116 let granule = mem_sharer.granule().map_err(|e| {
Alice Wangb6d2c642023-06-13 13:07:06 +0000117 error!("Failed to get memory protection granule: {e}");
118 RebootReason::InternalError
119 })?;
120 MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).map_err(|e| {
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000121 error!("Failed to initialize dynamically shared pool: {e}");
122 RebootReason::InternalError
123 })?;
124 } else {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700125 let range = info.swiotlb_info.fixed_range().ok_or_else(|| {
126 error!("Pre-shared pool range not specified in swiotlb node");
127 RebootReason::InvalidFdt
128 })?;
129
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100130 MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700131 error!("Failed to initialize pre-shared pool {e}");
132 RebootReason::InvalidFdt
133 })?;
134 }
135
Jiyong Park6a8789a2023-03-21 14:50:59 +0900136 let kernel_range = if let Some(r) = info.kernel_range {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100137 MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000138 error!("Failed to obtain the kernel range with DT range: {e}");
139 RebootReason::InternalError
140 })?
141 } else if cfg!(feature = "legacy") {
142 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
143
144 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
145 error!("Invalid kernel size: {kernel_size:#x}");
146 RebootReason::InvalidPayload
147 })?;
148
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100149 MEMORY.lock().as_mut().unwrap().alloc(kernel, kernel_size).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000150 error!("Failed to obtain the kernel range with legacy range: {e}");
151 RebootReason::InternalError
152 })?
153 } else {
154 error!("Failed to locate the kernel from the DT");
155 return Err(RebootReason::InvalidPayload);
156 };
157
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000158 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
159 let kernel =
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000160 unsafe { slice::from_raw_parts(kernel_range.start as *const u8, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000161
Jiyong Park6a8789a2023-03-21 14:50:59 +0900162 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000163 debug!("Located ramdisk at {r:?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100164 let r = MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000165 error!("Failed to obtain the initrd range: {e}");
166 RebootReason::InvalidRamdisk
167 })?;
168
169 // SAFETY - The region was validated by memory to be in main memory, mapped, and
170 // not overlap.
171 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
172 } else {
173 info!("Couldn't locate the ramdisk from the device tree");
174 None
175 };
176
177 Ok(Self { fdt, kernel, ramdisk })
178 }
179}
180
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100181/// Sets up the environment for main() and wraps its result for start().
182///
183/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
184/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100185fn main_wrapper(
186 fdt: usize,
187 payload: usize,
188 payload_size: usize,
189) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100190 // Limitations in this function:
191 // - only access MMIO once (and while) it has been mapped and configured
192 // - only perform logging once the logger has been initialized
193 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100194
Pierre-Clément Tosid3305482023-06-29 15:03:48 +0000195 log::set_max_level(LevelFilter::Info);
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100196 crypto::init();
197
Alice Wang807fa592023-06-02 09:54:43 +0000198 let page_table = memory::init_page_table().map_err(|e| {
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000199 error!("Failed to set up the dynamic page tables: {e}");
200 RebootReason::InternalError
201 })?;
Alan Stokesc3829f12023-06-02 15:02:23 +0100202
203 // SAFETY - We only get the appended payload from here, once. The region was statically mapped,
204 // then remapped by `init_page_table()`.
205 let appended_data = unsafe { get_appended_data_slice() };
206
207 let mut appended = AppendedPayload::new(appended_data).ok_or_else(|| {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100208 error!("No valid configuration found");
209 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000210 })?;
211
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000212 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100213
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100214 // Up to this point, we were using the built-in static (from .rodata) page tables.
Alice Wang4c70d142023-06-06 11:52:33 +0000215 MEMORY.lock().replace(MemoryTracker::new(
216 page_table,
Alice Wang63f4c9e2023-06-12 09:36:43 +0000217 crosvm::MEM_START..layout::MAX_VIRT_ADDR,
Alice Wang89d29592023-06-12 09:41:29 +0000218 crosvm::MMIO_RANGE,
Alice Wang5bb79502023-06-12 09:25:07 +0000219 Some(memory::appended_payload_range()),
Alice Wang4c70d142023-06-06 11:52:33 +0000220 ));
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100221
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100222 let slices = MemorySlices::new(fdt, payload, payload_size)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000223
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000224 rand::init().map_err(|e| {
225 error!("Failed to initialize rand: {e}");
226 RebootReason::InternalError
227 })?;
228
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100229 // This wrapper allows main() to be blissfully ignorant of platform details.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100230 let next_bcc = crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy)?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100231
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100232 // Writable-dirty regions will be flushed when MemoryTracker is dropped.
233 bcc_slice.zeroize();
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100234
Andrew Walbran19690632022-12-07 16:41:30 +0000235 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100236 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000237 error!("Failed to unshare MMIO ranges: {e}");
238 RebootReason::InternalError
239 })?;
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000240 // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
241 MEMORY.lock().as_mut().unwrap().unshare_all_memory();
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000242 if let Some(mmio_guard) = get_mmio_guard() {
243 mmio_guard.unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi5ad1e8c2023-06-29 10:36:48 +0000244 error!("Failed to unshare the UART: {e}");
245 RebootReason::InternalError
246 })?;
247 }
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100248
249 // Drop MemoryTracker and deactivate page table.
250 drop(MEMORY.lock().take());
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100251
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100252 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100253}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100254
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100255fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
256 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000257 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100258 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000259 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100260 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000261 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100262 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000263 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100264
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000265 const SCTLR_EL1_VAL: u64 = SCTLR_EL1_RES1 | SCTLR_EL1_ITD | SCTLR_EL1_SED | SCTLR_EL1_I;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100266
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100267 let scratch = layout::scratch_range();
268
Alice Wanga3931aa2023-07-05 12:52:09 +0000269 assert_ne!(scratch.end - scratch.start, 0, "scratch memory is empty.");
270 assert_eq!(scratch.start.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
271 assert_eq!(scratch.end.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100272
Alice Wanga3931aa2023-07-05 12:52:09 +0000273 assert!(bcc.is_within(&(scratch.start.0..scratch.end.0)));
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100274 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
275 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
276
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000277 let stack = memory::stack_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100278
Alice Wanga3931aa2023-07-05 12:52:09 +0000279 assert_ne!(stack.end - stack.start, 0, "stack region is empty.");
280 assert_eq!(stack.start.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
281 assert_eq!(stack.end.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100282
283 // Zero all memory that could hold secrets and that can't be safely written to from Rust.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000284 // Disable the exception vector, caches and page table and then jump to the payload at the
285 // given address, passing it the given FDT pointer.
286 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100287 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
288 unsafe {
289 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100290 "cmp {scratch}, {bcc}",
291 "b.hs 1f",
292
293 // Zero .data & .bss until BCC.
294 "0: stp xzr, xzr, [{scratch}], 16",
295 "cmp {scratch}, {bcc}",
296 "b.lo 0b",
297
298 "1:",
299 // Skip BCC.
300 "mov {scratch}, {bcc_end}",
301 "cmp {scratch}, {scratch_end}",
302 "b.hs 1f",
303
304 // Keep zeroing .data & .bss.
305 "0: stp xzr, xzr, [{scratch}], 16",
306 "cmp {scratch}, {scratch_end}",
307 "b.lo 0b",
308
309 "1:",
310 // Flush d-cache over .data & .bss (including BCC).
311 "0: dc cvau, {cache_line}",
312 "add {cache_line}, {cache_line}, {dcache_line_size}",
313 "cmp {cache_line}, {scratch_end}",
314 "b.lo 0b",
315
316 "mov {cache_line}, {stack}",
317 // Zero stack region.
318 "0: stp xzr, xzr, [{stack}], 16",
319 "cmp {stack}, {stack_end}",
320 "b.lo 0b",
321
322 // Flush d-cache over stack region.
323 "0: dc cvau, {cache_line}",
324 "add {cache_line}, {cache_line}, {dcache_line_size}",
325 "cmp {cache_line}, {stack_end}",
326 "b.lo 0b",
327
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100328 "msr sctlr_el1, {sctlr_el1_val}",
329 "isb",
330 "mov x1, xzr",
331 "mov x2, xzr",
332 "mov x3, xzr",
333 "mov x4, xzr",
334 "mov x5, xzr",
335 "mov x6, xzr",
336 "mov x7, xzr",
337 "mov x8, xzr",
338 "mov x9, xzr",
339 "mov x10, xzr",
340 "mov x11, xzr",
341 "mov x12, xzr",
342 "mov x13, xzr",
343 "mov x14, xzr",
344 "mov x15, xzr",
345 "mov x16, xzr",
346 "mov x17, xzr",
347 "mov x18, xzr",
348 "mov x19, xzr",
349 "mov x20, xzr",
350 "mov x21, xzr",
351 "mov x22, xzr",
352 "mov x23, xzr",
353 "mov x24, xzr",
354 "mov x25, xzr",
355 "mov x26, xzr",
356 "mov x27, xzr",
357 "mov x28, xzr",
358 "mov x29, xzr",
359 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100360 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100361 "dsb nsh",
362 "br x30",
363 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100364 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
365 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
Alice Wanga3931aa2023-07-05 12:52:09 +0000366 cache_line = in(reg) u64::try_from(scratch.start.0).unwrap(),
367 scratch = in(reg) u64::try_from(scratch.start.0).unwrap(),
368 scratch_end = in(reg) u64::try_from(scratch.end.0).unwrap(),
369 stack = in(reg) u64::try_from(stack.start.0).unwrap(),
370 stack_end = in(reg) u64::try_from(stack.end.0).unwrap(),
Alice Wang3fa9b802023-06-06 07:52:31 +0000371 dcache_line_size = in(reg) u64::try_from(min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100372 in("x0") fdt_address,
373 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100374 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100375 );
376 };
377}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100378
Alan Stokesc3829f12023-06-02 15:02:23 +0100379/// # Safety
380///
381/// This must only be called once, since we are returning a mutable reference.
382/// The appended data region must be mapped.
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100383unsafe fn get_appended_data_slice() -> &'static mut [u8] {
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000384 let range = memory::appended_payload_range();
Alan Stokesa0e42962023-04-14 17:59:50 +0100385 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
386 // objects.
Alice Wanga3931aa2023-07-05 12:52:09 +0000387 unsafe { slice::from_raw_parts_mut(range.start.0 as *mut u8, range.end - range.start) }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100388}
389
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000390enum AppendedConfigType {
391 Valid,
392 Invalid,
393 NotFound,
394}
395
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100396enum AppendedPayload<'a> {
397 /// Configuration data.
398 Config(config::Config<'a>),
399 /// Deprecated raw BCC, as used in Android T.
400 LegacyBcc(&'a mut [u8]),
401}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100402
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100403impl<'a> AppendedPayload<'a> {
Alan Stokesc3829f12023-06-02 15:02:23 +0100404 fn new(data: &'a mut [u8]) -> Option<Self> {
405 match Self::guess_config_type(data) {
Alan Stokesa0e42962023-04-14 17:59:50 +0100406 AppendedConfigType::Valid => {
Alan Stokesc3829f12023-06-02 15:02:23 +0100407 let config = config::Config::new(data);
Alan Stokesa0e42962023-04-14 17:59:50 +0100408 Some(Self::Config(config.unwrap()))
409 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000410 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
Alice Wangeacb7382023-06-05 12:53:54 +0000411 const BCC_SIZE: usize = SIZE_4KB;
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000412 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
413 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
414 }
415 _ => None,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100416 }
417 }
418
Alan Stokesc3829f12023-06-02 15:02:23 +0100419 fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100420 // This function is necessary to prevent the borrow checker from getting confused
421 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
422 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100423
Alan Stokesc3829f12023-06-02 15:02:23 +0100424 match config::Config::new(data) {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000425 Err(config::Error::InvalidMagic) => {
426 warn!("No configuration data found at {addr:?}");
427 AppendedConfigType::NotFound
428 }
429 Err(e) => {
430 error!("Invalid configuration data at {addr:?}: {e}");
431 AppendedConfigType::Invalid
432 }
433 Ok(_) => AppendedConfigType::Valid,
434 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100435 }
436
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000437 fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100438 match self {
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000439 Self::Config(ref mut cfg) => cfg.get_entries(),
440 Self::LegacyBcc(ref mut bcc) => (bcc, None),
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000441 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100442 }
443}