blob: 862fb1dabe76986e8cba8ba14fa3506dd93be492 [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 Tosibfa40602024-12-09 20:13:57 +000018use crate::memory::MemorySlices;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010019use core::arch::asm;
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000020use core::mem::size_of;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010021use core::slice;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010022use log::error;
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010023use log::warn;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010024use log::LevelFilter;
Alice Wang4be4dd02023-06-07 07:50:40 +000025use vmbase::util::RangeExt as _;
Alice Wangeacb7382023-06-05 12:53:54 +000026use vmbase::{
Pierre-Clément Tosi8ab7c372024-10-30 20:46:04 +000027 arch::aarch64::min_dcache_line_size,
Pierre-Clément Tosieba83162024-11-02 12:11:48 +000028 configure_heap, console_writeln, layout, limit_stack_size, main,
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000029 memory::{
Pierre-Clément Tosiae071612024-11-02 13:13:34 +000030 deactivate_dynamic_page_tables, map_image_footer, unshare_all_memory,
31 unshare_all_mmio_except_uart, unshare_uart, MemoryTrackerError, SIZE_128KB, SIZE_4KB,
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +000032 },
Alice Wangeacb7382023-06-05 12:53:54 +000033 power::reboot,
34};
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010035use zeroize::Zeroize;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010036
37#[derive(Debug, Clone)]
Andrew Walbran19690632022-12-07 16:41:30 +000038pub enum RebootReason {
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +010039 /// A malformed BCC was received.
40 InvalidBcc,
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +010041 /// An invalid configuration was appended to pvmfw.
42 InvalidConfig,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010043 /// An unexpected internal error happened.
44 InternalError,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000045 /// The provided FDT was invalid.
46 InvalidFdt,
47 /// The provided payload was invalid.
48 InvalidPayload,
49 /// The provided ramdisk was invalid.
50 InvalidRamdisk,
Alice Wang28cbcf12022-12-01 07:58:28 +000051 /// Failed to verify the payload.
52 PayloadVerificationError,
Pierre-Clément Tosi4f4f5eb2022-12-08 14:31:42 +000053 /// DICE layering process failed.
54 SecretDerivationError,
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010055}
56
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +010057impl RebootReason {
58 pub fn as_avf_reboot_string(&self) -> &'static str {
59 match self {
60 Self::InvalidBcc => "PVM_FIRMWARE_INVALID_BCC",
61 Self::InvalidConfig => "PVM_FIRMWARE_INVALID_CONFIG_DATA",
62 Self::InternalError => "PVM_FIRMWARE_INTERNAL_ERROR",
63 Self::InvalidFdt => "PVM_FIRMWARE_INVALID_FDT",
64 Self::InvalidPayload => "PVM_FIRMWARE_INVALID_PAYLOAD",
65 Self::InvalidRamdisk => "PVM_FIRMWARE_INVALID_RAMDISK",
66 Self::PayloadVerificationError => "PVM_FIRMWARE_PAYLOAD_VERIFICATION_FAILED",
67 Self::SecretDerivationError => "PVM_FIRMWARE_SECRET_DERIVATION_FAILED",
68 }
69 }
70}
71
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010072main!(start);
Pierre-Clément Tosi6a4808c2023-06-29 09:19:38 +000073configure_heap!(SIZE_128KB);
Pierre-Clément Tosieba83162024-11-02 12:11:48 +000074limit_stack_size!(SIZE_4KB * 12);
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010075
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +000076#[derive(Debug)]
77enum NextStage {
78 LinuxBoot(usize),
79 LinuxBootWithUart(usize),
80}
81
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010082/// Entry point for pVM firmware.
83pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +000084 let fdt_address = fdt_address.try_into().unwrap();
85 let payload_start = payload_start.try_into().unwrap();
86 let payload_size = payload_size.try_into().unwrap();
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010087
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +000088 let reboot_reason = match main_wrapper(fdt_address, payload_start, payload_size) {
89 Err(r) => r,
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +000090 Ok((next_stage, slices)) => match next_stage {
91 NextStage::LinuxBootWithUart(ep) => jump_to_payload(ep, &slices),
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +000092 NextStage::LinuxBoot(ep) => {
93 if let Err(e) = unshare_uart() {
94 error!("Failed to unmap UART: {e}");
95 RebootReason::InternalError
96 } else {
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +000097 jump_to_payload(ep, &slices)
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +000098 }
99 }
100 },
101 };
102
103 const REBOOT_REASON_CONSOLE: usize = 1;
104 console_writeln!(REBOOT_REASON_CONSOLE, "{}", reboot_reason.as_avf_reboot_string());
105 reboot()
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100106
107 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
108}
109
110/// Sets up the environment for main() and wraps its result for start().
111///
112/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
113/// the assumption that its environment has been properly configured.
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000114fn main_wrapper<'a>(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100115 fdt: usize,
116 payload: usize,
117 payload_size: usize,
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000118) -> Result<(NextStage, MemorySlices<'a>), RebootReason> {
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +0100119 // Limitations in this function:
120 // - only access MMIO once (and while) it has been mapped and configured
121 // - only perform logging once the logger has been initialized
122 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosifc531152022-10-20 12:22:23 +0100123
Pierre-Clément Tosid3305482023-06-29 15:03:48 +0000124 log::set_max_level(LevelFilter::Info);
Pierre-Clément Tosi41748ed2023-03-31 18:20:40 +0100125
Pierre-Clément Tosi229dd9d2024-11-02 10:34:27 +0000126 let appended_data = get_appended_data_slice().map_err(|e| {
127 error!("Failed to map the appended data: {e}");
128 RebootReason::InternalError
129 })?;
Alan Stokesc3829f12023-06-02 15:02:23 +0100130
Alan Stokes65618332023-12-15 14:09:25 +0000131 let appended = AppendedPayload::new(appended_data).ok_or_else(|| {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100132 error!("No valid configuration found");
133 RebootReason::InvalidConfig
Pierre-Clément Tosia8a4a202022-11-03 14:16:46 +0000134 })?;
135
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000136 let config_entries = appended.get_entries();
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100137
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000138 let mut slices = MemorySlices::new(fdt, payload, payload_size)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000139
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100140 // This wrapper allows main() to be blissfully ignorant of platform details.
Pierre-Clément Tosi64aff642024-07-31 16:20:21 +0100141 let (next_bcc, debuggable_payload) = crate::main(
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000142 slices.fdt,
143 slices.kernel,
144 slices.ramdisk,
145 config_entries.bcc,
146 config_entries.debug_policy,
Pierre-Clément Tosi92778802024-11-19 17:36:14 +0000147 config_entries.vm_dtbo,
148 config_entries.vm_ref_dt,
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000149 )?;
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000150 slices.add_dice_chain(next_bcc);
Pierre-Clément Tosi12f923e2024-12-04 22:30:45 +0000151 // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
152 let keep_uart = cfg!(debuggable_vms_improvements) && debuggable_payload;
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100153
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100154 // Writable-dirty regions will be flushed when MemoryTracker is dropped.
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000155 config_entries.bcc.zeroize();
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +0100156
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000157 unshare_all_mmio_except_uart().map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000158 error!("Failed to unshare MMIO ranges: {e}");
159 RebootReason::InternalError
160 })?;
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000161 unshare_all_memory();
Pierre-Clément Tosi64aff642024-07-31 16:20:21 +0100162
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +0000163 let next_stage = select_next_stage(slices.kernel, keep_uart);
164
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000165 Ok((next_stage, slices))
Pierre-Clément Tosi12f923e2024-12-04 22:30:45 +0000166}
167
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +0000168fn select_next_stage(kernel: &[u8], keep_uart: bool) -> NextStage {
169 if keep_uart {
170 NextStage::LinuxBootWithUart(kernel.as_ptr() as _)
171 } else {
172 NextStage::LinuxBoot(kernel.as_ptr() as _)
Pierre-Clément Tosi5ad1e8c2023-06-29 10:36:48 +0000173 }
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +0000174}
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100175
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000176fn jump_to_payload(entrypoint: usize, slices: &MemorySlices) -> ! {
177 let fdt_address = slices.fdt.as_ptr() as usize;
178 let bcc = slices
179 .dice_chain
180 .map(|slice| {
181 let r = slice.as_ptr_range();
182 (r.start as usize)..(r.end as usize)
183 })
184 .expect("Missing DICE chain");
185
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000186 deactivate_dynamic_page_tables();
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +0100187
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100188 const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000189 const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100190 // Stage 1 instruction access cacheability is unaffected.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000191 const SCTLR_EL1_I: u64 = 0b1 << 12;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100192 // SETEND instruction disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000193 const SCTLR_EL1_SED: u64 = 0b1 << 8;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100194 // Various IT instructions are disabled at EL0 in aarch32 mode.
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000195 const SCTLR_EL1_ITD: u64 = 0b1 << 7;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100196
Pierre-Clément Tosi6c0d48b2022-11-07 11:00:32 +0000197 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 +0100198
Pierre-Clément Tosi0b02a2b2024-11-28 22:48:27 +0000199 let scratch = layout::data_bss_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100200
Alice Wanga3931aa2023-07-05 12:52:09 +0000201 assert_ne!(scratch.end - scratch.start, 0, "scratch memory is empty.");
202 assert_eq!(scratch.start.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
203 assert_eq!(scratch.end.0 % ASM_STP_ALIGN, 0, "scratch memory is misaligned.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100204
Alice Wanga3931aa2023-07-05 12:52:09 +0000205 assert!(bcc.is_within(&(scratch.start.0..scratch.end.0)));
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100206 assert_eq!(bcc.start % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
207 assert_eq!(bcc.end % ASM_STP_ALIGN, 0, "Misaligned guest BCC.");
208
Pierre-Clément Tosieba83162024-11-02 12:11:48 +0000209 let stack = layout::stack_range();
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100210
Alice Wanga3931aa2023-07-05 12:52:09 +0000211 assert_ne!(stack.end - stack.start, 0, "stack region is empty.");
212 assert_eq!(stack.start.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
213 assert_eq!(stack.end.0 % ASM_STP_ALIGN, 0, "Misaligned stack region.");
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100214
Pierre-Clément Tosi0b02a2b2024-11-28 22:48:27 +0000215 let eh_stack = layout::eh_stack_range();
216
217 assert_ne!(eh_stack.end - eh_stack.start, 0, "EH stack region is empty.");
218 assert_eq!(eh_stack.start.0 % ASM_STP_ALIGN, 0, "Misaligned EH stack region.");
219 assert_eq!(eh_stack.end.0 % ASM_STP_ALIGN, 0, "Misaligned EH stack region.");
220
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100221 // 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 +0000222 // Disable the exception vector, caches and page table and then jump to the payload at the
223 // given address, passing it the given FDT pointer.
224 //
Andrew Walbran20bb4e42023-07-07 13:55:55 +0100225 // SAFETY: We're exiting pvmfw by passing the register values we need to a noreturn asm!().
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100226 unsafe {
227 asm!(
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100228 "cmp {scratch}, {bcc}",
229 "b.hs 1f",
230
231 // Zero .data & .bss until BCC.
232 "0: stp xzr, xzr, [{scratch}], 16",
233 "cmp {scratch}, {bcc}",
234 "b.lo 0b",
235
236 "1:",
237 // Skip BCC.
238 "mov {scratch}, {bcc_end}",
239 "cmp {scratch}, {scratch_end}",
240 "b.hs 1f",
241
242 // Keep zeroing .data & .bss.
243 "0: stp xzr, xzr, [{scratch}], 16",
244 "cmp {scratch}, {scratch_end}",
245 "b.lo 0b",
246
247 "1:",
248 // Flush d-cache over .data & .bss (including BCC).
249 "0: dc cvau, {cache_line}",
250 "add {cache_line}, {cache_line}, {dcache_line_size}",
251 "cmp {cache_line}, {scratch_end}",
252 "b.lo 0b",
253
254 "mov {cache_line}, {stack}",
255 // Zero stack region.
256 "0: stp xzr, xzr, [{stack}], 16",
257 "cmp {stack}, {stack_end}",
258 "b.lo 0b",
259
260 // Flush d-cache over stack region.
261 "0: dc cvau, {cache_line}",
262 "add {cache_line}, {cache_line}, {dcache_line_size}",
263 "cmp {cache_line}, {stack_end}",
264 "b.lo 0b",
265
Pierre-Clément Tosi0b02a2b2024-11-28 22:48:27 +0000266 "mov {cache_line}, {eh_stack}",
267 // Zero EH stack region.
268 "0: stp xzr, xzr, [{eh_stack}], 16",
269 "cmp {eh_stack}, {eh_stack_end}",
270 "b.lo 0b",
271
272 // Flush d-cache over EH stack region.
273 "0: dc cvau, {cache_line}",
274 "add {cache_line}, {cache_line}, {dcache_line_size}",
275 "cmp {cache_line}, {eh_stack_end}",
276 "b.lo 0b",
277
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100278 "msr sctlr_el1, {sctlr_el1_val}",
279 "isb",
280 "mov x1, xzr",
281 "mov x2, xzr",
282 "mov x3, xzr",
283 "mov x4, xzr",
284 "mov x5, xzr",
285 "mov x6, xzr",
286 "mov x7, xzr",
287 "mov x8, xzr",
288 "mov x9, xzr",
289 "mov x10, xzr",
290 "mov x11, xzr",
291 "mov x12, xzr",
292 "mov x13, xzr",
293 "mov x14, xzr",
294 "mov x15, xzr",
295 "mov x16, xzr",
296 "mov x17, xzr",
297 "mov x18, xzr",
298 "mov x19, xzr",
299 "mov x20, xzr",
300 "mov x21, xzr",
301 "mov x22, xzr",
302 "mov x23, xzr",
303 "mov x24, xzr",
304 "mov x25, xzr",
305 "mov x26, xzr",
306 "mov x27, xzr",
307 "mov x28, xzr",
308 "mov x29, xzr",
309 "msr ttbr0_el1, xzr",
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100310 // Ensure that CMOs have completed before entering payload.
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100311 "dsb nsh",
312 "br x30",
313 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100314 bcc = in(reg) u64::try_from(bcc.start).unwrap(),
315 bcc_end = in(reg) u64::try_from(bcc.end).unwrap(),
Alice Wanga3931aa2023-07-05 12:52:09 +0000316 cache_line = in(reg) u64::try_from(scratch.start.0).unwrap(),
317 scratch = in(reg) u64::try_from(scratch.start.0).unwrap(),
318 scratch_end = in(reg) u64::try_from(scratch.end.0).unwrap(),
319 stack = in(reg) u64::try_from(stack.start.0).unwrap(),
320 stack_end = in(reg) u64::try_from(stack.end.0).unwrap(),
Pierre-Clément Tosi0b02a2b2024-11-28 22:48:27 +0000321 eh_stack = in(reg) u64::try_from(eh_stack.start.0).unwrap(),
322 eh_stack_end = in(reg) u64::try_from(eh_stack.end.0).unwrap(),
Alice Wang3fa9b802023-06-06 07:52:31 +0000323 dcache_line_size = in(reg) u64::try_from(min_dcache_line_size()).unwrap(),
Pierre-Clément Tosi9bb62ac2024-12-06 23:42:46 +0000324 in("x0") u64::try_from(fdt_address).unwrap(),
Pierre-Clément Tosibfa40602024-12-09 20:13:57 +0000325 in("x30") u64::try_from(entrypoint).unwrap(),
Pierre-Clément Tosi97f52492023-04-04 15:52:17 +0100326 options(noreturn),
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +0100327 );
328 };
329}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100330
Pierre-Clément Tosi229dd9d2024-11-02 10:34:27 +0000331fn get_appended_data_slice() -> Result<&'static mut [u8], MemoryTrackerError> {
Pierre-Clément Tosic26e2202024-11-01 23:12:23 +0000332 let range = map_image_footer()?;
Pierre-Clément Tosi229dd9d2024-11-02 10:34:27 +0000333 // SAFETY: This region was just mapped for the first time (as map_image_footer() didn't fail)
334 // and the linker script prevents it from overlapping with other objects.
335 Ok(unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) })
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100336}
337
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100338enum AppendedPayload<'a> {
339 /// Configuration data.
340 Config(config::Config<'a>),
341 /// Deprecated raw BCC, as used in Android T.
342 LegacyBcc(&'a mut [u8]),
343}
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100344
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100345impl<'a> AppendedPayload<'a> {
Alan Stokesc3829f12023-06-02 15:02:23 +0100346 fn new(data: &'a mut [u8]) -> Option<Self> {
Pierre-Clément Tosi147addf2024-04-15 15:07:58 +0100347 // The borrow checker gets confused about the ownership of data (see inline comments) so we
348 // intentionally obfuscate it using a raw pointer; see a similar issue (still not addressed
349 // in v1.77) in https://users.rust-lang.org/t/78467.
350 let data_ptr = data as *mut [u8];
351
352 // Config::new() borrows data as mutable ...
353 match config::Config::new(data) {
354 // ... so this branch has a mutable reference to data, from the Ok(Config<'a>). But ...
355 Ok(valid) => Some(Self::Config(valid)),
356 // ... if Config::new(data).is_err(), the Err holds no ref to data. However ...
357 Err(config::Error::InvalidMagic) if cfg!(feature = "legacy") => {
358 // ... the borrow checker still complains about a second mutable ref without this.
359 // SAFETY: Pointer to a valid mut (not accessed elsewhere), 'a lifetime re-used.
360 let data: &'a mut _ = unsafe { &mut *data_ptr };
361
Alice Wangeacb7382023-06-05 12:53:54 +0000362 const BCC_SIZE: usize = SIZE_4KB;
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000363 warn!("Assuming the appended data at {:?} to be a raw BCC", data.as_ptr());
364 Some(Self::LegacyBcc(&mut data[..BCC_SIZE]))
365 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000366 Err(e) => {
Pierre-Clément Tosi147addf2024-04-15 15:07:58 +0100367 error!("Invalid configuration data at {data_ptr:?}: {e}");
368 None
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000369 }
Pierre-Clément Tosi7aca7ff2022-12-12 14:04:30 +0000370 }
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100371 }
372
Alan Stokes65618332023-12-15 14:09:25 +0000373 fn get_entries(self) -> config::Entries<'a> {
Pierre-Clément Tosi20b60962022-10-17 13:35:27 +0100374 match self {
Alan Stokesd0cf3cd2023-12-12 14:36:37 +0000375 Self::Config(cfg) => cfg.get_entries(),
376 Self::LegacyBcc(bcc) => config::Entries { bcc, ..Default::default() },
Pierre-Clément Tosi8edf72e2022-12-06 16:02:57 +0000377 }
Pierre-Clément Tosie8726e42022-10-17 13:35:27 +0100378 }
379}