Implement FFA_MEM_PERM_GET/SET types

Add new types for describing memory permissions in FFA_MEM_PERM_GET/SET
calls and parsing the FFA_SUCCESS arguments of an FFA_MEM_PERM_GET call.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I5fa5c67c258683efe586f567a0c4ad250254525c
diff --git a/src/lib.rs b/src/lib.rs
index 1408d51..fb30191 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -60,6 +60,8 @@
     InvalidVersionForFunctionId(Version, FuncId),
     #[error("Invalid character count {0}")]
     InvalidCharacterCount(u8),
+    #[error("Memory management error")]
+    MemoryManagementError(#[from] memory_management::Error),
 }
 
 impl From<Error> for FfaError {
@@ -81,7 +83,8 @@
             | Error::InvalidSuccessArgsVariant
             | Error::InvalidNotificationCount
             | Error::InvalidPartitionInfoGetRegsResponse
-            | Error::InvalidCharacterCount(_) => Self::InvalidParameters,
+            | Error::InvalidCharacterCount(_)
+            | Error::MemoryManagementError(_) => Self::InvalidParameters,
         }
     }
 }
@@ -1278,7 +1281,7 @@
     MemPermSet {
         addr: MemAddr,
         page_cnt: u32,
-        mem_perm: u32,
+        mem_perm: memory_management::MemPermissionsGetSet,
     },
     ConsoleLog {
         chars: ConsoleLogChars,
@@ -1800,12 +1803,12 @@
             FuncId::MemPermSet32 => Self::MemPermSet {
                 addr: MemAddr::Addr32(regs[1] as u32),
                 page_cnt: regs[2] as u32,
-                mem_perm: regs[3] as u32,
+                mem_perm: (regs[3] as u32).try_into()?,
             },
             FuncId::MemPermSet64 => Self::MemPermSet {
                 addr: MemAddr::Addr64(regs[1]),
                 page_cnt: regs[2] as u32,
-                mem_perm: regs[3] as u32,
+                mem_perm: (regs[3] as u32).try_into()?,
             },
             FuncId::ConsoleLog32 => {
                 let char_cnt = regs[1] as u8;
@@ -2272,7 +2275,7 @@
                     MemAddr::Addr64(addr) => addr,
                 };
                 a[2] = page_cnt.into();
-                a[3] = mem_perm.into();
+                a[3] = u32::from(mem_perm).into();
             }
             Interface::ConsoleLog { chars } => match chars {
                 ConsoleLogChars::Chars32(ConsoleLogChars32 {
diff --git a/src/memory_management.rs b/src/memory_management.rs
index 1302f82..a3b5ce7 100644
--- a/src/memory_management.rs
+++ b/src/memory_management.rs
@@ -26,7 +26,7 @@
 
 /// Rich error types returned by this module. Should be converted to [`crate::FfaError`] when used
 /// with the `FFA_ERROR` interface.
-#[derive(Debug, Error)]
+#[derive(Debug, Error, PartialEq, Eq)]
 pub enum Error {
     #[error("Invalid cacheability attribute {0}")]
     InvalidCacheability(u16),
@@ -50,6 +50,12 @@
     InvalidBufferSize,
     #[error("Malformed descriptor")]
     MalformedDescriptor,
+    #[error("Invalid get/set instruction access permission {0}")]
+    InvalidInstrAccessPermGetSet(u32),
+    #[error("Invalid get/set instruction data permission {0}")]
+    InvalidDataAccessPermGetSet(u32),
+    #[error("Invalid page count")]
+    InvalidPageCount,
 }
 
 impl From<Error> for crate::FfaError {
@@ -811,6 +817,112 @@
     }
 }
 
+/// Data access permission enum for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u32)]
+pub enum DataAccessPermGetSet {
+    NoAccess = Self::NO_ACCESS << Self::SHIFT,
+    ReadWrite = Self::READ_WRITE << Self::SHIFT,
+    ReadOnly = Self::READ_ONLY << Self::SHIFT,
+}
+
+impl DataAccessPermGetSet {
+    const SHIFT: usize = 0;
+    const MASK: u32 = 0b11;
+    const NO_ACCESS: u32 = 0b00;
+    const READ_WRITE: u32 = 0b01;
+    const READ_ONLY: u32 = 0b11;
+}
+
+impl TryFrom<u32> for DataAccessPermGetSet {
+    type Error = Error;
+
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match (value >> Self::SHIFT) & Self::MASK {
+            Self::NO_ACCESS => Ok(Self::NoAccess),
+            Self::READ_WRITE => Ok(Self::ReadWrite),
+            Self::READ_ONLY => Ok(Self::ReadOnly),
+            _ => Err(Error::InvalidDataAccessPermGetSet(value)),
+        }
+    }
+}
+
+/// Instructions access permission enum for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u32)]
+pub enum InstructionAccessPermGetSet {
+    Executable = Self::EXECUTABLE << Self::SHIFT,
+    NonExecutable = Self::NON_EXECUTABLE << Self::SHIFT,
+}
+
+impl InstructionAccessPermGetSet {
+    const SHIFT: usize = 2;
+    const MASK: u32 = 0b1;
+    const EXECUTABLE: u32 = 0b0;
+    const NON_EXECUTABLE: u32 = 0b1;
+}
+
+impl TryFrom<u32> for InstructionAccessPermGetSet {
+    type Error = Error;
+
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        match (value >> Self::SHIFT) & Self::MASK {
+            Self::EXECUTABLE => Ok(Self::Executable),
+            Self::NON_EXECUTABLE => Ok(Self::NonExecutable),
+            _ => Err(Error::InvalidInstrAccessPermGetSet(value)),
+        }
+    }
+}
+
+/// Memory permission structure for `FFA_MEM_PERM_GET` and `FFA_MEM_PERM_SET` calls.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct MemPermissionsGetSet {
+    pub data_access: DataAccessPermGetSet,
+    pub instr_access: InstructionAccessPermGetSet,
+}
+
+impl TryFrom<u32> for MemPermissionsGetSet {
+    type Error = Error;
+
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        Ok(Self {
+            data_access: value.try_into()?,
+            instr_access: value.try_into()?,
+        })
+    }
+}
+
+impl From<MemPermissionsGetSet> for u32 {
+    fn from(value: MemPermissionsGetSet) -> Self {
+        value.data_access as u32 | value.instr_access as u32
+    }
+}
+
+/// Success argument structure for `FFA_MEM_PERM_GET`.
+pub struct SuccessArgsMemPermGet {
+    pub perm: MemPermissionsGetSet,
+    pub page_cnt: u32,
+}
+
+impl From<SuccessArgsMemPermGet> for SuccessArgs {
+    fn from(value: SuccessArgsMemPermGet) -> Self {
+        assert_ne!(value.page_cnt, 0);
+        SuccessArgs::Args32([value.perm.into(), value.page_cnt - 1, 0, 0, 0, 0])
+    }
+}
+
+impl TryFrom<SuccessArgs> for SuccessArgsMemPermGet {
+    type Error = crate::Error;
+
+    fn try_from(value: SuccessArgs) -> Result<Self, Self::Error> {
+        let [perm, page_cnt, ..] = value.try_get_args32()?;
+        Ok(Self {
+            perm: perm.try_into()?,
+            page_cnt: page_cnt.checked_add(1).ok_or(Error::InvalidPageCount)?,
+        })
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;