pvmfw: Pass BCC to next stage through DT

Generate the next stage BCC in a heap-allocated page-aligned buffer that
our allocator leaks so that it outlives the execution of pvmfw and can
be accessed by the next stage. Flush the cache to ensure that it isn't
destroyed during invalidation (by the next stage) or missed if accessed
with the caches disabled.

Pass the size and location of the region through a pKVM-standard
device tree node.

Bug: 256827715
Test: atest MicrodroidHostTests
Change-Id: I5931054f74063eac3b3b21a6bcbe4881af2e1e8e
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index efd3e7c..9c62e03 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -19,6 +19,8 @@
 #![feature(default_alloc_error_handler)]
 #![feature(ptr_const_cast)] // Stabilized in 1.65.0
 
+extern crate alloc;
+
 mod avb;
 mod config;
 mod dice;
@@ -34,10 +36,14 @@
 mod pci;
 mod smccc;
 
+use alloc::boxed::Box;
+
 use crate::{
     avb::PUBLIC_KEY,
     dice::derive_next_bcc,
     entry::RebootReason,
+    fdt::add_dice_node,
+    helpers::flush,
     helpers::GUEST_PAGE_SIZE,
     memory::MemoryTracker,
     pci::{find_virtio_devices, map_mmio},
@@ -51,7 +57,7 @@
 const NEXT_BCC_SIZE: usize = GUEST_PAGE_SIZE;
 
 fn main(
-    fdt: &Fdt,
+    fdt: &mut Fdt,
     signed_kernel: &[u8],
     ramdisk: Option<&[u8]>,
     bcc: &bcc::Handover,
@@ -82,8 +88,6 @@
         RebootReason::PayloadVerificationError
     })?;
 
-    let mut scratch_bcc = [0; NEXT_BCC_SIZE];
-    let next_bcc = &mut scratch_bcc; // TODO(b/256827715): Pass result BCC to next stage.
     let debug_mode = false; // TODO(b/256148034): Derive the DICE mode from the received initrd.
     const HASH_SIZE: usize = 64;
     let mut hashes = [0; HASH_SIZE * 2]; // TODO(b/256148034): Extract AvbHashDescriptor digests.
@@ -101,6 +105,12 @@
     } else {
         &hashes[..HASH_SIZE]
     };
+    let next_bcc = heap::aligned_boxed_slice(NEXT_BCC_SIZE, GUEST_PAGE_SIZE).ok_or_else(|| {
+        error!("Failed to allocate the next-stage BCC");
+        RebootReason::InternalError
+    })?;
+    // By leaking the slice, its content will be left behind for the next stage.
+    let next_bcc = Box::leak(next_bcc);
     let next_bcc_size =
         derive_next_bcc(bcc, next_bcc, code_hash, debug_mode, PUBLIC_KEY).map_err(|e| {
             error!("Failed to derive next-stage DICE secrets: {e:?}");
@@ -108,6 +118,13 @@
         })?;
     trace!("Next BCC: {:x?}", bcc::Handover::new(&next_bcc[..next_bcc_size]));
 
+    flush(next_bcc);
+
+    add_dice_node(fdt, next_bcc.as_ptr() as usize, NEXT_BCC_SIZE).map_err(|e| {
+        error!("Failed to add DICE node to device tree: {e}");
+        RebootReason::InternalError
+    })?;
+
     info!("Starting payload...");
     Ok(())
 }