Merge "Merge TQ2A.230405.003"
diff --git a/authfs/service/authfs_service.rc b/authfs/service/authfs_service.rc
index 409e91c..bc67c83 100644
--- a/authfs/service/authfs_service.rc
+++ b/authfs/service/authfs_service.rc
@@ -3,3 +3,4 @@
     socket authfs_service stream 0666 root system
     # SYS_ADMIN capability allows to mount FUSE filesystem
     capabilities SYS_ADMIN
+    user root
diff --git a/authfs/tests/benchmarks/Android.bp b/authfs/tests/benchmarks/Android.bp
index b30ecdd..110d000 100644
--- a/authfs/tests/benchmarks/Android.bp
+++ b/authfs/tests/benchmarks/Android.bp
@@ -12,6 +12,7 @@
         "AuthFsHostTestCommon",
         "MicrodroidHostTestHelper",
         "cts-host-utils",
+        "MicrodroidTestPreparer", // Workaround for sandboxed test environment to install this
     ],
     test_suites: ["general-tests"],
     data_device_bins_first: [
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index bf4c678..bc6ab25 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -53,6 +53,8 @@
 /// Parameters to be used when creating a virtual machine instance.
 #[derive(Default, Debug, Clone)]
 pub struct VmParameters {
+    /// The name of VM for identifying.
+    pub name: String,
     /// Whether the VM should be debuggable.
     pub debug_mode: bool,
     /// CPU topology of the VM. Defaults to 1 vCPU.
@@ -115,7 +117,7 @@
         };
 
         let config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
-            name: String::from("Compos"),
+            name: parameters.name.clone(),
             apk: Some(apk_fd),
             idsig: Some(idsig_fd),
             instanceImage: Some(instance_fd),
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index 2ce12f8..d7c0f9a 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -41,12 +41,14 @@
 
     pub fn start_current_instance(&self) -> Result<CompOsInstance> {
         let mut vm_parameters = new_vm_parameters()?;
+        vm_parameters.name = String::from("Composd");
         vm_parameters.prefer_staged = true;
         self.start_instance(CURRENT_INSTANCE_DIR, vm_parameters)
     }
 
     pub fn start_test_instance(&self, prefer_staged: bool) -> Result<CompOsInstance> {
         let mut vm_parameters = new_vm_parameters()?;
+        vm_parameters.name = String::from("ComposdTest");
         vm_parameters.debug_mode = true;
         vm_parameters.prefer_staged = prefer_staged;
         self.start_instance(TEST_INSTANCE_DIR, vm_parameters)
diff --git a/compos/verify/verify.rs b/compos/verify/verify.rs
index 13e9292..952e9c7 100644
--- a/compos/verify/verify.rs
+++ b/compos/verify/verify.rs
@@ -115,6 +115,7 @@
         &idsig_manifest_apk,
         &idsig_manifest_ext_apk,
         &VmParameters {
+            name: String::from("ComposVerify"),
             cpu_topology: VmCpuTopology::OneCpu, // This VM runs very little work at boot
             debug_mode: args.debug,
             ..Default::default()
diff --git a/libs/smccc/Android.bp b/libs/smccc/Android.bp
new file mode 100644
index 0000000..96943d8
--- /dev/null
+++ b/libs/smccc/Android.bp
@@ -0,0 +1,18 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library_rlib {
+    name: "libsmccc",
+    crate_name: "smccc",
+    srcs: ["src/lib.rs"],
+    prefer_rlib: true,
+    rustlibs: [
+        "libpsci",
+    ],
+    no_stdlibs: true,
+    stdlibs: [
+        "libcore.rust_sysroot",
+    ],
+    apex_available: ["com.android.virt"],
+}
diff --git a/libs/smccc/src/lib.rs b/libs/smccc/src/lib.rs
new file mode 100644
index 0000000..2cd31dc
--- /dev/null
+++ b/libs/smccc/src/lib.rs
@@ -0,0 +1,22 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Structs and functions for making SMCCC calls following the SMC Calling
+//! Convention version 1.4.
+
+#![no_std]
+
+mod smccc;
+
+pub use smccc::{checked_hvc64, checked_hvc64_expect_zero, hvc64, Error, Result};
diff --git a/pvmfw/src/smccc.rs b/libs/smccc/src/smccc.rs
similarity index 66%
rename from pvmfw/src/smccc.rs
rename to libs/smccc/src/smccc.rs
index ccf2680..c0070e0 100644
--- a/pvmfw/src/smccc.rs
+++ b/libs/smccc/src/smccc.rs
@@ -12,41 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+//! Structs and functions for making SMCCC calls.
+
 use core::{fmt, result};
-
-// TODO(b/245889995): use psci-0.1.1 crate
-#[inline(always)]
-pub fn hvc64(function: u32, args: [u64; 17]) -> [u64; 18] {
-    #[cfg(target_arch = "aarch64")]
-    unsafe {
-        let mut ret = [0; 18];
-
-        core::arch::asm!(
-            "hvc #0",
-            inout("x0") function as u64 => ret[0],
-            inout("x1") args[0] => ret[1],
-            inout("x2") args[1] => ret[2],
-            inout("x3") args[2] => ret[3],
-            inout("x4") args[3] => ret[4],
-            inout("x5") args[4] => ret[5],
-            inout("x6") args[5] => ret[6],
-            inout("x7") args[6] => ret[7],
-            inout("x8") args[7] => ret[8],
-            inout("x9") args[8] => ret[9],
-            inout("x10") args[9] => ret[10],
-            inout("x11") args[10] => ret[11],
-            inout("x12") args[11] => ret[12],
-            inout("x13") args[12] => ret[13],
-            inout("x14") args[13] => ret[14],
-            inout("x15") args[14] => ret[15],
-            inout("x16") args[15] => ret[16],
-            inout("x17") args[16] => ret[17],
-            options(nomem, nostack)
-        );
-
-        ret
-    }
-}
+// Ideally, smccc shouldn't depend on psci. Smccc isn't split as a separate
+// upstream crate currently mostly for maintenance consideration.
+// See b/245889995 for more context.
+pub use psci::smccc::hvc64;
 
 /// Standard SMCCC error values as described in DEN 0028E.
 #[derive(Debug, Clone)]
@@ -75,8 +47,11 @@
     }
 }
 
+/// Result type with smccc::Error.
 pub type Result<T> = result::Result<T, Error>;
 
+/// Makes a checked HVC64 call to the hypervisor, following the SMC Calling Convention version 1.4.
+/// Returns Ok only when the return code is 0.
 pub fn checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()> {
     match checked_hvc64(function, args)? {
         0 => Ok(()),
@@ -84,6 +59,8 @@
     }
 }
 
+/// Makes a checked HVC64 call to the hypervisor, following the SMC Calling Convention version 1.4.
+/// Returns Ok with the return code only when the return code >= 0.
 pub fn checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64> {
     match hvc64(function, args)[0] as i64 {
         ret if ret >= 0 => Ok(ret as u64),
diff --git a/microdroid/initrd/Android.bp b/microdroid/initrd/Android.bp
index ff6314b..22a06e1 100644
--- a/microdroid/initrd/Android.bp
+++ b/microdroid/initrd/Android.bp
@@ -107,7 +107,7 @@
 prebuilt_etc {
     name: "microdroid_initrd_debuggable",
     // We don't have ramdisk for architectures other than x86_64 & arm64
-    src: "empty_file",
+    src: ":empty_file",
     arch: {
         x86_64: {
             src: ":microdroid_initrd_debuggable_x86_64",
@@ -122,7 +122,7 @@
 prebuilt_etc {
     name: "microdroid_initrd_normal",
     // We don't have ramdisk for architectures other than x86_64 & arm64
-    src: "empty_file",
+    src: ":empty_file",
     arch: {
         x86_64: {
             src: ":microdroid_initrd_normal_x86_64",
diff --git a/microdroid/initrd/empty_file b/microdroid/initrd/empty_file
deleted file mode 100644
index e69de29..0000000
--- a/microdroid/initrd/empty_file
+++ /dev/null
diff --git a/microdroid_manager/microdroid_manager.rc b/microdroid_manager/microdroid_manager.rc
index 97d14b5..e257547 100644
--- a/microdroid_manager/microdroid_manager.rc
+++ b/microdroid_manager/microdroid_manager.rc
@@ -11,4 +11,5 @@
     # CAP_SETCAP is required to allow microdroid_manager to drop capabilities
     #   before executing the payload
     capabilities AUDIT_CONTROL SYS_ADMIN SYS_BOOT SETPCAP
+    user root
     socket vm_payload_service stream 0666 system system
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 6900ea5..b16a1e1 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -279,12 +279,24 @@
     pub apex_data: Vec<ApexData>,
 }
 
+impl MicrodroidData {
+    pub fn extra_apk_root_hash_eq(&self, i: usize, root_hash: &[u8]) -> bool {
+        self.extra_apks_data.get(i).map_or(false, |apk| apk.root_hash_eq(root_hash))
+    }
+}
+
 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
 pub struct ApkData {
     pub root_hash: Box<RootHash>,
     pub pubkey: Box<[u8]>,
 }
 
+impl ApkData {
+    pub fn root_hash_eq(&self, root_hash: &[u8]) -> bool {
+        self.root_hash.as_ref() == root_hash
+    }
+}
+
 pub type RootHash = [u8];
 
 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 8732be1..c78b20f 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -424,13 +424,12 @@
         .as_ref()
         .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
 
-    if config.extra_apks.len() != verified_data.extra_apks_data.len() {
-        return Err(anyhow!(
-            "config expects {} extra apks, but found {}",
-            config.extra_apks.len(),
-            verified_data.extra_apks_data.len()
-        ));
-    }
+    ensure!(
+        config.extra_apks.len() == verified_data.extra_apks_data.len(),
+        "config expects {} extra apks, but found {}",
+        config.extra_apks.len(),
+        verified_data.extra_apks_data.len()
+    );
     mount_extra_apks(&config, &mut zipfuse)?;
 
     // Wait until apex config is done. (e.g. linker configuration for apexes)
@@ -567,9 +566,9 @@
     let start_time = SystemTime::now();
 
     // Verify main APK
-    let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
     let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
-    let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
+    let root_hash_trustful =
+        saved_data.map(|d| d.apk_data.root_hash_eq(root_hash_from_idsig.as_ref())).unwrap_or(false);
 
     // If root_hash can be trusted, pass it to apkdmverity so that it uses the passed root_hash
     // instead of the value read from the idsig file.
@@ -597,42 +596,36 @@
         sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
     let extra_idsigs =
         sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
-    if extra_apks.len() != extra_idsigs.len() {
-        return Err(anyhow!(
-            "Extra apks/idsigs mismatch: {} apks but {} idsigs",
-            extra_apks.len(),
-            extra_idsigs.len()
-        ));
-    }
-    let extra_apks_count = extra_apks.len();
+    ensure!(
+        extra_apks.len() == extra_idsigs.len(),
+        "Extra apks/idsigs mismatch: {} apks but {} idsigs",
+        extra_apks.len(),
+        extra_idsigs.len()
+    );
 
-    let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
+    let extra_root_hashes_from_idsig: Vec<_> = extra_idsigs
         .iter()
-        .enumerate()
-        .map(|(i, extra_idsig)| {
-            (
-                format!("extra-apk-{}", i),
-                get_apk_root_hash_from_idsig(extra_idsig)
-                    .expect("Can't find root hash from extra idsig"),
-            )
-        })
-        .unzip();
-
-    let saved_extra_root_hashes: Vec<_> = saved_data
-        .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
-        .unwrap_or_else(Vec::new);
-    let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
-        .iter()
-        .enumerate()
-        .map(|(i, root_hash_from_idsig)| {
-            saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
+        .map(|idsig| {
+            get_apk_root_hash_from_idsig(idsig).expect("Can't find root hash from extra idsig")
         })
         .collect();
 
-    for i in 0..extra_apks_count {
+    let extra_root_hashes_trustful: Vec<_> = if let Some(data) = saved_data {
+        extra_root_hashes_from_idsig
+            .iter()
+            .enumerate()
+            .map(|(i, root_hash)| data.extra_apk_root_hash_eq(i, root_hash))
+            .collect()
+    } else {
+        vec![false; extra_root_hashes_from_idsig.len()]
+    };
+    let extra_apk_names: Vec<_> =
+        (0..extra_apks.len()).map(|i| format!("extra-apk-{}", i)).collect();
+
+    for (i, extra_apk) in extra_apks.iter().enumerate() {
         apkdmverity_arguments.push({
             ApkDmverityArgument {
-                apk: extra_apks[i].to_str().unwrap(),
+                apk: extra_apk.to_str().unwrap(),
                 idsig: extra_idsigs[i].to_str().unwrap(),
                 name: &extra_apk_names[i],
                 saved_root_hash: if extra_root_hashes_trustful[i] {
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 0d845f9..a446c90 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -23,6 +23,7 @@
         "libpvmfw_avb_nostd",
         "libpvmfw_embedded_key",
         "libpvmfw_fdt_template",
+        "libsmccc",
         "libstatic_assertions",
         "libtinyvec_nostd",
         "libuuid_nostd",
@@ -32,6 +33,13 @@
     ],
 }
 
+// Generates an empty file.
+genrule {
+    name: "empty_file",
+    out: ["empty_file"],
+    cmd: "touch $(out)",
+}
+
 cc_binary {
     name: "pvmfw",
     defaults: ["vmbase_elf_defaults"],
@@ -81,7 +89,7 @@
             src: ":pvmfw_bin",
         },
     },
-    src: "empty_file",
+    src: ":empty_file",
     installable: false,
 }
 
diff --git a/pvmfw/empty_file b/pvmfw/empty_file
deleted file mode 100644
index e69de29..0000000
--- a/pvmfw/empty_file
+++ /dev/null
diff --git a/pvmfw/src/debug_policy.rs b/pvmfw/src/debug_policy.rs
deleted file mode 100644
index bbf7e04..0000000
--- a/pvmfw/src/debug_policy.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2023, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Support for the debug policy overlay in pvmfw
-
-use core::fmt;
-use libfdt::FdtError;
-
-#[derive(Debug, Clone)]
-pub enum DebugPolicyError {
-    /// The provided baseline FDT was invalid or malformed, so cannot access certain node/prop
-    Fdt(&'static str, FdtError),
-    /// The provided debug policy FDT was invalid or malformed.
-    DebugPolicyFdt(&'static str, FdtError),
-    /// The overlaid result FDT is invalid or malformed, and may be corrupted.
-    OverlaidFdt(&'static str, FdtError),
-}
-
-impl fmt::Display for DebugPolicyError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Self::Fdt(s, e) => write!(f, "Invalid baseline FDT. {s}: {e}"),
-            Self::DebugPolicyFdt(s, e) => write!(f, "Invalid overlay FDT. {s}: {e}"),
-            Self::OverlaidFdt(s, e) => write!(f, "Invalid overlaid FDT. {s}: {e}"),
-        }
-    }
-}
-
-/// Applies the debug policy device tree overlay to the pVM DT.
-///
-/// # Safety
-///
-/// When an error is returned by this function, the input `Fdt` should be
-/// discarded as it may have have been partially corrupted during the overlay
-/// application process.
-unsafe fn apply_debug_policy(
-    fdt: &mut libfdt::Fdt,
-    debug_policy: &mut [u8],
-) -> Result<(), DebugPolicyError> {
-    let overlay = libfdt::Fdt::from_mut_slice(debug_policy)
-        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to load debug policy overlay", e))?;
-
-    fdt.unpack().map_err(|e| DebugPolicyError::Fdt("Failed to unpack", e))?;
-
-    let fdt = fdt
-        .apply_overlay(overlay)
-        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to apply overlay", e))?;
-
-    fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to re-pack", e))
-}
-
-/// Handles debug policies.
-///
-/// # Safety
-///
-/// This may corrupt the input `Fdt` when overlaying debug policy or applying
-/// ramdump configuration.
-pub unsafe fn handle_debug_policy(
-    fdt: &mut libfdt::Fdt,
-    debug_policy: Option<&mut [u8]>,
-) -> Result<(), DebugPolicyError> {
-    if let Some(dp) = debug_policy {
-        apply_debug_policy(fdt, dp)?;
-    }
-
-    Ok(())
-}
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index ffbc4a8..00f0e9b 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -16,7 +16,6 @@
 
 use crate::config;
 use crate::crypto;
-use crate::debug_policy::{handle_debug_policy, DebugPolicyError};
 use crate::fdt;
 use crate::heap;
 use crate::helpers;
@@ -54,16 +53,6 @@
     SecretDerivationError,
 }
 
-impl From<DebugPolicyError> for RebootReason {
-    fn from(error: DebugPolicyError) -> Self {
-        match error {
-            DebugPolicyError::Fdt(_, _) => RebootReason::InvalidFdt,
-            DebugPolicyError::DebugPolicyFdt(_, _) => RebootReason::InvalidConfig,
-            DebugPolicyError::OverlaidFdt(_, _) => RebootReason::InternalError,
-        }
-    }
-}
-
 main!(start);
 
 /// Entry point for pVM firmware.
@@ -237,19 +226,11 @@
     })?;
 
     // This wrapper allows main() to be blissfully ignorant of platform details.
-    crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, &mut memory)?;
+    crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy, &mut memory)?;
 
     helpers::flushed_zeroize(bcc_slice);
     helpers::flush(slices.fdt.as_slice());
 
-    // SAFETY - As we `?` the result, there is no risk of using a bad `slices.fdt`.
-    unsafe {
-        handle_debug_policy(slices.fdt, debug_policy).map_err(|e| {
-            error!("Unexpected error when handling debug policy: {e:?}");
-            RebootReason::from(e)
-        })?;
-    }
-
     info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
     memory.mmio_unmap_all().map_err(|e| {
         error!("Failed to unshare MMIO ranges: {e}");
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 7d88455..d15eaba 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -22,6 +22,7 @@
 use crate::memory::MAX_ADDR;
 use crate::RebootReason;
 use alloc::ffi::CString;
+use alloc::vec::Vec;
 use core::cmp::max;
 use core::cmp::min;
 use core::ffi::CStr;
@@ -36,6 +37,7 @@
 use libfdt::FdtNode;
 use log::debug;
 use log::error;
+use log::info;
 use tinyvec::ArrayVec;
 
 /// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
@@ -672,6 +674,7 @@
     bcc: &[u8],
     new_instance: bool,
     strict_boot: bool,
+    debug_policy: Option<&mut [u8]>,
 ) -> libfdt::Result<()> {
     fdt.unpack()?;
 
@@ -680,6 +683,13 @@
     set_or_clear_chosen_flag(fdt, cstr!("avf,strict-boot"), strict_boot)?;
     set_or_clear_chosen_flag(fdt, cstr!("avf,new-instance"), new_instance)?;
 
+    if let Some(debug_policy) = debug_policy {
+        apply_debug_policy(fdt, debug_policy)?;
+        info!("Debug policy applied.");
+    } else {
+        info!("No debug policy found.");
+    }
+
     fdt.pack()?;
 
     Ok(())
@@ -712,3 +722,26 @@
 
     Ok(())
 }
+
+fn apply_debug_policy(fdt: &mut Fdt, debug_policy: &mut [u8]) -> libfdt::Result<()> {
+    let backup_fdt = Vec::from(fdt.as_slice());
+
+    let overlay = match Fdt::from_mut_slice(debug_policy) {
+        Ok(overlay) => overlay,
+        Err(e) => {
+            info!("Corrupted debug policy found: {e}. Not applying.");
+            return Ok(());
+        }
+    };
+    let backup_overlay = Vec::from(overlay.as_slice());
+
+    // SAFETY - on failure, the corrupted fdts are discarded and are restored using the backups.
+    if let Err(e) = unsafe { fdt.apply_overlay(overlay) } {
+        error!("Failed to apply debug policy: {e}. Recovering...");
+        fdt.copy_from_slice(backup_fdt.as_slice())?;
+        overlay.copy_from_slice(backup_overlay.as_slice())?;
+        // A successful restoration is considered success because an invalid debug policy
+        // shouldn't DOS the pvmfw
+    }
+    Ok(())
+}
diff --git a/pvmfw/src/hvc.rs b/pvmfw/src/hvc.rs
index 08edd86..f44e26e 100644
--- a/pvmfw/src/hvc.rs
+++ b/pvmfw/src/hvc.rs
@@ -16,8 +16,8 @@
 
 pub mod trng;
 
-use crate::smccc::{self, checked_hvc64, checked_hvc64_expect_zero};
 use log::info;
+use smccc::{self, checked_hvc64, checked_hvc64_expect_zero};
 
 const ARM_SMCCC_TRNG_VERSION: u32 = 0x8400_0050;
 #[allow(dead_code)]
@@ -78,7 +78,8 @@
     let mut args = [0u64; 17];
     args[0] = ipa;
 
-    // TODO(b/253586500): pKVM currently returns a i32 instead of a i64.
+    // TODO(b/277859415): pKVM returns a i32 instead of a i64 in T.
+    // Drop this hack once T reaches EoL.
     let is_i32_error_code = |n| u32::try_from(n).ok().filter(|v| (*v as i32) < 0).is_some();
     match checked_hvc64_expect_zero(VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID, args) {
         Err(smccc::Error::Unexpected(e)) if is_i32_error_code(e) => {
@@ -98,7 +99,8 @@
     let mut args = [0u64; 17];
     args[0] = ipa;
 
-    // TODO(b/251426790): pKVM currently returns NOT_SUPPORTED for SUCCESS.
+    // TODO(b/277860860): pKVM returns NOT_SUPPORTED for SUCCESS in T.
+    // Drop this hack once T reaches EoL.
     match checked_hvc64_expect_zero(VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID, args) {
         Err(smccc::Error::NotSupported) | Ok(_) => Ok(()),
         x => x,
diff --git a/pvmfw/src/hvc/trng.rs b/pvmfw/src/hvc/trng.rs
index d347693..05ecc6b 100644
--- a/pvmfw/src/hvc/trng.rs
+++ b/pvmfw/src/hvc/trng.rs
@@ -12,7 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use crate::smccc;
 use core::fmt;
 use core::result;
 
diff --git a/pvmfw/src/hypervisor.rs b/pvmfw/src/hypervisor.rs
index e06d809..22609c5 100644
--- a/pvmfw/src/hypervisor.rs
+++ b/pvmfw/src/hypervisor.rs
@@ -15,7 +15,6 @@
 //! Wrappers around hypervisor back-ends.
 
 use crate::hvc;
-use crate::smccc;
 
 pub fn hyp_meminfo() -> smccc::Result<u64> {
     hvc::kvm_hyp_meminfo()
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 00ff61f..fd6054f 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -21,7 +21,6 @@
 
 mod config;
 mod crypto;
-mod debug_policy;
 mod dice;
 mod entry;
 mod exceptions;
@@ -36,7 +35,6 @@
 mod mmio_guard;
 mod mmu;
 mod rand;
-mod smccc;
 mod virtio;
 
 use alloc::boxed::Box;
@@ -65,6 +63,7 @@
     signed_kernel: &[u8],
     ramdisk: Option<&[u8]>,
     current_bcc_handover: &[u8],
+    debug_policy: Option<&mut [u8]>,
     memory: &mut MemoryTracker,
 ) -> Result<(), RebootReason> {
     info!("pVM firmware");
@@ -122,7 +121,7 @@
     flush(next_bcc);
 
     let strict_boot = true;
-    modify_for_next_stage(fdt, next_bcc, new_instance, strict_boot).map_err(|e| {
+    modify_for_next_stage(fdt, next_bcc, new_instance, strict_boot, debug_policy).map_err(|e| {
         error!("Failed to configure device tree: {e}");
         RebootReason::InternalError
     })?;
diff --git a/pvmfw/src/memory.rs b/pvmfw/src/memory.rs
index b223f82..d26a4ba 100644
--- a/pvmfw/src/memory.rs
+++ b/pvmfw/src/memory.rs
@@ -20,7 +20,6 @@
 use crate::hypervisor::{hyp_meminfo, mem_share, mem_unshare};
 use crate::mmio_guard;
 use crate::mmu;
-use crate::smccc;
 use alloc::alloc::alloc_zeroed;
 use alloc::alloc::dealloc;
 use alloc::alloc::handle_alloc_error;
diff --git a/pvmfw/src/mmio_guard.rs b/pvmfw/src/mmio_guard.rs
index dac26e0..95a1b7f 100644
--- a/pvmfw/src/mmio_guard.rs
+++ b/pvmfw/src/mmio_guard.rs
@@ -16,7 +16,6 @@
 
 use crate::helpers;
 use crate::hypervisor::{mmio_guard_enroll, mmio_guard_info, mmio_guard_map, mmio_guard_unmap};
-use crate::smccc;
 use core::{fmt, result};
 
 #[derive(Debug, Clone)]
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index c71a8ec..873cc38 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -38,6 +38,7 @@
         "compatibility-host-util",
         "cts-statsd-atom-host-test-utils",
         "microdroid_payload_metadata",
+        "MicrodroidTestPreparer", // Workaround for sandboxed test environment to install this
     ],
     per_testcase_directory: true,
     data: [
diff --git a/virtualizationmanager/src/atom.rs b/virtualizationmanager/src/atom.rs
index 02d46ec..d6eb141 100644
--- a/virtualizationmanager/src/atom.rs
+++ b/virtualizationmanager/src/atom.rs
@@ -93,6 +93,7 @@
 }
 
 /// Write the stats of VMCreation to statsd
+/// The function creates a separate thread which waits for statsd to start to push atom
 pub fn write_vm_creation_stats(
     config: &VirtualMachineConfig,
     is_protected: bool,
@@ -158,7 +159,7 @@
 }
 
 /// Write the stats of VM boot to statsd
-/// The function creates a separate thread which waits fro statsd to start to push atom
+/// The function creates a separate thread which waits for statsd to start to push atom
 pub fn write_vm_booted_stats(
     uid: i32,
     vm_identifier: &str,
@@ -182,8 +183,7 @@
 }
 
 /// Write the stats of VM exit to statsd
-/// The function creates a separate thread which waits fro statsd to start to push atom
-pub fn write_vm_exited_stats(
+pub fn write_vm_exited_stats_sync(
     uid: i32,
     vm_identifier: &str,
     reason: DeathReason,
@@ -207,9 +207,7 @@
     };
 
     info!("Writing VmExited atom into statsd.");
-    thread::spawn(move || {
-        GLOBAL_SERVICE.atomVmExited(&atom).unwrap_or_else(|e| {
-            warn!("Failed to write VmExited atom: {e}");
-        });
+    GLOBAL_SERVICE.atomVmExited(&atom).unwrap_or_else(|e| {
+        warn!("Failed to write VmExited atom: {e}");
     });
 }
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index a8cad94..60dd4cf 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -15,7 +15,7 @@
 //! Functions for running instances of `crosvm`.
 
 use crate::aidl::{remove_temporary_files, Cid, VirtualMachineCallbacks};
-use crate::atom::{get_num_cpus, write_vm_exited_stats};
+use crate::atom::{get_num_cpus, write_vm_exited_stats_sync};
 use crate::debug_config::DebugConfig;
 use anyhow::{anyhow, bail, Context, Error, Result};
 use command_fds::CommandFdExt;
@@ -381,7 +381,7 @@
         self.callbacks.callback_on_died(self.cid, death_reason);
 
         let vm_metric = self.vm_metric.lock().unwrap();
-        write_vm_exited_stats(
+        write_vm_exited_stats_sync(
             self.requester_uid as i32,
             &self.name,
             death_reason,