blob: d17247438369d5503cbc48a32e4ab600cd6b97ce [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};
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> {
85 fn new(
86 fdt: usize,
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +000087 kernel: usize,
88 kernel_size: usize,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000089 memory: &mut MemoryTracker,
90 ) -> Result<Self, RebootReason> {
91 // SAFETY - SIZE_2MB is non-zero.
92 const FDT_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(helpers::SIZE_2MB) };
93 // TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
94 // e.g. by generating a DTBO for a template DT in main() and, on return, re-map DT as RW,
95 // overwrite with the template DT and apply the DTBO.
96 let range = memory.alloc_mut(fdt, FDT_SIZE).map_err(|e| {
97 error!("Failed to allocate the FDT range: {e}");
98 RebootReason::InternalError
99 })?;
100
101 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
102 let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
103 let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
104 error!("Failed to spawn the FDT wrapper: {e}");
105 RebootReason::InvalidFdt
106 })?;
107
Jiyong Park6a8789a2023-03-21 14:50:59 +0900108 let info = fdt::sanitize_device_tree(fdt)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000109 debug!("Fdt passed validation!");
110
Jiyong Park6a8789a2023-03-21 14:50:59 +0900111 let memory_range = info.memory_range;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000112 debug!("Resizing MemoryTracker to range {memory_range:#x?}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000113 memory.shrink(&memory_range).map_err(|_| {
114 error!("Failed to use memory range value from DT: {memory_range:#x?}");
115 RebootReason::InvalidFdt
116 })?;
117
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000118 if get_hypervisor().has_cap(HypervisorCap::DYNAMIC_MEM_SHARE) {
119 memory.init_dynamic_shared_pool().map_err(|e| {
120 error!("Failed to initialize dynamically shared pool: {e}");
121 RebootReason::InternalError
122 })?;
123 } else {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700124 let range = info.swiotlb_info.fixed_range().ok_or_else(|| {
125 error!("Pre-shared pool range not specified in swiotlb node");
126 RebootReason::InvalidFdt
127 })?;
128
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000129 memory.init_static_shared_pool(range).map_err(|e| {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700130 error!("Failed to initialize pre-shared pool {e}");
131 RebootReason::InvalidFdt
132 })?;
133 }
134
Jiyong Park6a8789a2023-03-21 14:50:59 +0900135 let kernel_range = if let Some(r) = info.kernel_range {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000136 memory.alloc_range(&r).map_err(|e| {
137 error!("Failed to obtain the kernel range with DT range: {e}");
138 RebootReason::InternalError
139 })?
140 } else if cfg!(feature = "legacy") {
141 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
142
143 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
144 error!("Invalid kernel size: {kernel_size:#x}");
145 RebootReason::InvalidPayload
146 })?;
147
148 memory.alloc(kernel, kernel_size).map_err(|e| {
149 error!("Failed to obtain the kernel range with legacy range: {e}");
150 RebootReason::InternalError
151 })?
152 } else {
153 error!("Failed to locate the kernel from the DT");
154 return Err(RebootReason::InvalidPayload);
155 };
156
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000157 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
158 let kernel =
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000159 unsafe { slice::from_raw_parts(kernel_range.start as *const u8, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000160
Jiyong Park6a8789a2023-03-21 14:50:59 +0900161 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000162 debug!("Located ramdisk at {r:?}");
163 let r = memory.alloc_range(&r).map_err(|e| {
164 error!("Failed to obtain the initrd range: {e}");
165 RebootReason::InvalidRamdisk
166 })?;
167
168 // SAFETY - The region was validated by memory to be in main memory, mapped, and
169 // not overlap.
170 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
171 } else {
172 info!("Couldn't locate the ramdisk from the device tree");
173 None
174 };
175
176 Ok(Self { fdt, kernel, ramdisk })
177 }
178}
179
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100180/// Sets up the environment for main() and wraps its result for start().
181///
182/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
183/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100184fn main_wrapper(
185 fdt: usize,
186 payload: usize,
187 payload_size: usize,
188) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100189 // Limitations in this function:
190 // - only access MMIO once (and while) it has been mapped and configured
191 // - only perform logging once the logger has been initialized
192 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100193
Pierre-Clément Tosidbd72862022-10-21 14:31:02 +0100194 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100195
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100196 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
197 // builds that have tweaked the logger::init() call will actually attempt to log the message.
198
Alice Wang90e6f162023-04-17 13:49:45 +0000199 get_hypervisor().mmio_guard_init().map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100200 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100201 RebootReason::InternalError
202 })?;
203
Alice Wang90e6f162023-04-17 13:49:45 +0000204 get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100205 debug!("Failed to configure the UART: {e}");
206 RebootReason::InternalError
207 })?;
208
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100209 crypto::init();
210
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100211 // SAFETY - We only get the appended payload from here, once. It is mapped and the linker
212 // script prevents it from overlapping with other objects.
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000213 let appended_data = unsafe { get_appended_data_slice() };
214
215 // Up to this point, we were using the built-in static (from .rodata) page tables.
216
217 let mut page_table = mmu::PageTable::from_static_layout().map_err(|e| {
218 error!("Failed to set up the dynamic page tables: {e}");
219 RebootReason::InternalError
220 })?;
221
222 const CONSOLE_LEN: usize = 1; // vmbase::uart::Uart only uses one u8 register.
223 let uart_range = console::BASE_ADDRESS..(console::BASE_ADDRESS + CONSOLE_LEN);
224 page_table.map_device(&uart_range).map_err(|e| {
225 error!("Failed to remap the UART as a dynamic page table entry: {e}");
226 RebootReason::InternalError
227 })?;
228
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100229 // SAFETY - We only get the appended payload from here, once. It is statically mapped and the
230 // linker script prevents it from overlapping with other objects.
231 let mut appended = unsafe { AppendedPayload::new(appended_data) }.ok_or_else(|| {
232 error!("No valid configuration found");
233 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000234 })?;
235
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000236 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100237
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000238 debug!("Activating dynamic page table...");
239 // SAFETY - page_table duplicates the static mappings for everything that the Rust code is
240 // aware of so activating it shouldn't have any visible effect.
241 unsafe { page_table.activate() };
242 debug!("... Success!");
243
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100244 MEMORY.lock().replace(MemoryTracker::new(page_table));
245 let slices = MemorySlices::new(fdt, payload, payload_size, MEMORY.lock().as_mut().unwrap())?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000246
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000247 rand::init().map_err(|e| {
248 error!("Failed to initialize rand: {e}");
249 RebootReason::InternalError
250 })?;
251
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100252 // This wrapper allows main() to be blissfully ignorant of platform details.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100253 let next_bcc = crate::main(
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100254 slices.fdt,
255 slices.kernel,
256 slices.ramdisk,
257 bcc_slice,
258 debug_policy,
259 MEMORY.lock().as_mut().unwrap(),
260 )?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100261
Pierre-Clément Tosi8383c542022-11-01 14:07:29 +0000262 helpers::flushed_zeroize(bcc_slice);
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100263
Andrew Walbran19690632022-12-07 16:41:30 +0000264 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100265 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000266 error!("Failed to unshare MMIO ranges: {e}");
267 RebootReason::InternalError
268 })?;
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000269 // Call unshare_all_memory here (instead of relying on the dtor) while UART is still mapped.
270 MEMORY.lock().as_mut().unwrap().unshare_all_memory();
Alice Wang90e6f162023-04-17 13:49:45 +0000271 get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100272 error!("Failed to unshare the UART: {e}");
273 RebootReason::InternalError
274 })?;
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100275 MEMORY.lock().take().unwrap();
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100276
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100277 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100278}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100279
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100280fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
281 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000282 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100283 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000284 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100285 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000286 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100287 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000288 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100289
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000290 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 +0100291
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100292 let scratch = layout::scratch_range();
293
294 assert_ne!(scratch.len(), 0, "scratch memory is empty.");
295 assert_eq!(scratch.start % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
296 assert_eq!(scratch.end % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
297
298 assert!(bcc.is_within(&scratch));
299 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
300 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
301
302 let stack = mmu::stack_range();
303
304 assert_ne!(stack.len(), 0, "stack region is empty.");
305 assert_eq!(stack.start % ASM_STP_ALIGN, 0, "Misaligned stack region.");
306 assert_eq!(stack.end % ASM_STP_ALIGN, 0, "Misaligned stack region.");
307
308 // 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 +0000309 // Disable the exception vector, caches and page table and then jump to the payload at the
310 // given address, passing it the given FDT pointer.
311 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100312 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
313 unsafe {
314 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100315 "cmp {scratch}, {bcc}",
316 "b.hs 1f",
317
318 // Zero .data & .bss until BCC.
319 "0: stp xzr, xzr, [{scratch}], 16",
320 "cmp {scratch}, {bcc}",
321 "b.lo 0b",
322
323 "1:",
324 // Skip BCC.
325 "mov {scratch}, {bcc_end}",
326 "cmp {scratch}, {scratch_end}",
327 "b.hs 1f",
328
329 // Keep zeroing .data & .bss.
330 "0: stp xzr, xzr, [{scratch}], 16",
331 "cmp {scratch}, {scratch_end}",
332 "b.lo 0b",
333
334 "1:",
335 // Flush d-cache over .data & .bss (including BCC).
336 "0: dc cvau, {cache_line}",
337 "add {cache_line}, {cache_line}, {dcache_line_size}",
338 "cmp {cache_line}, {scratch_end}",
339 "b.lo 0b",
340
341 "mov {cache_line}, {stack}",
342 // Zero stack region.
343 "0: stp xzr, xzr, [{stack}], 16",
344 "cmp {stack}, {stack_end}",
345 "b.lo 0b",
346
347 // Flush d-cache over stack region.
348 "0: dc cvau, {cache_line}",
349 "add {cache_line}, {cache_line}, {dcache_line_size}",
350 "cmp {cache_line}, {stack_end}",
351 "b.lo 0b",
352
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100353 "msr sctlr_el1, {sctlr_el1_val}",
354 "isb",
355 "mov x1, xzr",
356 "mov x2, xzr",
357 "mov x3, xzr",
358 "mov x4, xzr",
359 "mov x5, xzr",
360 "mov x6, xzr",
361 "mov x7, xzr",
362 "mov x8, xzr",
363 "mov x9, xzr",
364 "mov x10, xzr",
365 "mov x11, xzr",
366 "mov x12, xzr",
367 "mov x13, xzr",
368 "mov x14, xzr",
369 "mov x15, xzr",
370 "mov x16, xzr",
371 "mov x17, xzr",
372 "mov x18, xzr",
373 "mov x19, xzr",
374 "mov x20, xzr",
375 "mov x21, xzr",
376 "mov x22, xzr",
377 "mov x23, xzr",
378 "mov x24, xzr",
379 "mov x25, xzr",
380 "mov x26, xzr",
381 "mov x27, xzr",
382 "mov x28, xzr",
383 "mov x29, xzr",
384 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100385 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100386 "dsb nsh",
387 "br x30",
388 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100389 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
390 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
391 cache_line = in(reg) u64::try_from(scratch.start).unwrap(),
392 scratch = in(reg) u64::try_from(scratch.start).unwrap(),
393 scratch_end = in(reg) u64::try_from(scratch.end).unwrap(),
394 stack = in(reg) u64::try_from(stack.start).unwrap(),
395 stack_end = in(reg) u64::try_from(stack.end).unwrap(),
396 dcache_line_size = in(reg) u64::try_from(helpers::min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100397 in("x0") fdt_address,
398 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100399 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100400 );
401 };
402}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100403
404unsafe fn get_appended_data_slice() -> &'static mut [u8] {
405 let base = helpers::align_up(layout::binary_end(), helpers::SIZE_4KB).unwrap();
406 // pvmfw is contained in a 2MiB region so the payload can't be larger than the 2MiB alignment.
407 let size = helpers::align_up(base, helpers::SIZE_2MB).unwrap() - base;
408
Alan Stokesa0e42962023-04-14 17:59:50 +0100409 // SAFETY: This region is mapped and the linker script prevents it from overlapping with other
410 // objects.
411 unsafe { slice::from_raw_parts_mut(base as *mut u8, size) }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100412}
413
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000414enum AppendedConfigType {
415 Valid,
416 Invalid,
417 NotFound,
418}
419
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100420enum AppendedPayload<'a> {
421 /// Configuration data.
422 Config(config::Config<'a>),
423 /// Deprecated raw BCC, as used in Android T.
424 LegacyBcc(&'a mut [u8]),
425}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100426
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100427impl<'a> AppendedPayload<'a> {
428 /// SAFETY - 'data' should respect the alignment of config::Header.
429 unsafe fn new(data: &'a mut [u8]) -> Option<Self> {
Alan Stokesa0e42962023-04-14 17:59:50 +0100430 // Safety: This fn has the same constraint as us.
431 match unsafe { Self::guess_config_type(data) } {
432 AppendedConfigType::Valid => {
433 // Safety: This fn has the same constraint as us.
434 let config = unsafe { config::Config::new(data) };
435 Some(Self::Config(config.unwrap()))
436 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000437 AppendedConfigType::NotFound if cfg!(feature = "legacy") => {
438 const BCC_SIZE: usize = helpers::SIZE_4KB;
439 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
440 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
441 }
442 _ => None,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100443 }
444 }
445
Alan Stokesa0e42962023-04-14 17:59:50 +0100446 /// SAFETY - 'data' should respect the alignment of config::Header.
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000447 unsafe fn guess_config_type(data: &mut [u8]) -> AppendedConfigType {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100448 // This function is necessary to prevent the borrow checker from getting confused
449 // about the ownership of data in new(); see https://users.rust-lang.org/t/78467.
450 let addr = data.as_ptr();
Alan Stokesa0e42962023-04-14 17:59:50 +0100451
452 // Safety: This fn has the same constraint as us.
453 match unsafe { config::Config::new(data) } {
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000454 Err(config::Error::InvalidMagic) => {
455 warn!("No configuration data found at {addr:?}");
456 AppendedConfigType::NotFound
457 }
458 Err(e) => {
459 error!("Invalid configuration data at {addr:?}: {e}");
460 AppendedConfigType::Invalid
461 }
462 Ok(_) => AppendedConfigType::Valid,
463 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100464 }
465
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000466 fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>) {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100467 match self {
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000468 Self::Config(ref mut cfg) => cfg.get_entries(),
469 Self::LegacyBcc(ref mut bcc) => (bcc, None),
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000470 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100471 }
472}