Merge changes Ife13eb84,I22ae4bbb

* changes:
  pvmfw: Add swiotlb <reg> to platform.dts
  pvmfw: Accept either swiotlb DT reg or size/align
diff --git a/libs/avb/Android.bp b/libs/avb/Android.bp
index 7bfea3f..3a671e2 100644
--- a/libs/avb/Android.bp
+++ b/libs/avb/Android.bp
@@ -11,7 +11,9 @@
     source_stem: "bindings",
     bindgen_flags: [
         "--size_t-is-usize",
+        "--constified-enum-module AvbDescriptorTag",
         "--default-enum-style rust",
+        "--allowlist-type=AvbDescriptorTag",
         "--allowlist-function=.*",
         "--allowlist-var=AVB.*",
         "--use-core",
diff --git a/libs/devicemapper/src/loopdevice/sys.rs b/libs/devicemapper/src/loopdevice/sys.rs
index 98b5085..a35eaa9 100644
--- a/libs/devicemapper/src/loopdevice/sys.rs
+++ b/libs/devicemapper/src/loopdevice/sys.rs
@@ -61,6 +61,8 @@
 unsafe impl DataInit for loop_info64 {}
 
 bitflags! {
+    #[repr(transparent)]
+    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
     pub struct Flag: u32 {
         const LO_FLAGS_READ_ONLY = 1 << 0;
         const LO_FLAGS_AUTOCLEAR = 1 << 2;
diff --git a/libs/devicemapper/src/sys.rs b/libs/devicemapper/src/sys.rs
index e709bf0..3cecde3 100644
--- a/libs/devicemapper/src/sys.rs
+++ b/libs/devicemapper/src/sys.rs
@@ -72,6 +72,8 @@
 pub const DM_MAX_TYPE_NAME: usize = 16;
 
 bitflags! {
+    #[repr(transparent)]
+    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
     pub struct Flag: u32 {
         const DM_READONLY_FLAG = 1 << 0;
         const DM_SUSPEND_FLAG = 1 << 1;
diff --git a/libs/vbmeta/src/descriptor.rs b/libs/vbmeta/src/descriptor.rs
index 10484ff..caf1356 100644
--- a/libs/vbmeta/src/descriptor.rs
+++ b/libs/vbmeta/src/descriptor.rs
@@ -14,7 +14,8 @@
 
 use avb_bindgen::{
     avb_descriptor_foreach, avb_descriptor_validate_and_byteswap,
-    avb_hashtree_descriptor_validate_and_byteswap, AvbDescriptor, AvbHashtreeDescriptor,
+    avb_hashtree_descriptor_validate_and_byteswap, AvbDescriptor, AvbDescriptorTag,
+    AvbHashtreeDescriptor,
 };
 use std::ffi::c_void;
 use std::mem::{size_of, MaybeUninit};
@@ -22,13 +23,6 @@
 
 use super::VbMetaImageParseError;
 
-// TODO: import these with bindgen
-const AVB_DESCRIPTOR_TAG_PROPERTY: u64 = 0;
-const AVB_DESCRIPTOR_TAG_HASHTREE: u64 = 1;
-const AVB_DESCRIPTOR_TAG_HASH: u64 = 2;
-const AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: u64 = 3;
-const AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: u64 = 4;
-
 /// The descriptors from a VBMeta image.
 pub struct Descriptors<'a> {
     descriptors: Vec<Descriptor<'a>>,
@@ -72,12 +66,16 @@
             };
             // SAFETY: this cast gets a reference to the Vec passed as the user_data below.
             let descriptors = unsafe { &mut *(user_data as *mut Vec<Descriptor>) };
-            descriptors.push(match desc.tag {
-                AVB_DESCRIPTOR_TAG_PROPERTY => Descriptor::Property(data),
-                AVB_DESCRIPTOR_TAG_HASHTREE => Descriptor::Hashtree(data),
-                AVB_DESCRIPTOR_TAG_HASH => Descriptor::Hash(data),
-                AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE => Descriptor::KernelCmdline(data),
-                AVB_DESCRIPTOR_TAG_CHAIN_PARTITION => Descriptor::ChainPartition(data),
+            descriptors.push(match desc.tag.try_into() {
+                Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_PROPERTY) => Descriptor::Property(data),
+                Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASHTREE) => Descriptor::Hashtree(data),
+                Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASH) => Descriptor::Hash(data),
+                Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) => {
+                    Descriptor::KernelCmdline(data)
+                }
+                Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) => {
+                    Descriptor::ChainPartition(data)
+                }
                 _ => Descriptor::Unknown,
             });
             true
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 871db94..42033d6 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -147,10 +147,11 @@
 
 service ueventd /system/bin/ueventd
     user root
+    group root
     class core
     critical
     seclabel u:r:ueventd:s0
-    capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID MKNOD NET_ADMIN SETGID SETUID SYS_MODULE SYS_RAWIO
+    capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID MKNOD NET_ADMIN SETGID SETUID SYS_MODULE SYS_RAWIO SYS_ADMIN
 
 service console /system/bin/sh
     class core
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 0ae2203..c79605f 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -158,7 +158,7 @@
     ],
     out: ["lib.rs"],
     tools: ["dtc"],
