Merge "[VM] Refactor VirtualMachineConfig serialization from file"
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 71bac72..77de696 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -8,6 +8,9 @@
     defaults: ["vmbase_ffi_defaults"],
     srcs: ["src/main.rs"],
     edition: "2021",
+    features: [
+        "legacy",
+    ],
     rustlibs: [
         "libbuddy_system_allocator",
         "liblog_rust_nostd",
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index dc2087d..c0ad878 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -19,11 +19,15 @@
 use crate::mmio_guard;
 use core::arch::asm;
 use core::slice;
-use log::{debug, error, LevelFilter};
-use vmbase::{console, logger, main, power::reboot};
+use log::debug;
+use log::error;
+use log::LevelFilter;
+use vmbase::{console, layout, logger, main, power::reboot};
 
 #[derive(Debug, Clone)]
 enum RebootReason {
+    /// A malformed BCC was received.
+    InvalidBcc,
     /// An unexpected internal error happened.
     InternalError,
 }
@@ -80,8 +84,17 @@
         RebootReason::InternalError
     })?;
 
+    // SAFETY - We only get the appended payload from here, once. It is mapped and the linker
+    // script prevents it from overlapping with other objects.
+    let bcc = as_bcc(unsafe { get_appended_data_slice() }).ok_or_else(|| {
+        error!("Invalid BCC");
+        RebootReason::InvalidBcc
+    })?;
+
     // This wrapper allows main() to be blissfully ignorant of platform details.
-    crate::main(fdt, payload);
+    crate::main(fdt, payload, bcc);
+
+    // TODO: Overwrite BCC before jumping to payload to avoid leaking our sealing key.
 
     mmio_guard::unmap(console::BASE_ADDRESS).map_err(|e| {
         error!("Failed to unshare the UART: {e}");
@@ -147,3 +160,22 @@
         );
     };
 }
+
+unsafe fn get_appended_data_slice() -> &'static mut [u8] {
+    let base = helpers::align_up(layout::binary_end(), helpers::SIZE_4KB).unwrap();
+    // pvmfw is contained in a 2MiB region so the payload can't be larger than the 2MiB alignment.
+    let size = helpers::align_up(base, helpers::SIZE_2MB).unwrap() - base;
+
+    slice::from_raw_parts_mut(base as *mut u8, size)
+}
+
+fn as_bcc(data: &mut [u8]) -> Option<&mut [u8]> {
+    const BCC_SIZE: usize = helpers::SIZE_4KB;
+
+    if cfg!(feature = "legacy") {
+        // TODO(b/256148034): return None if BccHandoverParse(bcc) != kDiceResultOk.
+        Some(&mut data[..BCC_SIZE])
+    } else {
+        None
+    }
+}
diff --git a/pvmfw/src/helpers.rs b/pvmfw/src/helpers.rs
index adfc189..59cf9f3 100644
--- a/pvmfw/src/helpers.rs
+++ b/pvmfw/src/helpers.rs
@@ -17,12 +17,25 @@
 pub const SIZE_4KB: usize = 4 << 10;
 pub const SIZE_2MB: usize = 2 << 20;
 
-/// Computes the address of the page containing a given address.
-pub const fn page_of(addr: usize, page_size: usize) -> usize {
-    addr & !(page_size - 1)
+/// Computes the largest multiple of the provided alignment smaller or equal to the address.
+///
+/// Note: the result is undefined if alignment isn't a power of two.
+pub const fn unchecked_align_down(addr: usize, alignment: usize) -> usize {
+    addr & !(alignment - 1)
+}
+
+/// Safe wrapper around unchecked_align_up() that validates its assumptions and doesn't wrap.
+pub const fn align_up(addr: usize, alignment: usize) -> Option<usize> {
+    if !alignment.is_power_of_two() {
+        None
+    } else if let Some(s) = addr.checked_add(alignment - 1) {
+        Some(unchecked_align_down(s, alignment))
+    } else {
+        None
+    }
 }
 
 /// Computes the address of the 4KiB page containing a given address.
 pub const fn page_4kb_of(addr: usize) -> usize {
-    page_of(addr, SIZE_4KB)
+    unchecked_align_down(addr, SIZE_4KB)
 }
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index c0bb263..8178d0b 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -29,7 +29,7 @@
 use avb::PUBLIC_KEY;
 use log::{debug, info};
 
-fn main(fdt: &mut [u8], payload: &[u8]) {
+fn main(fdt: &mut [u8], payload: &[u8], bcc: &[u8]) {
     info!("pVM firmware");
     debug!(
         "fdt_address={:#018x}, payload_start={:#018x}, payload_size={:#018x}",
@@ -37,6 +37,7 @@
         payload.as_ptr() as usize,
         payload.len(),
     );
+    debug!("BCC: {:?} ({:#x} bytes)", bcc.as_ptr(), bcc.len());
     debug!("AVB public key: addr={:?}, size={:#x} ({1})", PUBLIC_KEY.as_ptr(), PUBLIC_KEY.len());
     info!("Starting payload...");
 }