Add MsgWaitFlags to the MsgWait Interface

Change-Id: I6dc162eba1b9bb9929ec225215c25a432f4e1981
Signed-off-by: Tomás González <tomasagustin.gonzalezorlando@arm.com>
diff --git a/src/lib.rs b/src/lib.rs
index 0328a82..48264b6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -33,8 +33,8 @@
     UnrecognisedErrorCode(i32),
     #[error("Unrecognised FF-A Framework Message {0}")]
     UnrecognisedFwkMsg(u32),
-    #[error("Unrecognised FF-A Msg Wait Flag {0}")]
-    UnrecognisedMsgWaitFlag(u32),
+    #[error("Invalid FF-A Msg Wait Flag {0}")]
+    InvalidMsgWaitFlag(u32),
     #[error("Unrecognised VM availability status {0}")]
     UnrecognisedVmAvailabilityStatus(i32),
     #[error("Unrecognised FF-A Warm Boot Type {0}")]
@@ -52,7 +52,7 @@
             Error::UnrecognisedErrorCode(_)
             | Error::UnrecognisedFwkMsg(_)
             | Error::InvalidVersion(_)
-            | Error::UnrecognisedMsgWaitFlag(_)
+            | Error::InvalidMsgWaitFlag(_)
             | Error::UnrecognisedVmAvailabilityStatus(_)
             | Error::UnrecognisedWarmBootType(_) => Self::InvalidParameters,
         }
@@ -416,6 +416,40 @@
 #[derive(Debug, Eq, PartialEq, Clone, Copy)]
 pub struct DirectMsg2Args([u64; 14]);
 
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
+pub struct MsgWaitFlags {
+    retain_rx_buffer: bool,
+}
+
+impl MsgWaitFlags {
+    const RETAIN_RX_BUFFER: u32 = 0x01;
+    const MBZ_BITS: u32 = 0xfffe;
+}
+
+impl TryFrom<u32> for MsgWaitFlags {
+    type Error = Error;
+
+    fn try_from(val: u32) -> Result<Self, Self::Error> {
+        if (val & Self::MBZ_BITS) != 0 {
+            Err(Error::InvalidMsgWaitFlag(val))
+        } else {
+            Ok(MsgWaitFlags {
+                retain_rx_buffer: val & Self::RETAIN_RX_BUFFER != 0,
+            })
+        }
+    }
+}
+
+impl From<MsgWaitFlags> for u32 {
+    fn from(flags: MsgWaitFlags) -> Self {
+        let mut bits: u32 = 0;
+        if flags.retain_rx_buffer {
+            bits |= MsgWaitFlags::RETAIN_RX_BUFFER;
+        }
+        bits
+    }
+}
+
 /// Descriptor for a dynamically allocated memory buffer that contains the memory transaction
 /// descriptor.
 ///
@@ -488,7 +522,9 @@
     },
     IdGet,
     SpmIdGet,
-    MsgWait,
+    MsgWait {
+        flags: Option<MsgWaitFlags>,
+    },
     Yield,
     Run {
         target_info: TargetInfo,
@@ -589,7 +625,7 @@
             Interface::PartitionInfoGet { .. } => Some(FuncId::PartitionInfoGet),
             Interface::IdGet => Some(FuncId::IdGet),
             Interface::SpmIdGet => Some(FuncId::SpmIdGet),
-            Interface::MsgWait => Some(FuncId::MsgWait),
+            Interface::MsgWait { .. } => Some(FuncId::MsgWait),
             Interface::Yield => Some(FuncId::Yield),
             Interface::Run { .. } => Some(FuncId::Run),
             Interface::NormalWorldResume => Some(FuncId::NormalWorldResume),
@@ -768,7 +804,13 @@
             }
             FuncId::IdGet => Self::IdGet,
             FuncId::SpmIdGet => Self::SpmIdGet,
-            FuncId::MsgWait => Self::MsgWait,
+            FuncId::MsgWait => Self::MsgWait {
+                flags: if version >= Version(1, 2) {
+                    Some(MsgWaitFlags::try_from(regs[2] as u32)?)
+                } else {
+                    None
+                },
+            },
             FuncId::Yield => Self::Yield,
             FuncId::Run => Self::Run {
                 target_info: (regs[1] as u32).into(),
@@ -1183,7 +1225,14 @@
                 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]).into();
                 a[5] = flags.into();
             }
-            Interface::IdGet | Interface::SpmIdGet | Interface::MsgWait | Interface::Yield => {}
+            Interface::MsgWait { flags } => {
+                if version >= Version(1, 2) {
+                    if let Some(flags) = flags {
+                        a[2] = u32::from(flags).into();
+                    }
+                }
+            }
+            Interface::IdGet | Interface::SpmIdGet | Interface::Yield => {}
             Interface::Run { target_info } => {
                 a[1] = u32::from(target_info).into();
             }