Merge "Require unsafe blocks in unsafe functions"
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index dff7d13..7ea1189 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -34,6 +34,7 @@
"libvmbase",
"libzerocopy_nostd",
"libzeroize_nostd",
+ "libspin_nostd",
],
}
diff --git a/pvmfw/README.md b/pvmfw/README.md
index 4e93648..1eb7286 100644
--- a/pvmfw/README.md
+++ b/pvmfw/README.md
@@ -197,16 +197,20 @@
that it differs from the `BccHandover` defined by the specification in that its
`Bcc` field is mandatory (while optional in the original).
-Devices that fully implement DICE should provide a certificate rooted at the
-Unique Device Secret (UDS) in a boot stage preceding the pvmfw loader (typically
-ABL), in such a way that it would receive a valid `BccHandover`, that can be
-passed to [`BccHandoverMainFlow`][BccHandoverMainFlow] along with the inputs
-described below.
+Ideally devices that fully implement DICE should provide a certificate rooted at
+the Unique Device Secret (UDS) in a boot stage preceding the pvmfw loader
+(typically ABL), in such a way that it would receive a valid `BccHandover`, that
+can be passed to [`BccHandoverMainFlow`][BccHandoverMainFlow] along with the
+inputs described below.
-Otherwise, as an intermediate step towards supporting DICE throughout the
-software stack of the device, incomplete implementations may root the BCC at the
-pvmfw loader, using an arbitrary constant as initial CDI. The pvmfw loader can
-easily do so by:
+However, there is a limitation in Android 14 that means that a UDS-rooted DICE
+chain must not be used for pvmfw. A non-UDS rooted DICE chain is recommended for
+Android 14.
+
+As an intermediate step towards supporting DICE throughout the software stack of
+the device, incomplete implementations may root the BCC at the pvmfw loader,
+using an arbitrary constant as initial CDI. The pvmfw loader can easily do so
+by:
1. Building a BCC-less `BccHandover` using CBOR operations
([example][Trusty-BCC]) and containing the constant CDIs
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index f625f1a..398c8df 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -19,7 +19,7 @@
use crate::fdt;
use crate::heap;
use crate::helpers;
-use crate::memory::MemoryTracker;
+use crate::memory::{MemoryTracker, MEMORY};
use crate::mmu;
use crate::rand;
use core::arch::asm;
@@ -217,8 +217,8 @@
unsafe { page_table.activate() };
debug!("... Success!");
- let mut memory = MemoryTracker::new(page_table);
- let slices = MemorySlices::new(fdt, payload, payload_size, &mut memory)?;
+ MEMORY.lock().replace(MemoryTracker::new(page_table));
+ let slices = MemorySlices::new(fdt, payload, payload_size, MEMORY.lock().as_mut().unwrap())?;
rand::init().map_err(|e| {
error!("Failed to initialize rand: {e}");
@@ -226,13 +226,20 @@
})?;
// This wrapper allows main() to be blissfully ignorant of platform details.
- crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy, &mut memory)?;
+ crate::main(
+ slices.fdt,
+ slices.kernel,
+ slices.ramdisk,
+ bcc_slice,
+ debug_policy,
+ MEMORY.lock().as_mut().unwrap(),
+ )?;
helpers::flushed_zeroize(bcc_slice);
helpers::flush(slices.fdt.as_slice());
info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
- memory.mmio_unmap_all().map_err(|e| {
+ MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
error!("Failed to unshare MMIO ranges: {e}");
RebootReason::InternalError
})?;
@@ -240,6 +247,7 @@
error!("Failed to unshare the UART: {e}");
RebootReason::InternalError
})?;
+ MEMORY.lock().take().unwrap();
Ok(slices.kernel.as_ptr() as usize)
}
diff --git a/pvmfw/src/exceptions.rs b/pvmfw/src/exceptions.rs
index 3ca4e0f..462a9cc 100644
--- a/pvmfw/src/exceptions.rs
+++ b/pvmfw/src/exceptions.rs
@@ -15,22 +15,92 @@
//! Exception handlers.
use crate::{helpers::page_4kb_of, read_sysreg};
+use core::fmt;
use vmbase::console;
+use vmbase::logger;
use vmbase::{eprintln, power::reboot};
-const ESR_32BIT_EXT_DABT: usize = 0x96000010;
const UART_PAGE: usize = page_4kb_of(console::BASE_ADDRESS);
+#[derive(Debug)]
+enum HandleExceptionError {
+ UnknownException,
+}
+
+impl fmt::Display for HandleExceptionError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::UnknownException => write!(f, "An unknown exception occurred, not handled."),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+enum Esr {
+ DataAbortTranslationFault,
+ DataAbortPermissionFault,
+ DataAbortSyncExternalAbort,
+ Unknown(usize),
+}
+
+impl Esr {
+ const EXT_DABT_32BIT: usize = 0x96000010;
+ const TRANSL_FAULT_BASE_32BIT: usize = 0x96000004;
+ const TRANSL_FAULT_ISS_MASK_32BIT: usize = !0x143;
+ const PERM_FAULT_BASE_32BIT: usize = 0x9600004C;
+ const PERM_FAULT_ISS_MASK_32BIT: usize = !0x103;
+}
+
+impl From<usize> for Esr {
+ fn from(esr: usize) -> Self {
+ if esr == Self::EXT_DABT_32BIT {
+ Self::DataAbortSyncExternalAbort
+ } else if esr & Self::TRANSL_FAULT_ISS_MASK_32BIT == Self::TRANSL_FAULT_BASE_32BIT {
+ Self::DataAbortTranslationFault
+ } else if esr & Self::PERM_FAULT_ISS_MASK_32BIT == Self::PERM_FAULT_BASE_32BIT {
+ Self::DataAbortPermissionFault
+ } else {
+ Self::Unknown(esr)
+ }
+ }
+}
+
+impl fmt::Display for Esr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::DataAbortSyncExternalAbort => write!(f, "Synchronous external abort"),
+ Self::DataAbortTranslationFault => write!(f, "Translation fault"),
+ Self::DataAbortPermissionFault => write!(f, "Permission fault"),
+ Self::Unknown(v) => write!(f, "Unknown exception esr={v:#08x}"),
+ }
+ }
+}
+
+fn handle_exception(_esr: Esr, _far: usize) -> Result<(), HandleExceptionError> {
+ Err(HandleExceptionError::UnknownException)
+}
+
+#[inline]
+fn handling_uart_exception(esr: Esr, far: usize) -> bool {
+ esr == Esr::DataAbortSyncExternalAbort && page_4kb_of(far) == UART_PAGE
+}
+
#[no_mangle]
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
- let esr = read_sysreg!("esr_el1");
+ // Disable logging in exception handler to prevent unsafe writes to UART.
+ let _guard = logger::suppress();
+ let esr: Esr = read_sysreg!("esr_el1").into();
let far = read_sysreg!("far_el1");
- // Don't print to the UART if we're handling the exception it could raise.
- if esr != ESR_32BIT_EXT_DABT || page_4kb_of(far) != UART_PAGE {
- eprintln!("sync_exception_current");
- eprintln!("esr={esr:#08x}");
+
+ if let Err(e) = handle_exception(esr, far) {
+ // Don't print to the UART if we are handling an exception it could raise.
+ if !handling_uart_exception(esr, far) {
+ eprintln!("sync_exception_current");
+ eprintln!("{e}");
+ eprintln!("{esr}, far={far:#08x}");
+ }
+ reboot()
}
- reboot();
}
#[no_mangle]
diff --git a/pvmfw/src/helpers.rs b/pvmfw/src/helpers.rs
index 9c739d1..8c05217 100644
--- a/pvmfw/src/helpers.rs
+++ b/pvmfw/src/helpers.rs
@@ -19,6 +19,7 @@
pub const SIZE_4KB: usize = 4 << 10;
pub const SIZE_2MB: usize = 2 << 20;
+pub const SIZE_4MB: usize = 4 << 20;
pub const GUEST_PAGE_SIZE: usize = SIZE_4KB;
diff --git a/pvmfw/src/memory.rs b/pvmfw/src/memory.rs
index 2d5eb5c..7df25f2 100644
--- a/pvmfw/src/memory.rs
+++ b/pvmfw/src/memory.rs
@@ -16,7 +16,7 @@
#![deny(unsafe_op_in_unsafe_fn)]
-use crate::helpers::{self, align_down, align_up, page_4kb_of, SIZE_4KB};
+use crate::helpers::{self, align_down, align_up, page_4kb_of, SIZE_4KB, SIZE_4MB};
use crate::mmu;
use alloc::alloc::alloc_zeroed;
use alloc::alloc::dealloc;
@@ -31,6 +31,7 @@
use core::result;
use hyp::get_hypervisor;
use log::error;
+use spin::mutex::SpinMutex;
use tinyvec::ArrayVec;
/// Base of the system's contiguous "main" memory.
@@ -40,6 +41,9 @@
pub type MemoryRange = Range<usize>;
+pub static MEMORY: SpinMutex<Option<MemoryTracker>> = SpinMutex::new(None);
+unsafe impl Send for MemoryTracker {}
+
#[derive(Clone, Copy, Debug, Default)]
enum MemoryType {
#[default]
@@ -132,6 +136,7 @@
impl MemoryTracker {
const CAPACITY: usize = 5;
const MMIO_CAPACITY: usize = 5;
+ const PVMFW_RANGE: MemoryRange = (BASE_ADDR - SIZE_4MB)..BASE_ADDR;
/// Create a new instance from an active page table, covering the maximum RAM size.
pub fn new(page_table: mmu::PageTable) -> Self {
@@ -197,7 +202,7 @@
/// appropriately.
pub fn map_mmio_range(&mut self, range: MemoryRange) -> Result<()> {
// MMIO space is below the main memory region.
- if range.end > self.total.start {
+ if range.end > self.total.start || overlaps(&Self::PVMFW_RANGE, &range) {
return Err(MemoryTrackerError::OutOfRange);
}
if self.mmio_regions.iter().any(|r| overlaps(r, &range)) {