blob: 2582d551a44a18cc597ec4a3dc8c22aa75933b6c [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 Tosif3681e82023-06-22 11:38:22 +000018use crate::configure_global_allocator_size;
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +010019use crate::crypto;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000020use crate::fdt;
Pierre-Clément Tosifc531152022-10-20 12:22:23 +010021use crate::heap;
Alice Wang93ee98a2023-06-08 08:20:39 +000022use crate::memory;
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000023use crate::rand;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010024use core::arch::asm;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +010025use core::mem::{drop, size_of};
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000026use core::num::NonZeroUsize;
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010027use core::ops::Range;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010028use core::slice;
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -070029use hyp::{get_hypervisor, HypervisorCap};
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010030use log::debug;
31use log::error;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000032use log::info;
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010033use log::warn;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010034use log::LevelFilter;
Alice Wang4be4dd02023-06-07 07:50:40 +000035use vmbase::util::RangeExt as _;
Alice Wangeacb7382023-06-05 12:53:54 +000036use vmbase::{
Alice Wang4c70d142023-06-06 11:52:33 +000037 console,
38 layout::{self, crosvm},
39 logger, main,
Pierre-Clément Tosif3681e82023-06-22 11:38:22 +000040 memory::{min_dcache_line_size, MemoryTracker, MEMORY, SIZE_128KB, SIZE_4KB},
Alice Wangeacb7382023-06-05 12:53:54 +000041 power::reboot,
42};
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010043use zeroize::Zeroize;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010044
45#[derive(Debug, Clone)]
Andrew Walbran19690632022-12-07 16:41:30 +000046pub enum RebootReason {
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010047 /// A malformed BCC was received.
48 InvalidBcc,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010049 /// An invalid configuration was appended to pvmfw.
50 InvalidConfig,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010051 /// An unexpected internal error happened.
52 InternalError,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000053 /// The provided FDT was invalid.
54 InvalidFdt,
55 /// The provided payload was invalid.
56 InvalidPayload,
57 /// The provided ramdisk was invalid.
58 InvalidRamdisk,
Alice Wang28cbcf12022-12-01 07:58:28 +000059 /// Failed to verify the payload.
60 PayloadVerificationError,
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000061 /// DICE layering process failed.
62 SecretDerivationError,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010063}
64
65main!(start);
Pierre-Clément Tosif3681e82023-06-22 11:38:22 +000066configure_global_allocator_size!(SIZE_128KB);
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010067
68/// Entry point for pVM firmware.
69pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
70 // Limitations in this function:
71 // - can't access non-pvmfw memory (only statically-mapped memory)
72 // - can't access MMIO (therefore, no logging)
73
Pierre-Clément Tosif03089c2023-05-15 17:33:39 +000074 // SAFETY - This function should and will only be called once, here.
75 unsafe { heap::init() };
76
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010077 match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010078 Ok((entry, bcc)) => jump_to_payload(fdt_address, entry.try_into().unwrap(), bcc),
Pierre-Clément Tosid836b5b2022-12-05 10:49:38 +000079 Err(_) => reboot(), // TODO(b/220071963) propagate the reason back to the host.
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010080 }
81
82 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
83}
84
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000085struct MemorySlices<'a> {
86 fdt: &'a mut libfdt::Fdt,
87 kernel: &'a [u8],
88 ramdisk: Option<&'a [u8]>,
89}
90
91impl<'a> MemorySlices<'a> {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010092 fn new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason> {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000093 // SAFETY - SIZE_2MB is non-zero.
Alice Wange9ae5c42023-06-12 11:14:13 +000094 const FDT_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(crosvm::FDT_MAX_SIZE) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000095 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
96 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
97 // overwrite with the template DT and apply the DTBO.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010098 let range = MEMORY.lock().as_mut().unwrap().alloc_mut(fdt, FDT_SIZE).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000099 error!("Failed to allocate the FDT range: {e}");
100 RebootReason::InternalError
101 })?;
102
103 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
104 let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
105 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
106 error!("Failed to spawn the FDT wrapper: {e}");
107 RebootReason::InvalidFdt
108 })?;
109
Jiyong Park6a8789a2023-03-21 14:50:59 +0900110 let info = fdt::sanitize_device_tree(fdt)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000111 debug!("Fdt passed validation!");
112
Jiyong Park6a8789a2023-03-21 14:50:59 +0900113 let memory_range = info.memory_range;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000114 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100115 MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
116 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000117 RebootReason::InvalidFdt
118 })?;
119
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000120 if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
Alice Wangb6d2c642023-06-13 13:07:06 +0000121 let granule = get_hypervisor().memory_protection_granule().map_err(|e| {
122 error!("Failed to get memory protection granule: {e}");
123 RebootReason::InternalError
124 })?;
125 MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).map_err(|e| {
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000126 error!("Failed to initialize dynamically shared pool: {e}");
127 RebootReason::InternalError
128 })?;
129 } else {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700130 let range = info.swiotlb_info.fixed_range().ok_or_else(|| {
131 error!("Pre-shared pool range not specified in swiotlb node");
132 RebootReason::InvalidFdt
133 })?;
134
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100135 MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700136 error!("Failed to initialize pre-shared pool {e}");
137 RebootReason::InvalidFdt
138 })?;
139 }
140
Jiyong Park6a8789a2023-03-21 14:50:59 +0900141 let kernel_range = if let Some(r) = info.kernel_range {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100142 MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000143 error!("Failed to obtain the kernel range with DT range: {e}");
144 RebootReason::InternalError
145 })?
146 } else if cfg!(feature = "legacy") {
147 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
148
149 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
150 error!("Invalid kernel size: {kernel_size:#x}");
151 RebootReason::InvalidPayload
152 })?;
153
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100154 MEMORY.lock().as_mut().unwrap().alloc(kernel, kernel_size).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000155 error!("Failed to obtain the kernel range with legacy range: {e}");
156 RebootReason::InternalError
157 })?
158 } else {
159 error!("Failed to locate the kernel from the DT");
160 return Err(RebootReason::InvalidPayload);
161 };
162
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000163 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
164 let kernel =
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000165 unsafe { slice::from_raw_parts(kernel_range.start as *const u8, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000166
Jiyong Park6a8789a2023-03-21 14:50:59 +0900167 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000168 debug!("Located ramdisk at {r:?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100169 let r = MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000170 error!("Failed to obtain the initrd range: {e}");
171 RebootReason::InvalidRamdisk
172 })?;
173
174 // SAFETY - The region was validated by memory to be in main memory, mapped, and
175 // not overlap.
176 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
177 } else {
178 info!("Couldn't locate the ramdisk from the device tree");
179 None
180 };
181
182 Ok(Self { fdt, kernel, ramdisk })
183 }
184}
185
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100186/// Sets up the environment for main() and wraps its result for start().
187///
188/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
189/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100190fn main_wrapper(
191 fdt: usize,
192 payload: usize,
193 payload_size: usize,
194) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100195 // Limitations in this function:
196 // - only access MMIO once (and while) it has been mapped and configured
197 // - only perform logging once the logger has been initialized
198 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100199
Pierre-Clément Tosidbd72862022-10-21 14:31:02 +0100200 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100201
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100202 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
203 // builds that have tweaked the logger::init() call will actually attempt to log the message.
204
Alice Wang90e6f162023-04-17 13:49:45 +0000205 get_hypervisor().mmio_guard_init().map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100206 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100207 RebootReason::InternalError
208 })?;
209
Alice Wang90e6f162023-04-17 13:49:45 +0000210 get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100211 debug!("Failed to configure the UART: {e}");
212 RebootReason::InternalError
213 })?;
214
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100215 crypto::init();
216
Alice Wang807fa592023-06-02 09:54:43 +0000217 let page_table = memory::init_page_table().map_err(|e| {
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000218 error!("Failed to set up the dynamic page tables: {e}");
219 RebootReason::InternalError
220 })?;
Alan Stokesc3829f12023-06-02 15:02:23 +0100221
222 // SAFETY - We only get the appended payload from here, once. The region was statically mapped,
223 // then remapped by `init_page_table()`.
224 let appended_data = unsafe { get_appended_data_slice() };
225
226 let mut appended = AppendedPayload::new(appended_data).ok_or_else(|| {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100227 error!("No valid configuration found");
228 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000229 })?;
230
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000231 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100232
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100233 // Up to this point, we were using the built-in static (from .rodata) page tables.
Alice Wang4c70d142023-06-06 11:52:33 +0000234 MEMORY.lock().replace(MemoryTracker::new(
235 page_table,
Alice Wang63f4c9e2023-06-12 09:36:43 +0000236 crosvm::MEM_START..layout::MAX_VIRT_ADDR,
Alice Wang89d29592023-06-12 09:41:29 +0000237 crosvm::MMIO_RANGE,
Alice Wang5bb79502023-06-12 09:25:07 +0000238 Some(memory::appended_payload_range()),
Alice Wang4c70d142023-06-06 11:52:33 +0000239 ));
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100240
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100241 let slices = MemorySlices::new(fdt, payload, payload_size)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000242
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000243 rand::init().map_err(|e| {
244 error!("Failed to initialize rand: {e}");
245 RebootReason::InternalError
246 })?;
247
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100248 // This wrapper allows main() to be blissfully ignorant of platform details.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100249 let next_bcc = crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy)?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100250
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100251 // Writable-dirty regions will be flushed when MemoryTracker is dropped.
252 bcc_slice.zeroize();
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100253
Andrew Walbran19690632022-12-07 16:41:30 +0000254 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100255 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000256 error!("Failed to unshare MMIO ranges: {e}");
257 RebootReason::InternalError
258 })?;
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000259 // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
260 MEMORY.lock().as_mut().unwrap().unshare_all_memory();
Alice Wang90e6f162023-04-17 13:49:45 +0000261 get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100262 error!("Failed to unshare the UART: {e}");
263 RebootReason::InternalError
264 })?;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100265
266 // Drop MemoryTracker and deactivate page table.
267 drop(MEMORY.lock().take());
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100268
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100269 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100270}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100271
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100272fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
273 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000274 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100275 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000276 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100277 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000278 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100279 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000280 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100281
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000282 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 +0100283
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100284 let scratch = layout::scratch_range();
285
286 assert_ne!(scratch.len(), 0, "scratch memory is empty.");
287 assert_eq!(scratch.start % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
288 assert_eq!(scratch.end % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
289
290 assert!(bcc.is_within(&scratch));
291 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
292 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
293
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000294 let stack = memory::stack_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100295
296 assert_ne!(stack.len(), 0, "stack region is empty.");
297 assert_eq!(stack.start % ASM_STP_ALIGN, 0, "Misaligned stack region.");
298 assert_eq!(stack.end % ASM_STP_ALIGN, 0, "Misaligned stack region.");
299
300 // 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 +0000301 // Disable the exception vector, caches and page table and then jump to the payload at the
302 // given address, passing it the given FDT pointer.
303 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100304 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
305 unsafe {
306 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100307 "cmp {scratch}, {bcc}",
308 "b.hs 1f",
309
310 // Zero .data & .bss until BCC.
311 "0: stp xzr, xzr, [{scratch}], 16",
312 "cmp {scratch}, {bcc}",
313 "b.lo 0b",
314
315 "1:",
316 // Skip BCC.
317 "mov {scratch}, {bcc_end}",
318 "cmp {scratch}, {scratch_end}",
319 "b.hs 1f",
320
321 // Keep zeroing .data & .bss.
322 "0: stp xzr, xzr, [{scratch}], 16",
323 "cmp {scratch}, {scratch_end}",
324 "b.lo 0b",
325
326 "1:",
327 // Flush d-cache over .data & .bss (including BCC).
328 "0: dc cvau, {cache_line}",
329 "add {cache_line}, {cache_line}, {dcache_line_size}",
330 "cmp {cache_line}, {scratch_end}",
331 "b.lo 0b",
332
333 "mov {cache_line}, {stack}",
334 // Zero stack region.
335 "0: stp xzr, xzr, [{stack}], 16",
336 "cmp {stack}, {stack_end}",
337 "b.lo 0b",
338
339 // Flush d-cache over stack region.
340 "0: dc cvau, {cache_line}",
341 "add {cache_line}, {cache_line}, {dcache_line_size}",
342 "cmp {cache_line}, {stack_end}",
343 "b.lo 0b",
344
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100345 "msr sctlr_el1, {sctlr_el1_val}",
346 "isb",
347 "mov x1, xzr",
348 "mov x2, xzr",
349 "mov x3, xzr",
350 "mov x4, xzr",
351 "mov x5, xzr",
352 "mov x6, xzr",
353 "mov x7, xzr",
354 "mov x8, xzr",
355 "mov x9, xzr",
356 "mov x10, xzr",
357 "mov x11, xzr",
358 "mov x12, xzr",
359 "mov x13, xzr",
360 "mov x14, xzr",
361 "mov x15, xzr",
362 "mov x16, xzr",
363 "mov x17, xzr",
364 "mov x18, xzr",
365 "mov x19, xzr",
366 "mov x20, xzr",
367 "mov x21, xzr",
368 "mov x22, xzr",
369 "mov x23, xzr",
370 "mov x24, xzr",
371 "mov x25, xzr",
372 "mov x26, xzr",
373 "mov x27, xzr",
374 "mov x28, xzr",
375 "mov x29, xzr",
376 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100377 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100378 "dsb nsh",
379 "br x30",
380 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100381 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
382 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
383 cache_line = in(reg) u64::try_from(scratch.start).unwrap(),
384 scratch = in(reg) u64::try_from(scratch.start).unwrap(),
385 scratch_end = in(reg) u64::try_from(scratch.end).unwrap(),
386 stack = in(reg) u64::try_from(stack.start).unwrap(),
387 stack_end = in(reg) u64::try_from(stack.end).unwrap(),
Alice Wang3fa9b802023-06-06 07:52:31 +0000388 dcache_line_size = in(reg) u64::try_from(min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100389 in("x0") fdt_address,
390 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100391 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100392 );
393 };
394}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100395
Alan Stokesc3829f12023-06-02 15:02:23 +0100396/// # Safety
397///
398/// This must only be called once, since we are returning a mutable reference.
399/// The appended data region must be mapped.
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100400unsafe fn get_appended_data_slice() -> &'static mut [u8] {
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000401 let range = memory::appended_payload_range();
Alan Stokesa0e42962023-04-14 17:59:50 +0100402 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
403 // objects.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100404 unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100405}
406
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000407enum AppendedConfigType {
408 Valid,
409 Invalid,
410 NotFound,
411}
412
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100413enum AppendedPayload<'a> {
414 /// Configuration data.
415 Config(config::Config<'a>),
416 /// Deprecated raw BCC, as used in Android T.
417 LegacyBcc(&'a mut [u8]),
418}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100419
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100420impl<'a> AppendedPayload<'a> {
Alan Stokesc3829f12023-06-02 15:02:23 +0100421 fn new(data: &'a mut [u8]) -> Option<Self> {
422 match Self::guess_config_type(data) {
Alan Stokesa0e42962023-04-14 17:59:50 +0100423 AppendedConfigType::Valid => {
Alan Stokesc3829f12023-06-02 15:02:23 +0100424 let config = config::Config::new(data);
Alan Stokesa0e42962023-04-14 17:59:50 +0100425 Some(Self::Config(config.unwrap()))
426 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000427 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
Alice Wangeacb7382023-06-05 12:53:54 +0000428 const BCC_SIZE: usize = SIZE_4KB;
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000429 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
430 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
431 }
432 _ => None,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100433 }
434 }
435
Alan Stokesc3829f12023-06-02 15:02:23 +0100436 fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100437 // This function is necessary to prevent the borrow checker from getting confused
438 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
439 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100440
Alan Stokesc3829f12023-06-02 15:02:23 +0100441 match config::Config::new(data) {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000442 Err(config::Error::InvalidMagic) => {
443 warn!("No configuration data found at {addr:?}");
444 AppendedConfigType::NotFound
445 }
446 Err(e) => {
447 error!("Invalid configuration data at {addr:?}: {e}");
448 AppendedConfigType::Invalid
449 }
450 Ok(_) => AppendedConfigType::Valid,
451 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100452 }
453
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000454 fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100455 match self {
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000456 Self::Config(ref mut cfg) => cfg.get_entries(),
457 Self::LegacyBcc(ref mut bcc) => (bcc, None),
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000458 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100459 }
460}