blob: 08f076b3b322b3af84c33802511aad4441a21aa4 [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;
Pierre-Clément Tosifc531152022-10-20 12:22:23 +010020use crate::heap;
Pierre-Clément Tosia1d3ea32022-11-01 15:05:11 +000021use crate::helpers;
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010022use crate::helpers::RangeExt as _;
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000023use crate::memory::{self, MemoryTracker, MEMORY};
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000024use crate::rand;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010025use core::arch::asm;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +010026use core::mem::{drop, size_of};
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000027use core::num::NonZeroUsize;
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010028use core::ops::Range;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010029use core::slice;
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -070030use hyp::{get_hypervisor, HypervisorCap};
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010031use log::debug;
32use log::error;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000033use log::info;
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010034use log::warn;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010035use log::LevelFilter;
36use vmbase::{console, layout, logger, main, power::reboot};
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010037use zeroize::Zeroize;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010038
39#[derive(Debug, Clone)]
Andrew Walbran19690632022-12-07 16:41:30 +000040pub enum RebootReason {
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010041 /// A malformed BCC was received.
42 InvalidBcc,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010043 /// An invalid configuration was appended to pvmfw.
44 InvalidConfig,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010045 /// An unexpected internal error happened.
46 InternalError,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000047 /// The provided FDT was invalid.
48 InvalidFdt,
49 /// The provided payload was invalid.
50 InvalidPayload,
51 /// The provided ramdisk was invalid.
52 InvalidRamdisk,
Alice Wang28cbcf12022-12-01 07:58:28 +000053 /// Failed to verify the payload.
54 PayloadVerificationError,
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000055 /// DICE layering process failed.
56 SecretDerivationError,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010057}
58
59main!(start);
60
61/// Entry point for pVM firmware.
62pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
63 // Limitations in this function:
64 // - can't access non-pvmfw memory (only statically-mapped memory)
65 // - can't access MMIO (therefore, no logging)
66
Pierre-Clément Tosif03089c2023-05-15 17:33:39 +000067 // SAFETY - This function should and will only be called once, here.
68 unsafe { heap::init() };
69
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010070 match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010071 Ok((entry, bcc)) => jump_to_payload(fdt_address, entry.try_into().unwrap(), bcc),
Pierre-Clément Tosid836b5b2022-12-05 10:49:38 +000072 Err(_) => reboot(), // TODO(b/220071963) propagate the reason back to the host.
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010073 }
74
75 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
76}
77
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000078struct MemorySlices<'a> {
79 fdt: &'a mut libfdt::Fdt,
80 kernel: &'a [u8],
81 ramdisk: Option<&'a [u8]>,
82}
83
84impl<'a> MemorySlices<'a> {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010085 fn new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason> {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000086 // SAFETY - SIZE_2MB is non-zero.
87 const FDT_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(helpers::SIZE_2MB) };
88 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
89 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
90 // overwrite with the template DT and apply the DTBO.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010091 let range = MEMORY.lock().as_mut().unwrap().alloc_mut(fdt, FDT_SIZE).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000092 error!("Failed to allocate the FDT range: {e}");
93 RebootReason::InternalError
94 })?;
95
96 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
97 let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
98 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
99 error!("Failed to spawn the FDT wrapper: {e}");
100 RebootReason::InvalidFdt
101 })?;
102
Jiyong Park6a8789a2023-03-21 14:50:59 +0900103 let info = fdt::sanitize_device_tree(fdt)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000104 debug!("Fdt passed validation!");
105
Jiyong Park6a8789a2023-03-21 14:50:59 +0900106 let memory_range = info.memory_range;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000107 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100108 MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
109 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000110 RebootReason::InvalidFdt
111 })?;
112
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000113 if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100114 MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool().map_err(|e| {
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000115 error!("Failed to initialize dynamically shared pool: {e}");
116 RebootReason::InternalError
117 })?;
118 } else {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700119 let range = info.swiotlb_info.fixed_range().ok_or_else(|| {
120 error!("Pre-shared pool range not specified in swiotlb node");
121 RebootReason::InvalidFdt
122 })?;
123
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100124 MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700125 error!("Failed to initialize pre-shared pool {e}");
126 RebootReason::InvalidFdt
127 })?;
128 }
129
Jiyong Park6a8789a2023-03-21 14:50:59 +0900130 let kernel_range = if let Some(r) = info.kernel_range {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100131 MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000132 error!("Failed to obtain the kernel range with DT range: {e}");
133 RebootReason::InternalError
134 })?
135 } else if cfg!(feature = "legacy") {
136 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
137
138 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
139 error!("Invalid kernel size: {kernel_size:#x}");
140 RebootReason::InvalidPayload
141 })?;
142
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100143 MEMORY.lock().as_mut().unwrap().alloc(kernel, kernel_size).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000144 error!("Failed to obtain the kernel range with legacy range: {e}");
145 RebootReason::InternalError
146 })?
147 } else {
148 error!("Failed to locate the kernel from the DT");
149 return Err(RebootReason::InvalidPayload);
150 };
151
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000152 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
153 let kernel =
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000154 unsafe { slice::from_raw_parts(kernel_range.start as *const u8, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000155
Jiyong Park6a8789a2023-03-21 14:50:59 +0900156 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000157 debug!("Located ramdisk at {r:?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100158 let r = MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000159 error!("Failed to obtain the initrd range: {e}");
160 RebootReason::InvalidRamdisk
161 })?;
162
163 // SAFETY - The region was validated by memory to be in main memory, mapped, and
164 // not overlap.
165 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
166 } else {
167 info!("Couldn't locate the ramdisk from the device tree");
168 None
169 };
170
171 Ok(Self { fdt, kernel, ramdisk })
172 }
173}
174
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100175/// Sets up the environment for main() and wraps its result for start().
176///
177/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
178/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100179fn main_wrapper(
180 fdt: usize,
181 payload: usize,
182 payload_size: usize,
183) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100184 // Limitations in this function:
185 // - only access MMIO once (and while) it has been mapped and configured
186 // - only perform logging once the logger has been initialized
187 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100188
Pierre-Clément Tosidbd72862022-10-21 14:31:02 +0100189 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100190
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100191 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
192 // builds that have tweaked the logger::init() call will actually attempt to log the message.
193
Alice Wang90e6f162023-04-17 13:49:45 +0000194 get_hypervisor().mmio_guard_init().map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100195 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100196 RebootReason::InternalError
197 })?;
198
Alice Wang90e6f162023-04-17 13:49:45 +0000199 get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100200 debug!("Failed to configure the UART: {e}");
201 RebootReason::InternalError
202 })?;
203
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100204 crypto::init();
205
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100206 // SAFETY - We only get the appended payload from here, once. It is mapped and the linker
207 // script prevents it from overlapping with other objects.
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000208 let appended_data = unsafe { get_appended_data_slice() };
209
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000210 let mut page_table = memory::init_page_table().map_err(|e| {
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000211 error!("Failed to set up the dynamic page tables: {e}");
212 RebootReason::InternalError
213 })?;
214
215 const CONSOLE_LEN: usize = 1; // vmbase::uart::Uart only uses one u8 register.
216 let uart_range = console::BASE_ADDRESS..(console::BASE_ADDRESS + CONSOLE_LEN);
217 page_table.map_device(&uart_range).map_err(|e| {
218 error!("Failed to remap the UART as a dynamic page table entry: {e}");
219 RebootReason::InternalError
220 })?;
221
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100222 // SAFETY - We only get the appended payload from here, once. It is statically mapped and the
223 // linker script prevents it from overlapping with other objects.
224 let mut appended = unsafe { AppendedPayload::new(appended_data) }.ok_or_else(|| {
225 error!("No valid configuration found");
226 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000227 })?;
228
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000229 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100230
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100231 // Up to this point, we were using the built-in static (from .rodata) page tables.
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100232 MEMORY.lock().replace(MemoryTracker::new(page_table));
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100233
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100234 let slices = MemorySlices::new(fdt, payload, payload_size)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000235
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000236 rand::init().map_err(|e| {
237 error!("Failed to initialize rand: {e}");
238 RebootReason::InternalError
239 })?;
240
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100241 // This wrapper allows main() to be blissfully ignorant of platform details.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100242 let next_bcc = crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy)?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100243
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100244 // Writable-dirty regions will be flushed when MemoryTracker is dropped.
245 bcc_slice.zeroize();
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100246
Andrew Walbran19690632022-12-07 16:41:30 +0000247 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100248 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000249 error!("Failed to unshare MMIO ranges: {e}");
250 RebootReason::InternalError
251 })?;
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000252 // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
253 MEMORY.lock().as_mut().unwrap().unshare_all_memory();
Alice Wang90e6f162023-04-17 13:49:45 +0000254 get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100255 error!("Failed to unshare the UART: {e}");
256 RebootReason::InternalError
257 })?;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100258
259 // Drop MemoryTracker and deactivate page table.
260 drop(MEMORY.lock().take());
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100261
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100262 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100263}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100264
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100265fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
266 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000267 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100268 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000269 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100270 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000271 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100272 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000273 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100274
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000275 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 +0100276
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100277 let scratch = layout::scratch_range();
278
279 assert_ne!(scratch.len(), 0, "scratch memory is empty.");
280 assert_eq!(scratch.start % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
281 assert_eq!(scratch.end % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
282
283 assert!(bcc.is_within(&scratch));
284 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
285 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
286
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000287 let stack = memory::stack_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100288
289 assert_ne!(stack.len(), 0, "stack region is empty.");
290 assert_eq!(stack.start % ASM_STP_ALIGN, 0, "Misaligned stack region.");
291 assert_eq!(stack.end % ASM_STP_ALIGN, 0, "Misaligned stack region.");
292
293 // 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 +0000294 // Disable the exception vector, caches and page table and then jump to the payload at the
295 // given address, passing it the given FDT pointer.
296 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100297 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
298 unsafe {
299 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100300 "cmp {scratch}, {bcc}",
301 "b.hs 1f",
302
303 // Zero .data & .bss until BCC.
304 "0: stp xzr, xzr, [{scratch}], 16",
305 "cmp {scratch}, {bcc}",
306 "b.lo 0b",
307
308 "1:",
309 // Skip BCC.
310 "mov {scratch}, {bcc_end}",
311 "cmp {scratch}, {scratch_end}",
312 "b.hs 1f",
313
314 // Keep zeroing .data & .bss.
315 "0: stp xzr, xzr, [{scratch}], 16",
316 "cmp {scratch}, {scratch_end}",
317 "b.lo 0b",
318
319 "1:",
320 // Flush d-cache over .data & .bss (including BCC).
321 "0: dc cvau, {cache_line}",
322 "add {cache_line}, {cache_line}, {dcache_line_size}",
323 "cmp {cache_line}, {scratch_end}",
324 "b.lo 0b",
325
326 "mov {cache_line}, {stack}",
327 // Zero stack region.
328 "0: stp xzr, xzr, [{stack}], 16",
329 "cmp {stack}, {stack_end}",
330 "b.lo 0b",
331
332 // Flush d-cache over stack region.
333 "0: dc cvau, {cache_line}",
334 "add {cache_line}, {cache_line}, {dcache_line_size}",
335 "cmp {cache_line}, {stack_end}",
336 "b.lo 0b",
337
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100338 "msr sctlr_el1, {sctlr_el1_val}",
339 "isb",
340 "mov x1, xzr",
341 "mov x2, xzr",
342 "mov x3, xzr",
343 "mov x4, xzr",
344 "mov x5, xzr",
345 "mov x6, xzr",
346 "mov x7, xzr",
347 "mov x8, xzr",
348 "mov x9, xzr",
349 "mov x10, xzr",
350 "mov x11, xzr",
351 "mov x12, xzr",
352 "mov x13, xzr",
353 "mov x14, xzr",
354 "mov x15, xzr",
355 "mov x16, xzr",
356 "mov x17, xzr",
357 "mov x18, xzr",
358 "mov x19, xzr",
359 "mov x20, xzr",
360 "mov x21, xzr",
361 "mov x22, xzr",
362 "mov x23, xzr",
363 "mov x24, xzr",
364 "mov x25, xzr",
365 "mov x26, xzr",
366 "mov x27, xzr",
367 "mov x28, xzr",
368 "mov x29, xzr",
369 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100370 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100371 "dsb nsh",
372 "br x30",
373 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100374 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
375 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
376 cache_line = in(reg) u64::try_from(scratch.start).unwrap(),
377 scratch = in(reg) u64::try_from(scratch.start).unwrap(),
378 scratch_end = in(reg) u64::try_from(scratch.end).unwrap(),
379 stack = in(reg) u64::try_from(stack.start).unwrap(),
380 stack_end = in(reg) u64::try_from(stack.end).unwrap(),
381 dcache_line_size = in(reg) u64::try_from(helpers::min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100382 in("x0") fdt_address,
383 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100384 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100385 );
386 };
387}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100388
389unsafe fn get_appended_data_slice() -> &'static mut [u8] {
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000390 let range = memory::appended_payload_range();
Alan Stokesa0e42962023-04-14 17:59:50 +0100391 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
392 // objects.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100393 unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100394}
395
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000396enum AppendedConfigType {
397 Valid,
398 Invalid,
399 NotFound,
400}
401
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100402enum AppendedPayload<'a> {
403 /// Configuration data.
404 Config(config::Config<'a>),
405 /// Deprecated raw BCC, as used in Android T.
406 LegacyBcc(&'a mut [u8]),
407}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100408
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100409impl<'a> AppendedPayload<'a> {
410 /// SAFETY - 'data' should respect the alignment of config::Header.
411 unsafe fn new(data: &'a mut [u8]) -> Option<Self> {
Alan Stokesa0e42962023-04-14 17:59:50 +0100412 // Safety: This fn has the same constraint as us.
413 match unsafe { Self::guess_config_type(data) } {
414 AppendedConfigType::Valid => {
415 // Safety: This fn has the same constraint as us.
416 let config = unsafe { config::Config::new(data) };
417 Some(Self::Config(config.unwrap()))
418 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000419 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
420 const BCC_SIZE: usize = helpers::SIZE_4KB;
421 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 Stokesa0e42962023-04-14 17:59:50 +0100428 /// SAFETY - 'data' should respect the alignment of config::Header.
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000429 unsafe fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100430 // This function is necessary to prevent the borrow checker from getting confused
431 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
432 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100433
434 // Safety: This fn has the same constraint as us.
435 match unsafe { config::Config::new(data) } {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000436 Err(config::Error::InvalidMagic) => {
437 warn!("No configuration data found at {addr:?}");
438 AppendedConfigType::NotFound
439 }
440 Err(e) => {
441 error!("Invalid configuration data at {addr:?}: {e}");
442 AppendedConfigType::Invalid
443 }
444 Ok(_) => AppendedConfigType::Valid,
445 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100446 }
447
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000448 fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100449 match self {
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000450 Self::Config(ref mut cfg) => cfg.get_entries(),
451 Self::LegacyBcc(ref mut bcc) => (bcc, None),
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000452 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100453 }
454}