Implement Xlat::get_access_rights
Implement function for querying memory access rights of a given virtual
address.
Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I4c43a743a4fd10872f3a15ca1c8d634175706b16
diff --git a/src/lib.rs b/src/lib.rs
index 496681c..f1f1234 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -125,6 +125,37 @@
}
}
+impl From<Attributes> for MemoryAccessRights {
+ fn from(value: Attributes) -> Self {
+ let mut result = Self::empty();
+
+ result |= match value.data_access_permissions {
+ DataAccessPermissions::ReadOnly_None => Self::R,
+ DataAccessPermissions::ReadWrite_None => Self::RW,
+ DataAccessPermissions::ReadOnly_ReadOnly => Self::R | Self::USER,
+ DataAccessPermissions::ReadWrite_ReadWrite => Self::RW | Self::USER,
+ };
+
+ if value.mem_attr_index == MemoryAttributesIndex::Device_nGnRnE {
+ result |= Self::DEVICE;
+ }
+
+ if !value.uxn {
+ result |= Self::X;
+ }
+
+ if !value.not_global {
+ result |= Self::GLOBAL;
+ }
+
+ if value.non_secure {
+ result |= Self::NS;
+ }
+
+ result
+ }
+}
+
/// Virtual Address range, selects x in `TTBRx_EL*`
#[derive(Debug, Clone, Copy)]
pub enum RegimeVaRange {
@@ -414,6 +445,39 @@
Ok(())
}
+ /// Query the memory access rights of virtual address
+ /// # Arguments
+ /// * va : Virtual address, alignment to granule size is not required
+ /// # Return value
+ /// Memory access rights of the virtual address and the minimal length of a continuous memory
+ /// area after the virtual address that is guaranteed to have the same access rights. The
+ /// following area after the returned length might or might not have the same access rights.
+ pub fn get_access_rights(
+ &self,
+ va: VirtualAddress,
+ ) -> Result<(MemoryAccessRights, usize), XlatError> {
+ let containing_region = self
+ .find_containing_region(va, 1)
+ .ok_or(XlatError::VaNotFound(va))?;
+
+ if !containing_region.used() {
+ return Err(XlatError::VaNotFound(va));
+ }
+
+ let (descriptor, level) = self.get_descriptor(va.remove_upper_bits::<VA_BITS>());
+
+ match descriptor.get_descriptor_type(level) {
+ DescriptorType::Block => {
+ let attributes = descriptor.get_block_attributes(level);
+ let block_length = self.granule.block_size_at_level(level);
+ let length = block_length - va.mask_bits(block_length - 1).0;
+
+ Ok((MemoryAccessRights::from(attributes), length))
+ }
+ _ => Err(XlatError::VaNotFound(va)),
+ }
+ }
+
/// Activate memory mapping represented by the object
///
/// # Safety
@@ -934,41 +998,42 @@
}
}
- fn get_descriptor(&mut self, va: VirtualAddress, block_size: usize) -> &mut Descriptor {
+ /// Find a block or an invalid descriptor which describes the virtual address' mapping.
+ /// # Arguments
+ /// * va : Virtual address, alignment to granule size is not required
+ /// # Return value
+ /// Reference to the descriptor and level of the descriptor in the translation table
+ fn get_descriptor(&self, va: VirtualAddress) -> (&Descriptor, isize) {
Self::walk_descriptors(
va,
- block_size,
self.granule.initial_lookup_level(),
- unsafe { self.base_table.get_as_mut_slice::<K, Descriptor>() },
+ unsafe { self.base_table.get_as_slice::<K, Descriptor>() },
self.granule,
)
}
+ /// Walk translation table until finding a block or invalid descriptor that contains the VA.
+ /// # Arguments
+ /// * va : Virtual address, alignment to granule size is not required
+ /// * table: Translation table on the given level
+ /// * granule: Translation granule
+ /// # Return value
+ /// Reference to the descriptor and level of the descriptor in the translation table
fn walk_descriptors(
va: VirtualAddress,
- block_size: usize,
level: isize,
- table: &mut [Descriptor],
+ table: &[Descriptor],
granule: TranslationGranule<VA_BITS>,
- ) -> &mut Descriptor {
+ ) -> (&Descriptor, isize) {
// Get descriptor of the current level
- let descriptor = &mut table[va.get_level_index(granule, level)];
-
- if granule.block_size_at_level(level) == block_size {
- return descriptor;
- }
+ let descriptor = &table[va.get_level_index(granule, level)];
// Need to iterate forward
match descriptor.get_descriptor_type(level) {
- DescriptorType::Invalid => {
- panic!("Invalid descriptor");
- }
- DescriptorType::Block => {
- panic!("Cannot split existing block descriptor to table");
- }
+ DescriptorType::Invalid | DescriptorType::Block => (descriptor, level),
DescriptorType::Table => {
let next_level_table = unsafe {
- Self::get_table_from_pa_mut(
+ Self::get_table_from_pa(
descriptor.get_next_level_table(level),
granule,
level + 1,
@@ -977,7 +1042,6 @@
Self::walk_descriptors(
va.mask_for_level(granule, level),
- block_size,
level + 1,
next_level_table,
granule,