blob: ca7474097d93267bcc3e5ba8720e8fb7a0c65653 [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 _;
Jakob Vukalovic85a00d72023-04-20 09:51:10 +010023use crate::memory::{MemoryTracker, MEMORY};
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +000024use crate::mmu;
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000025use crate::rand;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010026use core::arch::asm;
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010027use core::mem::size_of;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000028use core::num::NonZeroUsize;
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010029use core::ops::Range;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010030use core::slice;
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -070031use hyp::{get_hypervisor, HypervisorCap};
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010032use log::debug;
33use log::error;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000034use log::info;
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010035use log::warn;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010036use log::LevelFilter;
37use vmbase::{console, layout, logger, main, power::reboot};
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010038use zeroize::Zeroize;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010039
40#[derive(Debug, Clone)]
Andrew Walbran19690632022-12-07 16:41:30 +000041pub enum RebootReason {
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010042 /// A malformed BCC was received.
43 InvalidBcc,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010044 /// An invalid configuration was appended to pvmfw.
45 InvalidConfig,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010046 /// An unexpected internal error happened.
47 InternalError,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000048 /// The provided FDT was invalid.
49 InvalidFdt,
50 /// The provided payload was invalid.
51 InvalidPayload,
52 /// The provided ramdisk was invalid.
53 InvalidRamdisk,
Alice Wang28cbcf12022-12-01 07:58:28 +000054 /// Failed to verify the payload.
55 PayloadVerificationError,
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000056 /// DICE layering process failed.
57 SecretDerivationError,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010058}
59
60main!(start);
61
62/// Entry point for pVM firmware.
63pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
64 // Limitations in this function:
65 // - can't access non-pvmfw memory (only statically-mapped memory)
66 // - can't access MMIO (therefore, no logging)
67
Pierre-Clément Tosif03089c2023-05-15 17:33:39 +000068 // SAFETY - This function should and will only be called once, here.
69 unsafe { heap::init() };
70
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010071 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> {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010086 fn new(fdt: usize, kernel: usize, kernel_size: usize) -> Result<Self, RebootReason> {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000087 // SAFETY - SIZE_2MB is non-zero.
88 const FDT_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(helpers::SIZE_2MB) };
89 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
90 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
91 // overwrite with the template DT and apply the DTBO.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010092 let range = MEMORY.lock().as_mut().unwrap().alloc_mut(fdt, FDT_SIZE).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000093 error!("Failed to allocate the FDT range: {e}");
94 RebootReason::InternalError
95 })?;
96
97 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
98 let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
99 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
100 error!("Failed to spawn the FDT wrapper: {e}");
101 RebootReason::InvalidFdt
102 })?;
103
Jiyong Park6a8789a2023-03-21 14:50:59 +0900104 let info = fdt::sanitize_device_tree(fdt)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000105 debug!("Fdt passed validation!");
106
Jiyong Park6a8789a2023-03-21 14:50:59 +0900107 let memory_range = info.memory_range;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000108 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100109 MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
110 error!("Failed to use memory range value from DT: {memory_range:#x?}: {e}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000111 RebootReason::InvalidFdt
112 })?;
113
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000114 if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100115 MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool().map_err(|e| {
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000116 error!("Failed to initialize dynamically shared pool: {e}");
117 RebootReason::InternalError
118 })?;
119 } else {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700120 let range = info.swiotlb_info.fixed_range().ok_or_else(|| {
121 error!("Pre-shared pool range not specified in swiotlb node");
122 RebootReason::InvalidFdt
123 })?;
124
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100125 MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700126 error!("Failed to initialize pre-shared pool {e}");
127 RebootReason::InvalidFdt
128 })?;
129 }
130
Jiyong Park6a8789a2023-03-21 14:50:59 +0900131 let kernel_range = if let Some(r) = info.kernel_range {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100132 MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000133 error!("Failed to obtain the kernel range with DT range: {e}");
134 RebootReason::InternalError
135 })?
136 } else if cfg!(feature = "legacy") {
137 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
138
139 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
140 error!("Invalid kernel size: {kernel_size:#x}");
141 RebootReason::InvalidPayload
142 })?;
143
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100144 MEMORY.lock().as_mut().unwrap().alloc(kernel, kernel_size).map_err(|e| {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000145 error!("Failed to obtain the kernel range with legacy range: {e}");
146 RebootReason::InternalError
147 })?
148 } else {
149 error!("Failed to locate the kernel from the DT");
150 return Err(RebootReason::InvalidPayload);
151 };
152
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000153 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
154 let kernel =
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000155 unsafe { slice::from_raw_parts(kernel_range.start as *const u8, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000156
Jiyong Park6a8789a2023-03-21 14:50:59 +0900157 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000158 debug!("Located ramdisk at {r:?}");
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100159 let r = MEMORY.lock().as_mut().unwrap().alloc_range(&r).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000160 error!("Failed to obtain the initrd range: {e}");
161 RebootReason::InvalidRamdisk
162 })?;
163
164 // SAFETY - The region was validated by memory to be in main memory, mapped, and
165 // not overlap.
166 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
167 } else {
168 info!("Couldn't locate the ramdisk from the device tree");
169 None
170 };
171
172 Ok(Self { fdt, kernel, ramdisk })
173 }
174}
175
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100176/// Sets up the environment for main() and wraps its result for start().
177///
178/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
179/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100180fn main_wrapper(
181 fdt: usize,
182 payload: usize,
183 payload_size: usize,
184) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100185 // Limitations in this function:
186 // - only access MMIO once (and while) it has been mapped and configured
187 // - only perform logging once the logger has been initialized
188 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100189
Pierre-Clément Tosidbd72862022-10-21 14:31:02 +0100190 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100191
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100192 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
193 // builds that have tweaked the logger::init() call will actually attempt to log the message.
194
Alice Wang90e6f162023-04-17 13:49:45 +0000195 get_hypervisor().mmio_guard_init().map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100196 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100197 RebootReason::InternalError
198 })?;
199
Alice Wang90e6f162023-04-17 13:49:45 +0000200 get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100201 debug!("Failed to configure the UART: {e}");
202 RebootReason::InternalError
203 })?;
204
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100205 crypto::init();
206
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100207 // SAFETY - We only get the appended payload from here, once. It is mapped and the linker
208 // script prevents it from overlapping with other objects.
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000209 let appended_data = unsafe { get_appended_data_slice() };
210
211 // Up to this point, we were using the built-in static (from .rodata) page tables.
212
213 let mut page_table = mmu::PageTable::from_static_layout().map_err(|e| {
214 error!("Failed to set up the dynamic page tables: {e}");
215 RebootReason::InternalError
216 })?;
217
218 const CONSOLE_LEN: usize = 1; // vmbase::uart::Uart only uses one u8 register.
219 let uart_range = console::BASE_ADDRESS..(console::BASE_ADDRESS + CONSOLE_LEN);
220 page_table.map_device(&uart_range).map_err(|e| {
221 error!("Failed to remap the UART as a dynamic page table entry: {e}");
222 RebootReason::InternalError
223 })?;
224
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100225 // SAFETY - We only get the appended payload from here, once. It is statically mapped and the
226 // linker script prevents it from overlapping with other objects.
227 let mut appended = unsafe { AppendedPayload::new(appended_data) }.ok_or_else(|| {
228 error!("No valid configuration found");
229 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000230 })?;
231
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000232 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100233
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000234 debug!("Activating dynamic page table...");
235 // SAFETY - page_table duplicates the static mappings for everything that the Rust code is
236 // aware of so activating it shouldn't have any visible effect.
237 unsafe { page_table.activate() };
238 debug!("... Success!");
239
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100240 MEMORY.lock().replace(MemoryTracker::new(page_table));
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 Vukalovic85a00d72023-04-20 09:51:10 +0100265 MEMORY.lock().take().unwrap();
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100266
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100267 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100268}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100269
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100270fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
271 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000272 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100273 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000274 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100275 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000276 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100277 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000278 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100279
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000280 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 +0100281
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100282 let scratch = layout::scratch_range();
283
284 assert_ne!(scratch.len(), 0, "scratch memory is empty.");
285 assert_eq!(scratch.start % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
286 assert_eq!(scratch.end % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
287
288 assert!(bcc.is_within(&scratch));
289 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
290 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
291
292 let stack = mmu::stack_range();
293
294 assert_ne!(stack.len(), 0, "stack region is empty.");
295 assert_eq!(stack.start % ASM_STP_ALIGN, 0, "Misaligned stack region.");
296 assert_eq!(stack.end % ASM_STP_ALIGN, 0, "Misaligned stack region.");
297
298 // 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 +0000299 // Disable the exception vector, caches and page table and then jump to the payload at the
300 // given address, passing it the given FDT pointer.
301 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100302 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
303 unsafe {
304 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100305 "cmp {scratch}, {bcc}",
306 "b.hs 1f",
307
308 // Zero .data & .bss until BCC.
309 "0: stp xzr, xzr, [{scratch}], 16",
310 "cmp {scratch}, {bcc}",
311 "b.lo 0b",
312
313 "1:",
314 // Skip BCC.
315 "mov {scratch}, {bcc_end}",
316 "cmp {scratch}, {scratch_end}",
317 "b.hs 1f",
318
319 // Keep zeroing .data & .bss.
320 "0: stp xzr, xzr, [{scratch}], 16",
321 "cmp {scratch}, {scratch_end}",
322 "b.lo 0b",
323
324 "1:",
325 // Flush d-cache over .data & .bss (including BCC).
326 "0: dc cvau, {cache_line}",
327 "add {cache_line}, {cache_line}, {dcache_line_size}",
328 "cmp {cache_line}, {scratch_end}",
329 "b.lo 0b",
330
331 "mov {cache_line}, {stack}",
332 // Zero stack region.
333 "0: stp xzr, xzr, [{stack}], 16",
334 "cmp {stack}, {stack_end}",
335 "b.lo 0b",
336
337 // Flush d-cache over stack region.
338 "0: dc cvau, {cache_line}",
339 "add {cache_line}, {cache_line}, {dcache_line_size}",
340 "cmp {cache_line}, {stack_end}",
341 "b.lo 0b",
342
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100343 "msr sctlr_el1, {sctlr_el1_val}",
344 "isb",
345 "mov x1, xzr",
346 "mov x2, xzr",
347 "mov x3, xzr",
348 "mov x4, xzr",
349 "mov x5, xzr",
350 "mov x6, xzr",
351 "mov x7, xzr",
352 "mov x8, xzr",
353 "mov x9, xzr",
354 "mov x10, xzr",
355 "mov x11, xzr",
356 "mov x12, xzr",
357 "mov x13, xzr",
358 "mov x14, xzr",
359 "mov x15, xzr",
360 "mov x16, xzr",
361 "mov x17, xzr",
362 "mov x18, xzr",
363 "mov x19, xzr",
364 "mov x20, xzr",
365 "mov x21, xzr",
366 "mov x22, xzr",
367 "mov x23, xzr",
368 "mov x24, xzr",
369 "mov x25, xzr",
370 "mov x26, xzr",
371 "mov x27, xzr",
372 "mov x28, xzr",
373 "mov x29, xzr",
374 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100375 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100376 "dsb nsh",
377 "br x30",
378 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100379 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
380 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
381 cache_line = in(reg) u64::try_from(scratch.start).unwrap(),
382 scratch = in(reg) u64::try_from(scratch.start).unwrap(),
383 scratch_end = in(reg) u64::try_from(scratch.end).unwrap(),
384 stack = in(reg) u64::try_from(stack.start).unwrap(),
385 stack_end = in(reg) u64::try_from(stack.end).unwrap(),
386 dcache_line_size = in(reg) u64::try_from(helpers::min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100387 in("x0") fdt_address,
388 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100389 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100390 );
391 };
392}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100393
394unsafe fn get_appended_data_slice() -> &'static mut [u8] {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100395 let range = mmu::PageTable::appended_payload_range();
Alan Stokesa0e42962023-04-14 17:59:50 +0100396 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
397 // objects.
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100398 unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100399}
400
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000401enum AppendedConfigType {
402 Valid,
403 Invalid,
404 NotFound,
405}
406
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100407enum AppendedPayload<'a> {
408 /// Configuration data.
409 Config(config::Config<'a>),
410 /// Deprecated raw BCC, as used in Android T.
411 LegacyBcc(&'a mut [u8]),
412}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100413
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100414impl<'a> AppendedPayload<'a> {
415 /// SAFETY - 'data' should respect the alignment of config::Header.
416 unsafe fn new(data: &'a mut [u8]) -> Option<Self> {
Alan Stokesa0e42962023-04-14 17:59:50 +0100417 // Safety: This fn has the same constraint as us.
418 match unsafe { Self::guess_config_type(data) } {
419 AppendedConfigType::Valid => {
420 // Safety: This fn has the same constraint as us.
421 let config = unsafe { config::Config::new(data) };
422 Some(Self::Config(config.unwrap()))
423 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000424 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
425 const BCC_SIZE: usize = helpers::SIZE_4KB;
426 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
427 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
428 }
429 _ => None,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100430 }
431 }
432
Alan Stokesa0e42962023-04-14 17:59:50 +0100433 /// SAFETY - 'data' should respect the alignment of config::Header.
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000434 unsafe fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100435 // This function is necessary to prevent the borrow checker from getting confused
436 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
437 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100438
439 // Safety: This fn has the same constraint as us.
440 match unsafe { config::Config::new(data) } {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000441 Err(config::Error::InvalidMagic) => {
442 warn!("No configuration data found at {addr:?}");
443 AppendedConfigType::NotFound
444 }
445 Err(e) => {
446 error!("Invalid configuration data at {addr:?}: {e}");
447 AppendedConfigType::Invalid
448 }
449 Ok(_) => AppendedConfigType::Valid,
450 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100451 }
452
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000453 fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100454 match self {
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000455 Self::Config(ref mut cfg) => cfg.get_entries(),
456 Self::LegacyBcc(ref mut bcc) => (bcc, None),
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000457 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100458 }
459}