-    cmd: "prebuilts/clang/host/linux-x86/clang-r487747/bin/clang " + // UGLY!!!
+    cmd: "prebuilts/clang/host/linux-x86/clang-r487747c/bin/clang " + // UGLY!!!
         "-E -P -x assembler-with-cpp -I external/arm-trusted-firmware/include " +
         "-o $(genDir)/preprocessed.dts $(location platform.dts) && " +
         "$(location dtc) -I dts -O dtb -o $(genDir)/compiled.dtbo $(genDir)/preprocessed.dts && " +
diff --git a/pvmfw/avb/src/descriptor.rs b/pvmfw/avb/src/descriptor.rs
deleted file mode 100644
index cd623ac..0000000
--- a/pvmfw/avb/src/descriptor.rs
+++ /dev/null
@@ -1,201 +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.
-
-//! Structs and functions relating to the descriptors.
-
-use crate::error::{AvbIOError, AvbSlotVerifyError};
-use crate::partition::PartitionName;
-use crate::utils::{self, is_not_null, to_nonnull, to_usize, usize_checked_add};
-use avb_bindgen::{
-    avb_descriptor_foreach, avb_hash_descriptor_validate_and_byteswap, AvbDescriptor,
-    AvbHashDescriptor, AvbVBMetaData, AVB_SHA256_DIGEST_SIZE,
-};
-use core::{
-    ffi::c_void,
-    mem::{size_of, MaybeUninit},
-    ops::Range,
-    slice,
-};
-use tinyvec::ArrayVec;
-
-/// Digest type for kernel and initrd.
-pub type Digest = [u8; AVB_SHA256_DIGEST_SIZE as usize];
-
-/// `HashDescriptors` can have maximum one `HashDescriptor` per known partition.
-#[derive(Default)]
-pub(crate) struct HashDescriptors(
-    ArrayVec<[HashDescriptor; PartitionName::NUM_OF_KNOWN_PARTITIONS]>,
-);
-
-impl HashDescriptors {
-    /// Builds `HashDescriptors` from `AvbVBMetaData`.
-    /// Returns an error if the given `AvbVBMetaData` contains non-hash descriptor, hash
-    /// descriptor of unknown `PartitionName` or duplicated hash descriptors.
-    ///
-    /// # Safety
-    ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    /// * `vbmeta.vbmeta_data` must be non-null and points to a valid VBMeta.
-    /// * `vbmeta.vbmeta_data` must be valid for reading `vbmeta.vbmeta_size` bytes.
-    pub(crate) unsafe fn from_vbmeta(vbmeta: AvbVBMetaData) -> Result<Self, AvbSlotVerifyError> {
-        is_not_null(vbmeta.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
-        let mut descriptors = Self::default();
-        // SAFETY: It is safe as the raw pointer `vbmeta.vbmeta_data` is a non-null pointer and
-        // points to a valid VBMeta structure.
-        if !unsafe {
-            avb_descriptor_foreach(
-                vbmeta.vbmeta_data,
-                vbmeta.vbmeta_size,
-                Some(check_and_save_descriptor),
-                &mut descriptors as *mut _ as *mut c_void,
-            )
-        } {
-            return Err(AvbSlotVerifyError::InvalidMetadata);
-        }
-        Ok(descriptors)
-    }
-
-    fn push(&mut self, descriptor: HashDescriptor) -> utils::Result<()> {
-        if self.0.iter().any(|d| d.partition_name_eq(&descriptor)) {
-            return Err(AvbIOError::Io);
-        }
-        self.0.push(descriptor);
-        Ok(())
-    }
-
-    pub(crate) fn len(&self) -> usize {
-        self.0.len()
-    }
-
-    /// Finds the `HashDescriptor` for the given `PartitionName`.
-    /// Throws an error if no corresponding descriptor found.
-    pub(crate) fn find(
-        &self,
-        partition_name: PartitionName,
-    ) -> Result<&HashDescriptor, AvbSlotVerifyError> {
-        self.0
-            .iter()
-            .find(|d| d.partition_name == partition_name)
-            .ok_or(AvbSlotVerifyError::InvalidMetadata)
-    }
-}
-
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-/// * The `descriptor` pointer must be non-null and points to a valid `AvbDescriptor` struct.
-/// * The `user_data` pointer must be non-null and points to a valid `HashDescriptors` struct.
-unsafe extern "C" fn check_and_save_descriptor(
-    descriptor: *const AvbDescriptor,
-    user_data: *mut c_void,
-) -> bool {
-    // SAFETY: It is safe because the caller must ensure that the `descriptor` pointer and
-    // the `user_data` are non-null and valid.
-    unsafe { try_check_and_save_descriptor(descriptor, user_data).is_ok() }
-}
-
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-/// * The `descriptor` pointer must be non-null and points to a valid `AvbDescriptor` struct.
-/// * The `user_data` pointer must be non-null and points to a valid `HashDescriptors` struct.
-unsafe fn try_check_and_save_descriptor(
-    descriptor: *const AvbDescriptor,
-    user_data: *mut c_void,
-) -> utils::Result<()> {
-    is_not_null(descriptor)?;
-    // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null pointer
-    // pointing to a valid struct.
-    let desc = unsafe { AvbHashDescriptorWrap::from_descriptor_ptr(descriptor)? };
-    // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null pointer
-    // pointing to a valid struct.
-    let data = unsafe { slice::from_raw_parts(descriptor as *const u8, desc.len()?) };
-    let mut descriptors = to_nonnull(user_data as *mut HashDescriptors)?;
-    // SAFETY: It is safe because the caller ensures that `user_data` is a non-null pointer
-    // pointing to a valid struct.
-    let descriptors = unsafe { descriptors.as_mut() };
-    descriptors.push(HashDescriptor::new(&desc, data)?)
-}
-
-#[derive(Default)]
-pub(crate) struct HashDescriptor {
-    partition_name: PartitionName,
-    pub(crate) digest: Digest,
-}
-
-impl HashDescriptor {
-    fn new(desc: &AvbHashDescriptorWrap, data: &[u8]) -> utils::Result<Self> {
-        let partition_name = data
-            .get(desc.partition_name_range()?)
-            .ok_or(AvbIOError::RangeOutsidePartition)?
-            .try_into()?;
-        let partition_digest =
-            data.get(desc.digest_range()?).ok_or(AvbIOError::RangeOutsidePartition)?;
-        let mut digest = [0u8; size_of::<Digest>()];
-        digest.copy_from_slice(partition_digest);
-        Ok(Self { partition_name, digest })
-    }
-
-    fn partition_name_eq(&self, other: &HashDescriptor) -> bool {
-        self.partition_name == other.partition_name
-    }
-}
-
-/// `AvbHashDescriptor` contains the metadata for the given descriptor.
-struct AvbHashDescriptorWrap(AvbHashDescriptor);
-
-impl AvbHashDescriptorWrap {
-    /// # Safety
-    ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    /// * The `descriptor` pointer must be non-null and point to a valid `AvbDescriptor`.
-    unsafe fn from_descriptor_ptr(descriptor: *const AvbDescriptor) -> utils::Result<Self> {
-        is_not_null(descriptor)?;
-        // SAFETY: It is safe as the raw pointer `descriptor` is non-null and points to
-        // a valid `AvbDescriptor`.
-        let desc = unsafe {
-            let mut desc = MaybeUninit::uninit();
-            if !avb_hash_descriptor_validate_and_byteswap(
-                descriptor as *const AvbHashDescriptor,
-                desc.as_mut_ptr(),
-            ) {
-                return Err(AvbIOError::Io);
-            }
-            desc.assume_init()
-        };
-        Ok(Self(desc))
-    }
-
-    fn len(&self) -> utils::Result<usize> {
-        usize_checked_add(
-            size_of::<AvbDescriptor>(),
-            to_usize(self.0.parent_descriptor.num_bytes_following)?,
-        )
-    }
-
-    fn partition_name_end(&self) -> utils::Result<usize> {
-        usize_checked_add(size_of::<AvbHashDescriptor>(), to_usize(self.0.partition_name_len)?)
-    }
-
-    fn partition_name_range(&self) -> utils::Result<Range<usize>> {
-        let start = size_of::<AvbHashDescriptor>();
-        Ok(start..(self.partition_name_end()?))
-    }
-
-    fn digest_range(&self) -> utils::Result<Range<usize>> {
-        let start = usize_checked_add(self.partition_name_end()?, to_usize(self.0.salt_len)?)?;
-        let end = usize_checked_add(start, to_usize(self.0.digest_len)?)?;
-        Ok(start..end)
-    }
-}
diff --git a/pvmfw/avb/src/descriptor/descriptors.rs b/pvmfw/avb/src/descriptor/descriptors.rs
new file mode 100644
index 0000000..6eaf643
--- /dev/null
+++ b/pvmfw/avb/src/descriptor/descriptors.rs
@@ -0,0 +1,148 @@
+// 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 relating to the descriptor data.
+
+use crate::error::AvbIOError;
+use crate::partition::PartitionName;
+use crate::utils::{self, is_not_null, to_usize, usize_checked_add};
+use crate::Digest;
+use avb_bindgen::{
+    avb_descriptor_validate_and_byteswap, avb_hash_descriptor_validate_and_byteswap, AvbDescriptor,
+    AvbDescriptorTag, AvbHashDescriptor,
+};
+use core::{
+    mem::{size_of, MaybeUninit},
+    ops::Range,
+    slice,
+};
+
+pub(super) enum Descriptor<'a> {
+    Hash(HashDescriptor<'a>),
+}
+
+impl<'a> Descriptor<'a> {
+    /// # Safety
+    ///
+    /// Behavior is undefined if any of the following conditions are violated:
+    /// * The `descriptor` pointer must be non-null and point to a valid `AvbDescriptor`.
+    pub(super) unsafe fn from_descriptor_ptr(
+        descriptor: *const AvbDescriptor,
+    ) -> utils::Result<Self> {
+        // SAFETY: It is safe as the raw pointer `descriptor` is non-null and points to
+        // a valid `AvbDescriptor`.
+        let avb_descriptor =
+            unsafe { get_valid_descriptor(descriptor, avb_descriptor_validate_and_byteswap)? };
+        let len = usize_checked_add(
+            size_of::<AvbDescriptor>(),
+            to_usize(avb_descriptor.num_bytes_following)?,
+        )?;
+        // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null pointer
+        // pointing to a valid struct.
+        let data = unsafe { slice::from_raw_parts(descriptor as *const u8, len) };
+        match avb_descriptor.tag.try_into() {
+            Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASH) => {
+                // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null
+                // pointer pointing to a valid struct.
+                let h = unsafe { HashDescriptorHeader::from_descriptor_ptr(descriptor)? };
+                Ok(Self::Hash(HashDescriptor::new(&h, data)?))
+            }
+            _ => Err(AvbIOError::NoSuchValue),
+        }
+    }
+}
+
+struct HashDescriptorHeader(AvbHashDescriptor);
+
+impl HashDescriptorHeader {
+    /// # Safety
+    ///
+    /// Behavior is undefined if any of the following conditions are violated:
+    /// * The `descriptor` pointer must be non-null and point to a valid `AvbDescriptor`.
+    unsafe fn from_descriptor_ptr(descriptor: *const AvbDescriptor) -> utils::Result<Self> {
+        // SAFETY: It is safe as the raw pointer `descriptor` is non-null and points to
+        // a valid `AvbDescriptor`.
+        unsafe {
+            get_valid_descriptor(
+                descriptor as *const AvbHashDescriptor,
+                avb_hash_descriptor_validate_and_byteswap,
+            )
+            .map(Self)
+        }
+    }
+
+    fn partition_name_end(&self) -> utils::Result<usize> {
+        usize_checked_add(size_of::<AvbHashDescriptor>(), to_usize(self.0.partition_name_len)?)
+    }
+
+    fn partition_name_range(&self) -> utils::Result<Range<usize>> {
+        let start = size_of::<AvbHashDescriptor>();
+        Ok(start..(self.partition_name_end()?))
+    }
+
+    fn digest_range(&self) -> utils::Result<Range<usize>> {
+        let start = usize_checked_add(self.partition_name_end()?, to_usize(self.0.salt_len)?)?;
+        let end = usize_checked_add(start, to_usize(self.0.digest_len)?)?;
+        Ok(start..end)
+    }
+}
+
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+/// * The `descriptor_ptr` pointer must be non-null and point to a valid `AvbDescriptor`.
+unsafe fn get_valid_descriptor<T>(
+    descriptor_ptr: *const T,
+    descriptor_validate_and_byteswap: unsafe extern "C" fn(src: *const T, dest: *mut T) -> bool,
+) -> utils::Result<T> {
+    is_not_null(descriptor_ptr)?;
+    // SAFETY: It is safe because the caller ensures that `descriptor_ptr` is a non-null pointer
+    // pointing to a valid struct.
+    let descriptor = unsafe {
+        let mut desc = MaybeUninit::uninit();
+        if !descriptor_validate_and_byteswap(descriptor_ptr, desc.as_mut_ptr()) {
+            return Err(AvbIOError::Io);
+        }
+        desc.assume_init()
+    };
+    Ok(descriptor)
+}
+
+pub(crate) struct HashDescriptor<'a> {
+    pub(crate) partition_name: PartitionName,
+    pub(crate) digest: &'a Digest,
+}
+
+impl<'a> Default for HashDescriptor<'a> {
+    fn default() -> Self {
+        Self { partition_name: Default::default(), digest: &Self::EMPTY_DIGEST }
+    }
+}
+
+impl<'a> HashDescriptor<'a> {
+    const EMPTY_DIGEST: Digest = [0u8; 32];
+
+    fn new(desc: &HashDescriptorHeader, data: &'a [u8]) -> utils::Result<Self> {
+        let partition_name = data
+            .get(desc.partition_name_range()?)
+            .ok_or(AvbIOError::RangeOutsidePartition)?
+            .try_into()?;
+        let digest = data
+            .get(desc.digest_range()?)
+            .ok_or(AvbIOError::RangeOutsidePartition)?
+            .try_into()
+            .map_err(|_| AvbIOError::InvalidValueSize)?;
+        Ok(Self { partition_name, digest })
+    }
+}
diff --git a/pvmfw/avb/src/descriptor/mod.rs b/pvmfw/avb/src/descriptor/mod.rs
new file mode 100644
index 0000000..3c169bf
--- /dev/null
+++ b/pvmfw/avb/src/descriptor/mod.rs
@@ -0,0 +1,129 @@
+// 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 relating to the descriptors.
+
+mod descriptors;
+
+pub(crate) use self::descriptors::HashDescriptor;
+
+use self::descriptors::Descriptor;
+use crate::error::{AvbIOError, AvbSlotVerifyError};
+use crate::partition::PartitionName;
+use crate::utils::{self, is_not_null, to_nonnull};
+use avb_bindgen::{avb_descriptor_foreach, AvbDescriptor, AvbVBMetaData, AVB_SHA256_DIGEST_SIZE};
+use core::ffi::c_void;
+use tinyvec::ArrayVec;
+
+/// Digest type for kernel and initrd.
+pub type Digest = [u8; AVB_SHA256_DIGEST_SIZE as usize];
+
+/// `Descriptors` can have at most one `HashDescriptor` per known partition and at most one
+/// `PropertyDescriptor`.
+#[derive(Default)]
+pub(crate) struct Descriptors<'a> {
+    hash_descriptors: ArrayVec<[HashDescriptor<'a>; PartitionName::NUM_OF_KNOWN_PARTITIONS]>,
+}
+
+impl<'a> Descriptors<'a> {
+    /// Builds `Descriptors` from `AvbVBMetaData`.
+    /// Returns an error if the given `AvbVBMetaData` contains non-hash descriptor, hash
+    /// descriptor of unknown `PartitionName` or duplicated hash descriptors.
+    ///
+    /// # Safety
+    ///
+    /// Behavior is undefined if any of the following conditions are violated:
+    /// * `vbmeta.vbmeta_data` must be non-null and points to a valid VBMeta.
+    /// * `vbmeta.vbmeta_data` must be valid for reading `vbmeta.vbmeta_size` bytes.
+    pub(crate) unsafe fn from_vbmeta(vbmeta: AvbVBMetaData) -> Result<Self, AvbSlotVerifyError> {
+        is_not_null(vbmeta.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
+        let mut descriptors = Self::default();
+        // SAFETY: It is safe as the raw pointer `vbmeta.vbmeta_data` is a non-null pointer and
+        // points to a valid VBMeta structure.
+        if !unsafe {
+            avb_descriptor_foreach(
+                vbmeta.vbmeta_data,
+                vbmeta.vbmeta_size,
+                Some(check_and_save_descriptor),
+                &mut descriptors as *mut _ as *mut c_void,
+            )
+        } {
+            return Err(AvbSlotVerifyError::InvalidMetadata);
+        }
+        Ok(descriptors)
+    }
+
+    pub(crate) fn num_hash_descriptor(&self) -> usize {
+        self.hash_descriptors.len()
+    }
+
+    /// Finds the `HashDescriptor` for the given `PartitionName`.
+    /// Throws an error if no corresponding descriptor found.
+    pub(crate) fn find_hash_descriptor(
+        &self,
+        partition_name: PartitionName,
+    ) -> Result<&HashDescriptor, AvbSlotVerifyError> {
+        self.hash_descriptors
+            .iter()
+            .find(|d| d.partition_name == partition_name)
+            .ok_or(AvbSlotVerifyError::InvalidMetadata)
+    }
+
+    fn push(&mut self, descriptor: Descriptor<'a>) -> utils::Result<()> {
+        match descriptor {
+            Descriptor::Hash(d) => self.push_hash_descriptor(d),
+        }
+    }
+
+    fn push_hash_descriptor(&mut self, descriptor: HashDescriptor<'a>) -> utils::Result<()> {
+        if self.hash_descriptors.iter().any(|d| d.partition_name == descriptor.partition_name) {
+            return Err(AvbIOError::Io);
+        }
+        self.hash_descriptors.push(descriptor);
+        Ok(())
+    }
+}
+
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+/// * The `descriptor` pointer must be non-null and points to a valid `AvbDescriptor` struct.
+/// * The `user_data` pointer must be non-null and points to a valid `Descriptors` struct.
+unsafe extern "C" fn check_and_save_descriptor(
+    descriptor: *const AvbDescriptor,
+    user_data: *mut c_void,
+) -> bool {
+    // SAFETY: It is safe because the caller must ensure that the `descriptor` pointer and
+    // the `user_data` are non-null and valid.
+    unsafe { try_check_and_save_descriptor(descriptor, user_data).is_ok() }
+}
+
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+/// * The `descriptor` pointer must be non-null and points to a valid `AvbDescriptor` struct.
+/// * The `user_data` pointer must be non-null and points to a valid `Descriptors` struct.
+unsafe fn try_check_and_save_descriptor(
+    descriptor: *const AvbDescriptor,
+    user_data: *mut c_void,
+) -> utils::Result<()> {
+    let mut descriptors = to_nonnull(user_data as *mut Descriptors)?;
+    // SAFETY: It is safe because the caller ensures that `user_data` is a non-null pointer
+    // pointing to a valid struct.
+    let descriptors = unsafe { descriptors.as_mut() };
+    // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null pointer
+    // pointing to a valid struct.
+    let descriptor = unsafe { Descriptor::from_descriptor_ptr(descriptor)? };
+    descriptors.push(descriptor)
+}
diff --git a/pvmfw/avb/src/error.rs b/pvmfw/avb/src/error.rs
index 674e5a7..c2b7428 100644
--- a/pvmfw/avb/src/error.rs
+++ b/pvmfw/avb/src/error.rs
@@ -93,7 +93,6 @@
     #[allow(dead_code)]
     Oom,
     /// AVB_IO_RESULT_ERROR_IO,
-    #[allow(dead_code)]
     Io,
     /// AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION,
     NoSuchPartition,
diff --git a/pvmfw/avb/src/verify.rs b/pvmfw/avb/src/verify.rs
index b03506c..ded0766 100644
--- a/pvmfw/avb/src/verify.rs
+++ b/pvmfw/avb/src/verify.rs
@@ -14,7 +14,7 @@
 
 //! This module handles the pvmfw payload verification.
 
-use crate::descriptor::{Digest, HashDescriptors};
+use crate::descriptor::{Descriptors, Digest};
 use crate::error::AvbSlotVerifyError;
 use crate::ops::{Ops, Payload};
 use crate::partition::PartitionName;
@@ -63,9 +63,9 @@
 }
 
 fn verify_vbmeta_has_only_one_hash_descriptor(
-    hash_descriptors: &HashDescriptors,
+    descriptors: &Descriptors,
 ) -> Result<(), AvbSlotVerifyError> {
-    if hash_descriptors.len() == 1 {
+    if descriptors.num_hash_descriptor() == 1 {
         Ok(())
     } else {
         Err(AvbSlotVerifyError::InvalidMetadata)
@@ -112,14 +112,14 @@
     // SAFETY: It is safe because the `vbmeta_image` is collected from `AvbSlotVerifyData`,
     // which is returned by `avb_slot_verify()` when the verification succeeds. It is
     // guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
-    let hash_descriptors = unsafe { HashDescriptors::from_vbmeta(vbmeta_image)? };
-    let kernel_descriptor = hash_descriptors.find(PartitionName::Kernel)?;
+    let descriptors = unsafe { Descriptors::from_vbmeta(vbmeta_image)? };
+    let kernel_descriptor = descriptors.find_hash_descriptor(PartitionName::Kernel)?;
 
     if initrd.is_none() {
-        verify_vbmeta_has_only_one_hash_descriptor(&hash_descriptors)?;
+        verify_vbmeta_has_only_one_hash_descriptor(&descriptors)?;
         return Ok(VerifiedBootData {
             debug_level: DebugLevel::None,
-            kernel_digest: kernel_descriptor.digest,
+            kernel_digest: *kernel_descriptor.digest,
             initrd_digest: None,
             public_key: trusted_public_key,
         });
@@ -140,11 +140,11 @@
         initrd_partition_name,
         initrd.len(),
     )?;
-    let initrd_descriptor = hash_descriptors.find(initrd_partition_name)?;
+    let initrd_descriptor = descriptors.find_hash_descriptor(initrd_partition_name)?;
     Ok(VerifiedBootData {
         debug_level,
-        kernel_digest: kernel_descriptor.digest,
-        initrd_digest: Some(initrd_descriptor.digest),
+        kernel_digest: *kernel_descriptor.digest,
+        initrd_digest: Some(*initrd_descriptor.digest),
         public_key: trusted_public_key,
     })
 }
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 63a59a1..c0241ca 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -744,7 +744,7 @@
     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 debuggable {
+    if !debuggable {
         if let Some(bootargs) = read_bootargs_from(fdt)? {
             filter_out_dangerous_bootargs(fdt, &bootargs)?;
         }
diff --git a/pvmfw/src/mmu.rs b/pvmfw/src/mmu.rs
index e33dcba..da8c4b5 100644
--- a/pvmfw/src/mmu.rs
+++ b/pvmfw/src/mmu.rs
@@ -26,8 +26,10 @@
 // We assume that:
 // - MAIR_EL1.Attr0 = "Device-nGnRE memory" (0b0000_0100)
 // - MAIR_EL1.Attr1 = "Normal memory, Outer & Inner WB Non-transient, R/W-Allocate" (0b1111_1111)
-const MEMORY: Attributes = Attributes::NORMAL.union(Attributes::NON_GLOBAL);
-const DEVICE: Attributes = Attributes::DEVICE_NGNRE.union(Attributes::EXECUTE_NEVER);
+const MEMORY: Attributes =
+    Attributes::NORMAL.union(Attributes::NON_GLOBAL).union(Attributes::VALID);
+const DEVICE: Attributes =
+    Attributes::DEVICE_NGNRE.union(Attributes::EXECUTE_NEVER).union(Attributes::VALID);
 const CODE: Attributes = MEMORY.union(Attributes::READ_ONLY);
 const DATA: Attributes = MEMORY.union(Attributes::EXECUTE_NEVER);
 const RODATA: Attributes = DATA.union(Attributes::READ_ONLY);
diff --git a/rialto/src/main.rs b/rialto/src/main.rs
index 03fa107..0f92d3f 100644
--- a/rialto/src/main.rs
+++ b/rialto/src/main.rs
@@ -44,21 +44,21 @@
 const PT_ROOT_LEVEL: usize = 1;
 const PT_ASID: usize = 1;
 
-const PROT_DEV: Attributes = Attributes::from_bits_truncate(
-    Attributes::DEVICE_NGNRE.bits() | Attributes::EXECUTE_NEVER.bits(),
-);
-const PROT_RX: Attributes = Attributes::from_bits_truncate(
-    Attributes::NORMAL.bits() | Attributes::NON_GLOBAL.bits() | Attributes::READ_ONLY.bits(),
-);
-const PROT_RO: Attributes = Attributes::from_bits_truncate(
-    Attributes::NORMAL.bits()
-        | Attributes::NON_GLOBAL.bits()
-        | Attributes::READ_ONLY.bits()
-        | Attributes::EXECUTE_NEVER.bits(),
-);
-const PROT_RW: Attributes = Attributes::from_bits_truncate(
-    Attributes::NORMAL.bits() | Attributes::NON_GLOBAL.bits() | Attributes::EXECUTE_NEVER.bits(),
-);
+const PROT_DEV: Attributes =
+    Attributes::DEVICE_NGNRE.union(Attributes::EXECUTE_NEVER).union(Attributes::VALID);
+const PROT_RX: Attributes = Attributes::NORMAL
+    .union(Attributes::NON_GLOBAL)
+    .union(Attributes::READ_ONLY)
+    .union(Attributes::VALID);
+const PROT_RO: Attributes = Attributes::NORMAL
+    .union(Attributes::NON_GLOBAL)
+    .union(Attributes::READ_ONLY)
+    .union(Attributes::EXECUTE_NEVER)
+    .union(Attributes::VALID);
+const PROT_RW: Attributes = Attributes::NORMAL
+    .union(Attributes::NON_GLOBAL)
+    .union(Attributes::EXECUTE_NEVER)
+    .union(Attributes::VALID);
 
 #[global_allocator]
 static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index 3bf850c..90a0ec2 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -82,17 +82,23 @@
     check_alloc();
 
     let mut idmap = IdMap::new(ASID, ROOT_LEVEL);
-    idmap.map_range(&DEVICE_REGION, Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER).unwrap();
+    idmap
+        .map_range(
+            &DEVICE_REGION,
+            Attributes::VALID | Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER,
+        )
+        .unwrap();
     idmap
         .map_range(
             &text_range().into(),
-            Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,
+            Attributes::VALID | Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,
         )
         .unwrap();
     idmap
         .map_range(
             &rodata_range().into(),
-            Attributes::NORMAL
+            Attributes::VALID
+                | Attributes::NORMAL
                 | Attributes::NON_GLOBAL
                 | Attributes::READ_ONLY
                 | Attributes::EXECUTE_NEVER,
@@ -101,26 +107,36 @@
     idmap
         .map_range(
             &scratch_range().into(),
-            Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
+            Attributes::VALID
+                | Attributes::NORMAL
+                | Attributes::NON_GLOBAL
+                | Attributes::EXECUTE_NEVER,
         )
         .unwrap();
     idmap
         .map_range(
             &boot_stack_range().into(),
-            Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::EXECUTE_NEVER,
+            Attributes::VALID
+                | Attributes::NORMAL
+                | Attributes::NON_GLOBAL
+                | Attributes::EXECUTE_NEVER,
         )
         .unwrap();
     idmap
         .map_range(
             &dtb_range().into(),
-            Attributes::NORMAL
+            Attributes::VALID
+                | Attributes::NORMAL
                 | Attributes::NON_GLOBAL
                 | Attributes::READ_ONLY
                 | Attributes::EXECUTE_NEVER,
         )
         .unwrap();
     idmap
-        .map_range(&get_bar_region(&pci_info), Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER)
+        .map_range(
+            &get_bar_region(&pci_info),
+            Attributes::VALID | Attributes::DEVICE_NGNRE | Attributes::EXECUTE_NEVER,
+        )
         .unwrap();
 
     info!("Activating IdMap...");
diff --git a/vmbase/src/logger.rs b/vmbase/src/logger.rs
index 94dc880..c30adad 100644
--- a/vmbase/src/logger.rs
+++ b/vmbase/src/logger.rs
@@ -18,8 +18,6 @@
 //! Note: may not work if the VM is in an inconsistent state. Exception handlers
 //! should avoid using this logger and instead print with eprintln!.
 
-extern crate log;
-
 use crate::console::println;
 use core::sync::atomic::{AtomicBool, Ordering};
 use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};