blob: 3d2fea8ee54f84243f3c58a94d90dcf15be888d6 [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;
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -070026use hyp::{get_hypervisor, HypervisorCap};
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},
36 logger, 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 Tosif19c0e62023-05-02 13:56:58 +0000115 if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
Alice Wangb6d2c642023-06-13 13:07:06 +0000116 let granule = get_hypervisor().memory_protection_granule().map_err(|e| {
117 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 Tosidbd72862022-10-21 14:31:02 +0100195 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100196
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100197 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
198 // builds that have tweaked the logger::init() call will actually attempt to log the message.
199
Alice Wang90e6f162023-04-17 13:49:45 +0000200 get_hypervisor().mmio_guard_init().map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100201 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100202 RebootReason::InternalError
203 })?;
204
Alice Wang90e6f162023-04-17 13:49:45 +0000205 get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100206 debug!("Failed to configure the UART: {e}");
207 RebootReason::InternalError
208 })?;
209
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100210 crypto::init();
211
Alice Wang807fa592023-06-02 09:54:43 +0000212 let page_table = memory::init_page_table().map_err(|e| {
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000213 error!("Failed to set up the dynamic page tables: {e}");
214 RebootReason::InternalError
215 })?;
Alan Stokesc3829f12023-06-02 15:02:23 +0100216
217 // SAFETY - We only get the appended payload from here, once. The region was statically mapped,
218 // then remapped by `init_page_table()`.
219 let appended_data = unsafe { get_appended_data_slice() };
220
221 let mut appended = AppendedPayload::new(appended_data).ok_or_else(|| {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100222 error!("No valid configuration found");
223 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000224 })?;
225
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000226 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100227
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100228 // Up to this point, we were using the built-in static (from .rodata) page tables.
Alice Wang4c70d142023-06-06 11:52:33 +0000229 MEMORY.lock().replace(MemoryTracker::new(
230 page_table,
Alice Wang63f4c9e2023-06-12 09:36:43 +0000231 crosvm::MEM_START..layout::MAX_VIRT_ADDR,
Alice Wang89d29592023-06-12 09:41:29 +0000232 crosvm::MMIO_RANGE,
Alice Wang5bb79502023-06-12 09:25:07 +0000233 Some(memory::appended_payload_range()),
Alice Wang4c70d142023-06-06 11:52:33 +0000234 ));
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100235
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100236 let slices = MemorySlices::new(fdt, payload, payload_size)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000237
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000238 rand::init().map_err(|e| {
239 error!("Failed to initialize rand: {e}");
240 RebootReason::InternalError
241 })?;
242
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100243 // This wrapper allows main() to be blissfully ignorant of platform details.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100244 let next_bcc = crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy)?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100245
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100246 // Writable-dirty regions will be flushed when MemoryTracker is dropped.
247 bcc_slice.zeroize();
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100248
Andrew Walbran19690632022-12-07 16:41:30 +0000249 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100250 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000251 error!("Failed to unshare MMIO ranges: {e}");
252 RebootReason::InternalError
253 })?;
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000254 // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
255 MEMORY.lock().as_mut().unwrap().unshare_all_memory();
Alice Wang90e6f162023-04-17 13:49:45 +0000256 get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100257 error!("Failed to unshare the UART: {e}");
258 RebootReason::InternalError
259 })?;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100260
261 // Drop MemoryTracker and deactivate page table.
262 drop(MEMORY.lock().take());
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100263
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100264 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100265}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100266
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100267fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
268 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000269 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100270 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000271 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100272 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000273 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100274 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000275 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100276
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000277 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 +0100278
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100279 let scratch = layout::scratch_range();
280
Alice Wanga3931aa2023-07-05 12:52:09 +0000281 assert_ne!(scratch.end - scratch.start, 0, "scratch memory is empty.");
282 assert_eq!(scratch.start.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
283 assert_eq!(scratch.end.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100284
Alice Wanga3931aa2023-07-05 12:52:09 +0000285 assert!(bcc.is_within(&(scratch.start.0..scratch.end.0)));
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100286 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
287 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
288
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000289 let stack = memory::stack_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100290
Alice Wanga3931aa2023-07-05 12:52:09 +0000291 assert_ne!(stack.end - stack.start, 0, "stack region is empty.");
292 assert_eq!(stack.start.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
293 assert_eq!(stack.end.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100294
295 // 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 +0000296 // Disable the exception vector, caches and page table and then jump to the payload at the
297 // given address, passing it the given FDT pointer.
298 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100299 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
300 unsafe {
301 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100302 "cmp {scratch}, {bcc}",
303 "b.hs 1f",
304
305 // Zero .data & .bss until BCC.
306 "0: stp xzr, xzr, [{scratch}], 16",
307 "cmp {scratch}, {bcc}",
308 "b.lo 0b",
309
310 "1:",
311 // Skip BCC.
312 "mov {scratch}, {bcc_end}",
313 "cmp {scratch}, {scratch_end}",
314 "b.hs 1f",
315
316 // Keep zeroing .data & .bss.
317 "0: stp xzr, xzr, [{scratch}], 16",
318 "cmp {scratch}, {scratch_end}",
319 "b.lo 0b",
320
321 "1:",
322 // Flush d-cache over .data & .bss (including BCC).
323 "0: dc cvau, {cache_line}",
324 "add {cache_line}, {cache_line}, {dcache_line_size}",
325 "cmp {cache_line}, {scratch_end}",
326 "b.lo 0b",
327
328 "mov {cache_line}, {stack}",
329 // Zero stack region.
330 "0: stp xzr, xzr, [{stack}], 16",
331 "cmp {stack}, {stack_end}",
332 "b.lo 0b",
333
334 // Flush d-cache over stack region.
335 "0: dc cvau, {cache_line}",
336 "add {cache_line}, {cache_line}, {dcache_line_size}",
337 "cmp {cache_line}, {stack_end}",
338 "b.lo 0b",
339
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100340 "msr sctlr_el1, {sctlr_el1_val}",
341 "isb",
342 "mov x1, xzr",
343 "mov x2, xzr",
344 "mov x3, xzr",
345 "mov x4, xzr",
346 "mov x5, xzr",
347 "mov x6, xzr",
348 "mov x7, xzr",
349 "mov x8, xzr",
350 "mov x9, xzr",
351 "mov x10, xzr",
352 "mov x11, xzr",
353 "mov x12, xzr",
354 "mov x13, xzr",
355 "mov x14, xzr",
356 "mov x15, xzr",
357 "mov x16, xzr",
358 "mov x17, xzr",
359 "mov x18, xzr",
360 "mov x19, xzr",
361 "mov x20, xzr",
362 "mov x21, xzr",
363 "mov x22, xzr",
364 "mov x23, xzr",
365 "mov x24, xzr",
366 "mov x25, xzr",
367 "mov x26, xzr",
368 "mov x27, xzr",
369 "mov x28, xzr",
370 "mov x29, xzr",
371 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100372 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100373 "dsb nsh",
374 "br x30",
375 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100376 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
377 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
Alice Wanga3931aa2023-07-05 12:52:09 +0000378 cache_line = in(reg) u64::try_from(scratch.start.0).unwrap(),
379 scratch = in(reg) u64::try_from(scratch.start.0).unwrap(),
380 scratch_end = in(reg) u64::try_from(scratch.end.0).unwrap(),
381 stack = in(reg) u64::try_from(stack.start.0).unwrap(),
382 stack_end = in(reg) u64::try_from(stack.end.0).unwrap(),
Alice Wang3fa9b802023-06-06 07:52:31 +0000383 dcache_line_size = in(reg) u64::try_from(min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100384 in("x0") fdt_address,
385 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100386 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100387 );
388 };
389}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100390
Alan Stokesc3829f12023-06-02 15:02:23 +0100391/// # Safety
392///
393/// This must only be called once, since we are returning a mutable reference.
394/// The appended data region must be mapped.
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100395unsafe fn get_appended_data_slice() -> &'static mut [u8] {
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000396 let range = memory::appended_payload_range();
Alan Stokesa0e42962023-04-14 17:59:50 +0100397 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
398 // objects.
Alice Wanga3931aa2023-07-05 12:52:09 +0000399 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 +0100400}
401
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000402enum AppendedConfigType {
403 Valid,
404 Invalid,
405 NotFound,
406}
407
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100408enum AppendedPayload<'a> {
409 /// Configuration data.
410 Config(config::Config<'a>),
411 /// Deprecated raw BCC, as used in Android T.
412 LegacyBcc(&'a mut [u8]),
413}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100414
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100415impl<'a> AppendedPayload<'a> {
Alan Stokesc3829f12023-06-02 15:02:23 +0100416 fn new(data: &'a mut [u8]) -> Option<Self> {
417 match Self::guess_config_type(data) {
Alan Stokesa0e42962023-04-14 17:59:50 +0100418 AppendedConfigType::Valid => {
Alan Stokesc3829f12023-06-02 15:02:23 +0100419 let config = config::Config::new(data);
Alan Stokesa0e42962023-04-14 17:59:50 +0100420 Some(Self::Config(config.unwrap()))
421 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000422 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
Alice Wangeacb7382023-06-05 12:53:54 +0000423 const BCC_SIZE: usize = SIZE_4KB;
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000424 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
425 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
426 }
427 _ => None,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100428 }
429 }
430
Alan Stokesc3829f12023-06-02 15:02:23 +0100431 fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100432 // This function is necessary to prevent the borrow checker from getting confused
433 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
434 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100435
Alan Stokesc3829f12023-06-02 15:02:23 +0100436 match config::Config::new(data) {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000437 Err(config::Error::InvalidMagic) => {
438 warn!("No configuration data found at {addr:?}");
439 AppendedConfigType::NotFound
440 }
441 Err(e) => {
442 error!("Invalid configuration data at {addr:?}: {e}");
443 AppendedConfigType::Invalid
444 }
445 Ok(_) => AppendedConfigType::Valid,
446 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100447 }
448
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000449 fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100450 match self {
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000451 Self::Config(ref mut cfg) => cfg.get_entries(),
452 Self::LegacyBcc(ref mut bcc) => (bcc, None),
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000453 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100454 }
455}