blob: 4889c28b99a13740bda780d95b794242b3b3911c [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;
Alice Wang90e6f162023-04-17 13:49:45 +000031use hyp::get_hypervisor;
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
67 match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +010068 Ok((entry, bcc)) => jump_to_payload(fdt_address, entry.try_into().unwrap(), bcc),
Pierre-Clément Tosid836b5b2022-12-05 10:49:38 +000069 Err(_) => reboot(), // TODO(b/220071963) propagate the reason back to the host.
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010070 }
71
72 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
73}
74
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000075struct MemorySlices<'a> {
76 fdt: &'a mut libfdt::Fdt,
77 kernel: &'a [u8],
78 ramdisk: Option<&'a [u8]>,
79}
80
81impl<'a> MemorySlices<'a> {
82 fn new(
83 fdt: usize,
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +000084 kernel: usize,
85 kernel_size: usize,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000086 memory: &mut MemoryTracker,
87 ) -> Result<Self, RebootReason> {
88 // SAFETY - SIZE_2MB is non-zero.
89 const FDT_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(helpers::SIZE_2MB) };
90 // 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.
93 let range = memory.alloc_mut(fdt, FDT_SIZE).map_err(|e| {
94 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?}");
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000110 memory.shrink(&memory_range).map_err(|_| {
111 error!("Failed to use memory range value from DT: {memory_range:#x?}");
112 RebootReason::InvalidFdt
113 })?;
114
Jiyong Park6a8789a2023-03-21 14:50:59 +0900115 let kernel_range = if let Some(r) = info.kernel_range {
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000116 memory.alloc_range(&r).map_err(|e| {
117 error!("Failed to obtain the kernel range with DT range: {e}");
118 RebootReason::InternalError
119 })?
120 } else if cfg!(feature = "legacy") {
121 warn!("Failed to find the kernel range in the DT; falling back to legacy ABI");
122
123 let kernel_size = NonZeroUsize::new(kernel_size).ok_or_else(|| {
124 error!("Invalid kernel size: {kernel_size:#x}");
125 RebootReason::InvalidPayload
126 })?;
127
128 memory.alloc(kernel, kernel_size).map_err(|e| {
129 error!("Failed to obtain the kernel range with legacy range: {e}");
130 RebootReason::InternalError
131 })?
132 } else {
133 error!("Failed to locate the kernel from the DT");
134 return Err(RebootReason::InvalidPayload);
135 };
136
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000137 // SAFETY - The tracker validated the range to be in main memory, mapped, and not overlap.
138 let kernel =
Pierre-Clément Tosic3811b82022-11-29 11:24:16 +0000139 unsafe { slice::from_raw_parts(kernel_range.start as *const u8, kernel_range.len()) };
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000140
Jiyong Park6a8789a2023-03-21 14:50:59 +0900141 let ramdisk = if let Some(r) = info.initrd_range {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000142 debug!("Located ramdisk at {r:?}");
143 let r = memory.alloc_range(&r).map_err(|e| {
144 error!("Failed to obtain the initrd range: {e}");
145 RebootReason::InvalidRamdisk
146 })?;
147
148 // SAFETY - The region was validated by memory to be in main memory, mapped, and
149 // not overlap.
150 Some(unsafe { slice::from_raw_parts(r.start as *const u8, r.len()) })
151 } else {
152 info!("Couldn't locate the ramdisk from the device tree");
153 None
154 };
155
156 Ok(Self { fdt, kernel, ramdisk })
157 }
158}
159
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100160/// Sets up the environment for main() and wraps its result for start().
161///
162/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
163/// the assumption that its environment has been properly configured.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100164fn main_wrapper(
165 fdt: usize,
166 payload: usize,
167 payload_size: usize,
168) -> Result<(usize, Range<usize>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100169 // Limitations in this function:
170 // - only access MMIO once (and while) it has been mapped and configured
171 // - only perform logging once the logger has been initialized
172 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100173
174 // SAFETY - This function should and will only be called once, here.
175 unsafe { heap::init() };
176
Pierre-Clément Tosidbd72862022-10-21 14:31:02 +0100177 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100178
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100179 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
180 // builds that have tweaked the logger::init() call will actually attempt to log the message.
181
Alice Wang90e6f162023-04-17 13:49:45 +0000182 get_hypervisor().mmio_guard_init().map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100183 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100184 RebootReason::InternalError
185 })?;
186
Alice Wang90e6f162023-04-17 13:49:45 +0000187 get_hypervisor().mmio_guard_map(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100188 debug!("Failed to configure the UART: {e}");
189 RebootReason::InternalError
190 })?;
191
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100192 crypto::init();
193
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100194 // SAFETY - We only get the appended payload from here, once. It is mapped and the linker
195 // script prevents it from overlapping with other objects.
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000196 let appended_data = unsafe { get_appended_data_slice() };
197
198 // Up to this point, we were using the built-in static (from .rodata) page tables.
199
200 let mut page_table = mmu::PageTable::from_static_layout().map_err(|e| {
201 error!("Failed to set up the dynamic page tables: {e}");
202 RebootReason::InternalError
203 })?;
204
205 const CONSOLE_LEN: usize = 1; // vmbase::uart::Uart only uses one u8 register.
206 let uart_range = console::BASE_ADDRESS..(console::BASE_ADDRESS + CONSOLE_LEN);
207 page_table.map_device(&uart_range).map_err(|e| {
208 error!("Failed to remap the UART as a dynamic page table entry: {e}");
209 RebootReason::InternalError
210 })?;
211
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100212 // SAFETY - We only get the appended payload from here, once. It is statically mapped and the
213 // linker script prevents it from overlapping with other objects.
214 let mut appended = unsafe { AppendedPayload::new(appended_data) }.ok_or_else(|| {
215 error!("No valid configuration found");
216 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000217 })?;
218
Pierre-Clément Tosiefe780c2023-02-21 21:36:30 +0000219 let (bcc_slice, debug_policy) = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100220
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000221 debug!("Activating dynamic page table...");
222 // SAFETY - page_table duplicates the static mappings for everything that the Rust code is
223 // aware of so activating it shouldn't have any visible effect.
224 unsafe { page_table.activate() };
225 debug!("... Success!");
226
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100227 MEMORY.lock().replace(MemoryTracker::new(page_table));
228 let slices = MemorySlices::new(fdt, payload, payload_size, MEMORY.lock().as_mut().unwrap())?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000229
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000230 rand::init().map_err(|e| {
231 error!("Failed to initialize rand: {e}");
232 RebootReason::InternalError
233 })?;
234
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100235 // This wrapper allows main() to be blissfully ignorant of platform details.
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100236 let next_bcc = crate::main(
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100237 slices.fdt,
238 slices.kernel,
239 slices.ramdisk,
240 bcc_slice,
241 debug_policy,
242 MEMORY.lock().as_mut().unwrap(),
243 )?;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100244
Pierre-Clément Tosi8383c542022-11-01 14:07:29 +0000245 helpers::flushed_zeroize(bcc_slice);
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000246 helpers::flush(slices.fdt.as_slice());
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100247
Andrew Walbran19690632022-12-07 16:41:30 +0000248 info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100249 MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000250 error!("Failed to unshare MMIO ranges: {e}");
251 RebootReason::InternalError
252 })?;
Alice Wang90e6f162023-04-17 13:49:45 +0000253 get_hypervisor().mmio_guard_unmap(console::BASE_ADDRESS).map_err(|e| {
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100254 error!("Failed to unshare the UART: {e}");
255 RebootReason::InternalError
256 })?;
Jakob Vukalovic85a00d72023-04-20 09:51:10 +0100257 MEMORY.lock().take().unwrap();
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100258
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100259 Ok((slices.kernel.as_ptr() as usize, next_bcc))
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100260}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100261
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100262fn jump_to_payload(fdt_address: u64, payload_start: u64, bcc: Range<usize>) -> ! {
263 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000264 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100265 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000266 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100267 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000268 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100269 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000270 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100271
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000272 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 +0100273
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100274 let scratch = layout::scratch_range();
275
276 assert_ne!(scratch.len(), 0, "scratch memory is empty.");
277 assert_eq!(scratch.start % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
278 assert_eq!(scratch.end % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
279
280 assert!(bcc.is_within(&scratch));
281 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
282 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
283
284 let stack = mmu::stack_range();
285
286 assert_ne!(stack.len(), 0, "stack region is empty.");
287 assert_eq!(stack.start % ASM_STP_ALIGN, 0, "Misaligned stack region.");
288 assert_eq!(stack.end % ASM_STP_ALIGN, 0, "Misaligned stack region.");
289
290 // 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 +0000291 // Disable the exception vector, caches and page table and then jump to the payload at the
292 // given address, passing it the given FDT pointer.
293 //
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100294 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
295 unsafe {
296 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100297 "cmp {scratch}, {bcc}",
298 "b.hs 1f",
299
300 // Zero .data & .bss until BCC.
301 "0: stp xzr, xzr, [{scratch}], 16",
302 "cmp {scratch}, {bcc}",
303 "b.lo 0b",
304
305 "1:",
306 // Skip BCC.
307 "mov {scratch}, {bcc_end}",
308 "cmp {scratch}, {scratch_end}",
309 "b.hs 1f",
310
311 // Keep zeroing .data & .bss.
312 "0: stp xzr, xzr, [{scratch}], 16",
313 "cmp {scratch}, {scratch_end}",
314 "b.lo 0b",
315
316 "1:",
317 // Flush d-cache over .data & .bss (including BCC).
318 "0: dc cvau, {cache_line}",
319 "add {cache_line}, {cache_line}, {dcache_line_size}",
320 "cmp {cache_line}, {scratch_end}",
321 "b.lo 0b",
322
323 "mov {cache_line}, {stack}",
324 // Zero stack region.
325 "0: stp xzr, xzr, [{stack}], 16",
326 "cmp {stack}, {stack_end}",
327 "b.lo 0b",
328
329 // Flush d-cache over stack region.
330 "0: dc cvau, {cache_line}",
331 "add {cache_line}, {cache_line}, {dcache_line_size}",
332 "cmp {cache_line}, {stack_end}",
333 "b.lo 0b",
334
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100335 "msr sctlr_el1, {sctlr_el1_val}",
336 "isb",
337 "mov x1, xzr",
338 "mov x2, xzr",
339 "mov x3, xzr",
340 "mov x4, xzr",
341 "mov x5, xzr",
342 "mov x6, xzr",
343 "mov x7, xzr",
344 "mov x8, xzr",
345 "mov x9, xzr",
346 "mov x10, xzr",
347 "mov x11, xzr",
348 "mov x12, xzr",
349 "mov x13, xzr",
350 "mov x14, xzr",
351 "mov x15, xzr",
352 "mov x16, xzr",
353 "mov x17, xzr",
354 "mov x18, xzr",
355 "mov x19, xzr",
356 "mov x20, xzr",
357 "mov x21, xzr",
358 "mov x22, xzr",
359 "mov x23, xzr",
360 "mov x24, xzr",
361 "mov x25, xzr",
362 "mov x26, xzr",
363 "mov x27, xzr",
364 "mov x28, xzr",
365 "mov x29, xzr",
366 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100367 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100368 "dsb nsh",
369 "br x30",
370 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100371 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
372 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
373 cache_line = in(reg) u64::try_from(scratch.start).unwrap(),
374 scratch = in(reg) u64::try_from(scratch.start).unwrap(),
375 scratch_end = in(reg) u64::try_from(scratch.end).unwrap(),
376 stack = in(reg) u64::try_from(stack.start).unwrap(),
377 stack_end = in(reg) u64::try_from(stack.end).unwrap(),
378 dcache_line_size = in(reg) u64::try_from(helpers::min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100379 in("x0") fdt_address,
380 in("x30") payload_start,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100381 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100382 );
383 };
384}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100385
386unsafe fn get_appended_data_slice() -> &'static mut [u8] {
387 let base = helpers::align_up(layout::binary_end(), helpers::SIZE_4KB).unwrap();
388 // pvmfw is contained in a 2MiB region so the payload can't be larger than the 2MiB alignment.
389 let size = helpers::align_up(base, helpers::SIZE_2MB).unwrap() - base;
390
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.
393 unsafe { slice::from_raw_parts_mut(base as *mut u8, size) }
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}