Merge changes I74c8b81b,I382e42c1 into main

* changes:
  pvmfw: Support QTVMs through missing DICE handover
  pvmfw: Delay panicking when DICE chain missing
diff --git a/guest/pvmfw/src/config.rs b/guest/pvmfw/src/config.rs
index 1f9eacf..a16da35 100644
--- a/guest/pvmfw/src/config.rs
+++ b/guest/pvmfw/src/config.rs
@@ -141,7 +141,7 @@
 
 #[derive(Default)]
 pub struct Entries<'a> {
-    pub dice_handover: &'a mut [u8],
+    pub dice_handover: Option<&'a mut [u8]>,
     pub debug_policy: Option<&'a [u8]>,
     pub vm_dtbo: Option<&'a mut [u8]>,
     pub vm_ref_dt: Option<&'a [u8]>,
@@ -295,9 +295,6 @@
         }
         let [dice_handover, debug_policy, vm_dtbo, vm_ref_dt] = entries;
 
-        // The platform DICE handover has always been required.
-        let dice_handover = dice_handover.unwrap();
-
         // We have no reason to mutate so drop the `mut`.
         let debug_policy = debug_policy.map(|x| &*x);
         let vm_ref_dt = vm_ref_dt.map(|x| &*x);
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index 8bbbce1..cb6c64e 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -139,7 +139,7 @@
         slices.fdt,
         slices.kernel,
         slices.ramdisk,
-        config_entries.dice_handover,
+        config_entries.dice_handover.as_deref(),
         config_entries.debug_policy,
         config_entries.vm_dtbo,
         config_entries.vm_ref_dt,
@@ -147,11 +147,14 @@
     if let Some(r) = next_dice_handover {
         slices.add_dice_handover(r);
     }
+
     // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
     let keep_uart = cfg!(debuggable_vms_improvements) && debuggable_payload;
 
     // Writable-dirty regions will be flushed when MemoryTracker is dropped.
-    config_entries.dice_handover.zeroize();
+    if let Some(r) = config_entries.dice_handover {
+        r.zeroize();
+    }
 
     unshare_all_mmio_except_uart().map_err(|e| {
         error!("Failed to unshare MMIO ranges: {e}");
@@ -220,8 +223,8 @@
     fn get_entries(self) -> config::Entries<'a> {
         match self {
             Self::Config(cfg) => cfg.get_entries(),
-            Self::LegacyDiceHandover(dice_handover) => {
-                config::Entries { dice_handover, ..Default::default() }
+            Self::LegacyDiceHandover(d) => {
+                config::Entries { dice_handover: Some(d), ..Default::default() }
             }
         }
     }
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index 7bf68b8..db60849 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -56,7 +56,7 @@
     untrusted_fdt: &mut Fdt,
     signed_kernel: &[u8],
     ramdisk: Option<&[u8]>,
-    current_dice_handover: &[u8],
+    current_dice_handover: Option<&[u8]>,
     mut debug_policy: Option<&[u8]>,
     vm_dtbo: Option<&mut [u8]>,
     vm_ref_dt: Option<&[u8]>,
@@ -71,8 +71,7 @@
         debug!("Ramdisk: None");
     }
 
-    let (dice_handover_bytes, dice_cdi_seal, dice_context, dice_debug_mode) =
-        parse_dice_handover(current_dice_handover)?;
+    let (parsed_dice, dice_debug_mode) = parse_dice_handover(current_dice_handover)?;
 
     // The bootloader should never pass us a debug policy when the boot is secure (the bootloader
     // is locked). If it gets it wrong, disregard it & log it, to avoid it causing problems.
@@ -81,7 +80,13 @@
         debug_policy = None;
     }
 
-    let (verified_boot_data, debuggable, guest_page_size) = {
+    // Policy/Hidden ABI: If the pvmfw loader (typically ABL) didn't pass a DICE handover (which is
+    // technically still mandatory, as per the config data specification), skip DICE, AVB, and RBP.
+    // This is to support Qualcomm QTVMs, which perform guest image verification in TrustZone.
+    let (verified_boot_data, debuggable, guest_page_size) = if current_dice_handover.is_none() {
+        warn!("Verified boot is disabled!");
+        (None, false, SIZE_4KB)
+    } else {
         let (dat, debug, sz) = perform_verified_boot(signed_kernel, ramdisk)?;
         (Some(dat), debug, sz)
     };
@@ -97,6 +102,8 @@
             error!("Failed to compute partial DICE inputs: {e:?}");
             RebootReason::InternalError
         })?;
+        let (dice_handover_bytes, dice_cdi_seal, dice_context) =
+            parsed_dice.expect("Missing DICE values with VB data");
         let (new_instance, salt, defer_rollback_protection) =
             perform_rollback_protection(fdt, data, &dice_inputs, &dice_cdi_seal)?;
         trace!("Got salt for instance: {salt:x?}");
@@ -140,8 +147,11 @@
 }
 
 fn parse_dice_handover(
-    bytes: &[u8],
-) -> Result<(Cow<'_, [u8]>, Vec<u8>, DiceContext, bool), RebootReason> {
+    bytes: Option<&[u8]>,
+) -> Result<(Option<(Cow<'_, [u8]>, Vec<u8>, DiceContext)>, bool), RebootReason> {
+    let Some(bytes) = bytes else {
+        return Ok((None, false));
+    };
     let dice_handover = bcc_handover_parse(bytes).map_err(|e| {
         error!("Invalid DICE Handover: {e:?}");
         RebootReason::InvalidDiceHandover
@@ -181,7 +191,7 @@
         Cow::Owned(truncated_bytes)
     };
 
-    Ok((bytes_for_next, cdi_seal, dice_context, is_debug_mode))
+    Ok((Some((bytes_for_next, cdi_seal, dice_context)), is_debug_mode))
 }
 
 fn perform_dice_derivation<'a>(