Add SecureAccess enum

Introduce SecureAccess enum to describe read/write access instead of
using a pair of booleans. This makes caller code more readable and
simplifies storage of access rights.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: Idbb675790043b5816325fe8132b021cd3a00a01d
diff --git a/src/lib.rs b/src/lib.rs
index 551dea9..b12ea45 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,7 @@
 use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
 
 pub use crate::fail::{FailAccessDirection, FailControlRegister, FailIDRegister, TzcFail};
-pub use crate::region::{RegionAttributes, RegionIDAccess, TzcRegion, TzcRegionMut};
+pub use crate::region::{RegionAttributes, RegionIDAccess, SecureAccess, TzcRegion, TzcRegionMut};
 use crate::{
     fail::FailRegisters,
     region::RegionRegisters,
diff --git a/src/region.rs b/src/region.rs
index b79de3e..921f619 100644
--- a/src/region.rs
+++ b/src/region.rs
@@ -1,5 +1,7 @@
 // SPDX-FileCopyrightText: Copyright The arm-tzc Contributors.
 // SPDX-License-Identifier: MIT OR Apache-2.0
+
+use bitflags::bitflags;
 use safe_mmio::{SharedMmioPointer, UniqueMmioPointer, field, field_shared, fields::ReadPureWrite};
 use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
 
@@ -10,6 +12,27 @@
 
 const REGION_ALIGNMENT_MASK: u64 = 0xfff;
 
+/// Controls access to a region from the secure world.
+#[derive(Debug, Clone, Copy, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+#[repr(transparent)]
+pub struct SecureAccess(u32);
+
+bitflags! {
+    impl SecureAccess: u32 {
+        /// Denies all access from secure world.
+        const NONE = 0;
+
+        /// Enables read access from secure world.
+        const R = 1 << 30;
+
+        /// Enables write access from secure world.
+        const W = 1 << 31;
+
+        /// Enables read-write access from secure world.
+        const RW = Self::R.bits() | Self::W.bits();
+    }
+}
+
 #[derive(Debug, Clone, Copy, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
 /// Each region has a region attributes register which controls the permissions for Region 0 and,
 /// for all other regions, the permissions and target filter region enables.
@@ -19,13 +42,10 @@
 impl RegionAttributes {
     /// Creates a fresh value for a `RegionAttributes`.
     ///
-    /// - `write`: whether the region should allow write access from the Secure World.
-    /// - `read`: whether the region should allow red access from the Secure World.
+    /// - `secure_access`: controls read/write access from the Secure World.
     /// - `filters`: the id of the filters to enable for this region.
-    pub const fn new(write: bool, read: bool, filters: &[usize]) -> Self {
-        let mut s = Self(0);
-        s.set_write_enabled(write);
-        s.set_read_enabled(read);
+    pub const fn new(secure_access: SecureAccess, filters: &[usize]) -> Self {
+        let mut s = Self(secure_access.bits());
 
         for_in_slice! {
             f in filters,
@@ -35,26 +55,15 @@
         s
     }
 
-    /// Whether Secure writes are permitted in this region.
-    pub const fn is_write_enabled(&self) -> bool {
-        get_bit(self.0, 31)
+    /// Gets secure access attributes of the region.
+    pub const fn secure_access(&self) -> SecureAccess {
+        SecureAccess::from_bits_truncate(self.0)
     }
 
-    /// Secure global write enable. This control bit defines the permissions for the Secure writes
-    /// in the region.
-    pub const fn set_write_enabled(&mut self, enabled: bool) {
-        set_bit(&mut self.0, 31, enabled);
-    }
-
-    /// Whether Secure reads are permitted in this region.
-    pub const fn is_read_enabled(&self) -> bool {
-        get_bit(self.0, 30)
-    }
-
-    /// Secure global read enable. This control bit defines the permissions for the Secure reads in
-    /// the region.
-    pub const fn set_read_enabled(&mut self, enabled: bool) {
-        set_bit(&mut self.0, 30, enabled);
+    /// Sets secure access attributes of the region.
+    pub const fn set_secure_access(&mut self, secure_access: SecureAccess) {
+        self.0 &= !SecureAccess::RW.bits();
+        self.0 |= secure_access.bits();
     }
 
     /// Whether the filter `index` is enabled for this region.
@@ -80,6 +89,9 @@
 pub struct RegionIDAccess(u32);
 
 impl RegionIDAccess {
+    /// Denies non-secure access to the region.
+    pub const NONE: Self = Self::new(&[], &[]);
+
     /// Creates a new instance of `RegionIDAccess`.
     ///
     /// - `writes`: all the NSA indexes that should be allowed to write into this region.
@@ -268,7 +280,8 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::{region::REGION_ALIGNMENT_MASK, tests::FakeTZCRegisters, *};
+    use super::*;
+    use crate::{region::REGION_ALIGNMENT_MASK, tests::FakeTZCRegisters};
 
     #[test]
     fn region_0_address() {
@@ -390,29 +403,25 @@
         let att2 = tzc.region(2).unwrap().region_attributes();
         let att3 = tzc.region(3).unwrap().region_attributes();
 
-        assert!(!att0.is_read_enabled());
-        assert!(!att0.is_write_enabled());
+        assert_eq!(SecureAccess::NONE, att0.secure_access());
         assert!(att0.is_filter_enabled(0));
         assert!(!att0.is_filter_enabled(1));
         assert!(att0.is_filter_enabled(2));
         assert!(!att0.is_filter_enabled(3));
 
-        assert!(att1.is_read_enabled());
-        assert!(!att1.is_write_enabled());
+        assert_eq!(SecureAccess::R, att1.secure_access());
         assert!(!att1.is_filter_enabled(0));
         assert!(att1.is_filter_enabled(1));
         assert!(!att1.is_filter_enabled(2));
         assert!(!att1.is_filter_enabled(3));
 
-        assert!(!att2.is_read_enabled());
-        assert!(att2.is_write_enabled());
+        assert_eq!(SecureAccess::W, att2.secure_access());
         assert!(att2.is_filter_enabled(0));
         assert!(att2.is_filter_enabled(1));
         assert!(att2.is_filter_enabled(2));
         assert!(att2.is_filter_enabled(3));
 
-        assert!(att3.is_read_enabled());
-        assert!(att3.is_write_enabled());
+        assert_eq!(SecureAccess::RW, att3.secure_access());
         assert!(!att3.is_filter_enabled(0));
         assert!(!att3.is_filter_enabled(1));
         assert!(!att3.is_filter_enabled(2));
@@ -429,17 +438,17 @@
 
         let mut reg0 = tzc.region_mut(0).unwrap();
         let mut att0 = reg0.region_attributes();
-        att0.set_write_enabled(true);
+        att0.set_secure_access(SecureAccess::W);
         att0.set_filter_status(0, false);
         reg0.set_region_attributes(att0);
 
         let mut reg1 = tzc.region_mut(1).unwrap();
         let mut att1 = reg1.region_attributes();
-        att1.set_read_enabled(false);
+        att1.set_secure_access(SecureAccess::NONE);
         att1.set_filter_status(1, false);
         reg1.set_region_attributes(att1);
 
-        let att2 = RegionAttributes::new(true, true, &[0, 1, 2, 3]);
+        let att2 = RegionAttributes::new(SecureAccess::RW, &[0, 1, 2, 3]);
         tzc.region_mut(2).unwrap().set_region_attributes(att2);
         assert_eq!(
             regs.reg_read(0x110),