blob: 8c4396dfe520046e8f18fa65282d8fd32aa926ca [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 Tosia0934c12022-11-25 20:54:11 +000018use crate::fdt;
Alice Wang93ee98a2023-06-08 08:20:39 +000019use crate::memory;
Maurice Lam0322b8c2023-12-18 22:13:48 +000020use bssl_sys::CRYPTO_library_init;
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,
39};
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010040use zeroize::Zeroize;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010041
42#[derive(Debug, Clone)]
Andrew Walbran19690632022-12-07 16:41:30 +000043pub enum RebootReason {
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010044 /// A malformed BCC was received.
45 InvalidBcc,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010046 /// An invalid configuration was appended to pvmfw.
47 InvalidConfig,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010048 /// An unexpected internal error happened.
49 InternalError,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000050 /// The provided FDT was invalid.
51 InvalidFdt,
52 /// The provided payload was invalid.
53 InvalidPayload,
54 /// The provided ramdisk was invalid.
55 InvalidRamdisk,
Alice Wang28cbcf12022-12-01 07:58:28 +000056 /// Failed to verify the payload.
57 PayloadVerificationError,
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000058 /// DICE layering process failed.
59 SecretDerivationError,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010060}
61
62main!(start);
Pierre-Clément Tosi6a4808c2023-06-29 09:19:38 +000063configure_heap!(SIZE_128KB);
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010064
65/// Entry point for pVM firmware.
66pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
67 // Limitations in this function:
68 // - can't access non-pvmfw memory (only statically-mapped memory)
69 // - can't access MMIO (therefore, no logging)
70
71 match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010072 Ok((entry, bcc)) => jump_to_payload(fdt_address, entry.try_into().unwrap(), bcc),
Pierre-Clément Tosid836b5b2022-12-05 10:49:38 +000073 Err(_) => reboot(), // TODO(b/220071963) propagate the reason back to the host.
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010074 }
75
76 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
77}
78
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000079struct MemorySlices<'a> {
80 fdt: &'a mut libfdt::Fdt,
81 kernel: &'a [u8],
82 ramdisk: Option<&'a [u8]>,
83}
84
85impl<'a> MemorySlices<'a> {
Jaewan Kimc6e023b2023-10-12 15:11:05 +090086 fn new(
87 fdt: usize,
88 kernel: usize,
89 kernel_size: usize,
90 vm_dtbo: Option<&mut [u8]>,
91 ) -> Result<Self, RebootReason> {
Pierre-Clément Tosid88fd2d2023-07-07 15:54:33 +000092 let fdt_size = NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap();
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000093 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
94 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
95 // overwrite with the template DT and apply the DTBO.
Pierre-Clément Tosid88fd2d2023-07-07 15:54:33 +000096 let range = MEMORY.lock().as_mut().unwrap().alloc_mut(fdt, fdt_size).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000097 error!("Failed to allocate the FDT range: {e}");
98 RebootReason::InternalError
99 })?;
100
Andrew Walbran20bb4e42023-07-07 13:55:55 +0100101 // SAFETY: The tracker validated the range to be in main memory, mapped, and not overlap.
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000102 let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
Jaewan Kimc6e023b2023-10-12 15:11:05 +0900103
104 let info = fdt::sanitize_device_tree(fdt, vm_dtbo)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000105 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
Jaewan Kimc6e023b2023-10-12 15:11:05 +0900106 error!("Failed to load sanitized FDT: {e}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000107 RebootReason::InvalidFdt
108 })?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000109 debug!("Fdt passed validation!");
110
Jiyong Park6a8789a2023-03-21 14:50:59 +0900111 let memory_range = info.memory_range;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000112 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100113 MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
114 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000115 RebootReason::InvalidFdt
116 })?;
117
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000118 if let Some(mem_sharer) = get_mem_sharer() {
119 let granule = mem_sharer.granule().map_err(|e| {
Alice Wangb6d2c642023-06-13 13:07:06 +0000120 error!("Failed to get memory protection granule: {e}");
121 RebootReason::InternalError
122 })?;
123 MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).map_err(|e| {
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000124 error!("Failed to initialize dynamically shared pool: {e}");
125 RebootReason::InternalError
126 })?;
127 } else {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700128 let range = info.swiotlb_info.fixed_range().ok_or_else(|| {
129 error!("Pre-shared pool range not specified in swiotlb node");
130 RebootReason::InvalidFdt
131 })?;
132
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100133 MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700134 error!("Failed to initialize pre-shared pool {e}");
135 RebootReason::InvalidFdt
136 })?;
137 }
138
Jiyong Park6a8789a2023-03-21 14:50:59 +0900139 let kernel_range = if let Some(r) = info.kernel_range {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100140 MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000141 error!("Failed to obtain the kernel range with DT range: {e}");
142 RebootReason::InternalError
143 })?
144 } else if cfg!(feature = "legacy") {
145 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
146
147 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
148 error!("Invalid kernel size: {kernel_size:#x}");
149 RebootReason::InvalidPayload
150 })?;
151
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100152 MEMORY.lock().as_mut().unwrap().alloc(kernel, kernel_size).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000153 error!("Failed to obtain the kernel range with legacy range: {e}");
154 RebootReason::InternalError
155 })?
156 } else {
157 error!("Failed to locate the kernel from the DT");
158 return Err(RebootReason::InvalidPayload);
159 };
160
Andrew Walbran20bb4e42023-07-07 13:55:55 +0100161 let kernel = kernel_range.start as *const u8;
162 // SAFETY: The tracker validated the range to be in main memory, mapped, and not overlap.
163 let kernel = unsafe { slice::from_raw_parts(kernel, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000164
Jiyong Park6a8789a2023-03-21 14:50:59 +0900165 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000166 debug!("Located ramdisk at {r:?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100167 let r = MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000168 error!("Failed to obtain the initrd range: {e}");
169 RebootReason::InvalidRamdisk
170 })?;
171
Andrew Walbran20bb4e42023-07-07 13:55:55 +0100172 // SAFETY: The region was validated by memory to be in main memory, mapped, and
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000173 // not overlap.
174 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
175 } else {
176 info!("Couldn't locate the ramdisk from the device tree");
177 None
178 };
179
180 Ok(Self { fdt, kernel, ramdisk })
181 }
182}
183
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100184/// Sets up the environment for main() and wraps its result for start().
185///
186/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
187/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100188fn main_wrapper(
189 fdt: usize,
190 payload: usize,
191 payload_size: usize,
192) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100193 // Limitations in this function:
194 // - only access MMIO once (and while) it has been mapped and configured
195 // - only perform logging once the logger has been initialized
196 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100197
Pierre-Clément Tosid3305482023-06-29 15:03:48 +0000198 log::set_max_level(LevelFilter::Info);
Alice Wangee07f722023-10-03 15:20:17 +0000199 // TODO(https://crbug.com/boringssl/35): Remove this init when BoringSSL can handle this
200 // internally.
201 // SAFETY: Configures the internal state of the library - may be called multiple times.
202 unsafe {
203 CRYPTO_library_init();
204 }
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100205
Alice Wang807fa592023-06-02 09:54:43 +0000206 let page_table = memory::init_page_table().map_err(|e| {
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000207 error!("Failed to set up the dynamic page tables: {e}");
208 RebootReason::InternalError
209 })?;
Alan Stokesc3829f12023-06-02 15:02:23 +0100210
Andrew Walbran20bb4e42023-07-07 13:55:55 +0100211 // SAFETY: We only get the appended payload from here, once. The region was statically mapped,
Alan Stokesc3829f12023-06-02 15:02:23 +0100212 // then remapped by `init_page_table()`.
213 let appended_data = unsafe { get_appended_data_slice() };
214
Alan Stokes65618332023-12-15 14:09:25 +0000215 let appended = AppendedPayload::new(appended_data).ok_or_else(|| {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100216 error!("No valid configuration found");
217 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000218 })?;
219
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000220 let config_entries = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100221
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100222 // Up to this point, we were using the built-in static (from .rodata) page tables.
Alice Wang4c70d142023-06-06 11:52:33 +0000223 MEMORY.lock().replace(MemoryTracker::new(
224 page_table,
Alice Wang63f4c9e2023-06-12 09:36:43 +0000225 crosvm::MEM_START..layout::MAX_VIRT_ADDR,
Alice Wang89d29592023-06-12 09:41:29 +0000226 crosvm::MMIO_RANGE,
Alice Wang5bb79502023-06-12 09:25:07 +0000227 Some(memory::appended_payload_range()),
Alice Wang4c70d142023-06-06 11:52:33 +0000228 ));
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100229
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000230 let slices = MemorySlices::new(fdt, payload, payload_size, config_entries.vm_dtbo)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000231
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100232 // This wrapper allows main() to be blissfully ignorant of platform details.
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000233 let next_bcc = crate::main(
234 slices.fdt,
235 slices.kernel,
236 slices.ramdisk,
237 config_entries.bcc,
238 config_entries.debug_policy,
239 )?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100240
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100241 // Writable-dirty regions will be flushed when MemoryTracker is dropped.
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000242 config_entries.bcc.zeroize();
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100243
Andrew Walbran19690632022-12-07 16:41:30 +0000244 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100245 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000246 error!("Failed to unshare MMIO ranges: {e}");
247 RebootReason::InternalError
248 })?;
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000249 // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
250 MEMORY.lock().as_mut().unwrap().unshare_all_memory();
Pierre-Clément Tosid643cfe2023-06-29 09:30:51 +0000251 if let Some(mmio_guard) = get_mmio_guard() {
252 mmio_guard.unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi5ad1e8c2023-06-29 10:36:48 +0000253 error!("Failed to unshare the UART: {e}");
254 RebootReason::InternalError
255 })?;
256 }
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100257
258 // Drop MemoryTracker and deactivate page table.
259 drop(MEMORY.lock().take());
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100260
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100261 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100262}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100263
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100264fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
265 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000266 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100267 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000268 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100269 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000270 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100271 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000272 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100273
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000274 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 +0100275
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100276 let scratch = layout::scratch_range();
277
Alice Wanga3931aa2023-07-05 12:52:09 +0000278 assert_ne!(scratch.end - scratch.start, 0, "scratch memory is empty.");
279 assert_eq!(scratch.start.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
280 assert_eq!(scratch.end.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100281
Alice Wanga3931aa2023-07-05 12:52:09 +0000282 assert!(bcc.is_within(&(scratch.start.0..scratch.end.0)));
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100283 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
284 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
285
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000286 let stack = memory::stack_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100287
Alice Wanga3931aa2023-07-05 12:52:09 +0000288 assert_ne!(stack.end - stack.start, 0, "stack region is empty.");
289 assert_eq!(stack.start.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
290 assert_eq!(stack.end.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100291
292 // 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 +0000293 // Disable the exception vector, caches and page table and then jump to the payload at the
294 // given address, passing it the given FDT pointer.
295 //
Andrew Walbran20bb4e42023-07-07 13:55:55 +0100296 // SAFETY: We're exiting pvmfw by passing the register values we need to a noreturn asm!().
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100297 unsafe {
298 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100299 "cmp {scratch}, {bcc}",
300 "b.hs 1f",
301
302 // Zero .data & .bss until BCC.
303 "0: stp xzr, xzr, [{scratch}], 16",
304 "cmp {scratch}, {bcc}",
305 "b.lo 0b",
306
307 "1:",
308 // Skip BCC.
309 "mov {scratch}, {bcc_end}",
310 "cmp {scratch}, {scratch_end}",
311 "b.hs 1f",
312
313 // Keep zeroing .data & .bss.
314 "0: stp xzr, xzr, [{scratch}], 16",
315 "cmp {scratch}, {scratch_end}",
316 "b.lo 0b",
317
318 "1:",
319 // Flush d-cache over .data & .bss (including BCC).
320 "0: dc cvau, {cache_line}",
321 "add {cache_line}, {cache_line}, {dcache_line_size}",
322 "cmp {cache_line}, {scratch_end}",
323 "b.lo 0b",
324
325 "mov {cache_line}, {stack}",
326 // Zero stack region.
327 "0: stp xzr, xzr, [{stack}], 16",
328 "cmp {stack}, {stack_end}",
329 "b.lo 0b",
330
331 // Flush d-cache over stack region.
332 "0: dc cvau, {cache_line}",
333 "add {cache_line}, {cache_line}, {dcache_line_size}",
334 "cmp {cache_line}, {stack_end}",
335 "b.lo 0b",
336
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100337 "msr sctlr_el1, {sctlr_el1_val}",
338 "isb",
339 "mov x1, xzr",
340 "mov x2, xzr",
341 "mov x3, xzr",
342 "mov x4, xzr",
343 "mov x5, xzr",
344 "mov x6, xzr",
345 "mov x7, xzr",
346 "mov x8, xzr",
347 "mov x9, xzr",
348 "mov x10, xzr",
349 "mov x11, xzr",
350 "mov x12, xzr",
351 "mov x13, xzr",
352 "mov x14, xzr",
353 "mov x15, xzr",
354 "mov x16, xzr",
355 "mov x17, xzr",
356 "mov x18, xzr",
357 "mov x19, xzr",
358 "mov x20, xzr",
359 "mov x21, xzr",
360 "mov x22, xzr",
361 "mov x23, xzr",
362 "mov x24, xzr",
363 "mov x25, xzr",
364 "mov x26, xzr",
365 "mov x27, xzr",
366 "mov x28, xzr",
367 "mov x29, xzr",
368 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100369 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100370 "dsb nsh",
371 "br x30",
372 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100373 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
374 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
Alice Wanga3931aa2023-07-05 12:52:09 +0000375 cache_line = in(reg) u64::try_from(scratch.start.0).unwrap(),
376 scratch = in(reg) u64::try_from(scratch.start.0).unwrap(),
377 scratch_end = in(reg) u64::try_from(scratch.end.0).unwrap(),
378 stack = in(reg) u64::try_from(stack.start.0).unwrap(),
379 stack_end = in(reg) u64::try_from(stack.end.0).unwrap(),
Alice Wang3fa9b802023-06-06 07:52:31 +0000380 dcache_line_size = in(reg) u64::try_from(min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100381 in("x0") fdt_address,
382 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100383 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100384 );
385 };
386}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100387
Alan Stokesc3829f12023-06-02 15:02:23 +0100388/// # Safety
389///
390/// This must only be called once, since we are returning a mutable reference.
391/// The appended data region must be mapped.
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100392unsafe fn get_appended_data_slice() -> &'static mut [u8] {
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000393 let range = memory::appended_payload_range();
Alan Stokesa0e42962023-04-14 17:59:50 +0100394 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
395 // objects.
Alice Wanga3931aa2023-07-05 12:52:09 +0000396 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 +0100397}
398
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000399enum AppendedConfigType {
400 Valid,
401 Invalid,
402 NotFound,
403}
404
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100405enum AppendedPayload<'a> {
406 /// Configuration data.
407 Config(config::Config<'a>),
408 /// Deprecated raw BCC, as used in Android T.
409 LegacyBcc(&'a mut [u8]),
410}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100411
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100412impl<'a> AppendedPayload<'a> {
Alan Stokesc3829f12023-06-02 15:02:23 +0100413 fn new(data: &'a mut [u8]) -> Option<Self> {
414 match Self::guess_config_type(data) {
Alan Stokesa0e42962023-04-14 17:59:50 +0100415 AppendedConfigType::Valid => {
Alan Stokesc3829f12023-06-02 15:02:23 +0100416 let config = config::Config::new(data);
Alan Stokesa0e42962023-04-14 17:59:50 +0100417 Some(Self::Config(config.unwrap()))
418 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000419 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
Alice Wangeacb7382023-06-05 12:53:54 +0000420 const BCC_SIZE: usize = SIZE_4KB;
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000421 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
422 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
423 }
424 _ => None,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100425 }
426 }
427
Alan Stokesc3829f12023-06-02 15:02:23 +0100428 fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100429 // This function is necessary to prevent the borrow checker from getting confused
430 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
431 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100432
Alan Stokesc3829f12023-06-02 15:02:23 +0100433 match config::Config::new(data) {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000434 Err(config::Error::InvalidMagic) => {
435 warn!("No configuration data found at {addr:?}");
436 AppendedConfigType::NotFound
437 }
438 Err(e) => {
439 error!("Invalid configuration data at {addr:?}: {e}");
440 AppendedConfigType::Invalid
441 }
442 Ok(_) => AppendedConfigType::Valid,
443 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100444 }
445
Alan Stokes65618332023-12-15 14:09:25 +0000446 fn get_entries(self) -> config::Entries<'a> {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100447 match self {
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000448 Self::Config(cfg) => cfg.get_entries(),
449 Self::LegacyBcc(bcc) => config::Entries { bcc, ..Default::default() },
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000450 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100451 }
452}