Merge "Specify SYS_ADMIN capability for authfs_service"
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 8cc8daf..ecaadf8 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -46,6 +46,7 @@
     use_avb: true,
     avb_private_key: ":microdroid_sign_key",
     avb_algorithm: "SHA256_RSA4096",
+    avb_hash_algorithm: "sha256",
     partition_name: "system",
     deps: [
         "init_second_stage",
@@ -90,7 +91,7 @@
 
         "libvm_payload", // used by payload to interact with microdroid manager
 
-        "prng_seeder",
+        "prng_seeder_microdroid",
     ] + microdroid_shell_and_utilities,
     multilib: {
         common: {
@@ -215,6 +216,7 @@
     },
     avb_private_key: ":microdroid_sign_key",
     avb_algorithm: "SHA256_RSA4096",
+    avb_hash_algorithm: "sha256",
     file_contexts: ":microdroid_vendor_file_contexts.gen",
     // For deterministic output, use fake_timestamp, hard-coded uuid
     fake_timestamp: "1611569676",
diff --git a/pvmfw/src/helpers.rs b/pvmfw/src/helpers.rs
index d1b828a..e8a20a8 100644
--- a/pvmfw/src/helpers.rs
+++ b/pvmfw/src/helpers.rs
@@ -45,6 +45,17 @@
     }
 }
 
+/// Aligns the given address to the given alignment, if it is a power of two.
+///
+/// Returns `None` if the alignment isn't a power of two.
+pub const fn align_down(addr: usize, alignment: usize) -> Option<usize> {
+    if !alignment.is_power_of_two() {
+        None
+    } else {
+        Some(unchecked_align_down(addr, alignment))
+    }
+}
+
 /// Computes the address of the 4KiB page containing a given address.
 pub const fn page_4kb_of(addr: usize) -> usize {
     unchecked_align_down(addr, SIZE_4KB)
diff --git a/pvmfw/src/hvc.rs b/pvmfw/src/hvc.rs
index 66f7977..dc99303 100644
--- a/pvmfw/src/hvc.rs
+++ b/pvmfw/src/hvc.rs
@@ -17,11 +17,41 @@
 use crate::smccc::{self, checked_hvc64, checked_hvc64_expect_zero};
 use log::info;
 
+const ARM_SMCCC_KVM_FUNC_HYP_MEMINFO: u32 = 0xc6000002;
+const ARM_SMCCC_KVM_FUNC_MEM_SHARE: u32 = 0xc6000003;
+const ARM_SMCCC_KVM_FUNC_MEM_UNSHARE: u32 = 0xc6000004;
 const VENDOR_HYP_KVM_MMIO_GUARD_INFO_FUNC_ID: u32 = 0xc6000005;
 const VENDOR_HYP_KVM_MMIO_GUARD_ENROLL_FUNC_ID: u32 = 0xc6000006;
 const VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID: u32 = 0xc6000007;
 const VENDOR_HYP_KVM_MMIO_GUARD_UNMAP_FUNC_ID: u32 = 0xc6000008;
 
+/// Queries the memory protection parameters for a protected virtual machine.
+///
+/// Returns the memory protection granule size in bytes.
+pub fn hyp_meminfo() -> smccc::Result<u64> {
+    let args = [0u64; 17];
+    checked_hvc64(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, args)
+}
+
+/// Shares a region of memory with the KVM host, granting it read, write and execute permissions.
+/// The size of the region is equal to the memory protection granule returned by [`hyp_meminfo`].
+pub fn mem_share(base_ipa: u64) -> smccc::Result<()> {
+    let mut args = [0u64; 17];
+    args[0] = base_ipa;
+
+    checked_hvc64_expect_zero(ARM_SMCCC_KVM_FUNC_MEM_SHARE, args)
+}
+
+/// Revokes access permission from the KVM host to a memory region previously shared with
+/// [`mem_share`]. The size of the region is equal to the memory protection granule returned by
+/// [`hyp_meminfo`].
+pub fn mem_unshare(base_ipa: u64) -> smccc::Result<()> {
+    let mut args = [0u64; 17];
+    args[0] = base_ipa;
+
+    checked_hvc64_expect_zero(ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, args)
+}
+
 pub fn mmio_guard_info() -> smccc::Result<u64> {
     let args = [0u64; 17];
 
diff --git a/pvmfw/src/memory.rs b/pvmfw/src/memory.rs
index 892089e..5e4874f 100644
--- a/pvmfw/src/memory.rs
+++ b/pvmfw/src/memory.rs
@@ -14,9 +14,11 @@
 
 //! Low-level allocation and tracking of main memory.
 
-use crate::helpers::{self, page_4kb_of, SIZE_4KB};
+use crate::helpers::{self, align_down, page_4kb_of, SIZE_4KB};
+use crate::hvc::{hyp_meminfo, mem_share, mem_unshare};
 use crate::mmio_guard;
 use crate::mmu;
+use crate::smccc;
 use core::cmp::max;
 use core::cmp::min;
 use core::fmt;
@@ -267,6 +269,36 @@
     }
 }
 
+/// Gives the KVM host read, write and execute permissions on the given memory range. If the range
+/// is not aligned with the memory protection granule then it will be extended on either end to
+/// align.
+#[allow(unused)]
+pub fn share_range(range: &MemoryRange) -> smccc::Result<()> {
+    let granule = hyp_meminfo()? as usize;
+    for base in (align_down(range.start, granule)
+        .expect("Memory protection granule was not a power of two")..range.end)
+        .step_by(granule)
+    {
+        mem_share(base as u64)?;
+    }
+    Ok(())
+}
+
+/// Removes permission from the KVM host to access the given memory range which was previously
+/// shared. If the range is not aligned with the memory protection granule then it will be extended
+/// on either end to align.
+#[allow(unused)]
+pub fn unshare_range(range: &MemoryRange) -> smccc::Result<()> {
+    let granule = hyp_meminfo()? as usize;
+    for base in (align_down(range.start, granule)
+        .expect("Memory protection granule was not a power of two")..range.end)
+        .step_by(granule)
+    {
+        mem_unshare(base as u64)?;
+    }
+    Ok(())
+}
+
 /// Returns an iterator which yields the base address of each 4 KiB page within the given range.
 fn page_iterator(range: &MemoryRange) -> impl Iterator<Item = usize> {
     (page_4kb_of(range.start)..range.end).step_by(SIZE_4KB)