Implement conversions between ErrorCode and u32/u64

Implement TryFrom and From traits for ErrorCode to support conversions
between ErrorCode and u32/u64 types. According to the PSCI
specification, error code values are represented as 32-bit or 64-bit
signed integers. These new trait implementations allow ErrorCode to be
converted to and from u32/u64, making it possible to use the values
directly in registers.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: If4b4151760d8d7600d65d1c3d83d317547223457
diff --git a/src/lib.rs b/src/lib.rs
index 087872b..1daec01 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,6 +26,8 @@
     UnrecognisedFunctionId(u32),
     #[error("unrecognised PSCI error code {0}")]
     UnrecognisedErrorCode(i32),
+    #[error("overflowing PSCI error code {0}")]
+    OverflowingErrorCode(i64),
     #[error("invalid PSCI version {0}")]
     InvalidVersion(u32),
     #[error("invalid power state value {0}")]
@@ -162,6 +164,41 @@
     InvalidAddress = -9,
 }
 
+impl TryFrom<u32> for ErrorCode {
+    type Error = Error;
+
+    fn try_from(value: u32) -> Result<Self, Self::Error> {
+        Self::try_from_primitive(value as i32)
+    }
+}
+
+impl TryFrom<u64> for ErrorCode {
+    type Error = Error;
+
+    fn try_from(value: u64) -> Result<Self, Self::Error> {
+        let signed_value =
+            i32::try_from(value as i64).map_err(|_| Error::OverflowingErrorCode(value as i64))?;
+        Self::try_from_primitive(signed_value)
+    }
+}
+
+impl From<ErrorCode> for u32 {
+    /// Converts `ErrorCode` to be suitable for returning it in a 32-bit register.
+    /// See 5.2.2 Return error codes
+    fn from(value: ErrorCode) -> Self {
+        i32::from(value) as u32
+    }
+}
+
+impl From<ErrorCode> for u64 {
+    /// Converts `ErrorCode` to be suitable for returning it in a 64-bit register, i.e. it does
+    /// sign extension to 64 bits.
+    /// See 5.2.2 Return error codes
+    fn from(value: ErrorCode) -> Self {
+        i32::from(value) as u64
+    }
+}
+
 /// Structure for describing PSCI major and minor version.
 #[derive(Debug, Eq, PartialEq, Clone, Copy)]
 pub struct Version {
@@ -1107,6 +1144,37 @@
         assert_eq!(-7, i32::from(ErrorCode::NotPresent));
         assert_eq!(-8, i32::from(ErrorCode::Disabled));
         assert_eq!(-9, i32::from(ErrorCode::InvalidAddress));
+
+        assert_eq!(
+            Err(Error::UnrecognisedErrorCode(0)),
+            ErrorCode::try_from(0u32)
+        );
+
+        assert_eq!(
+            Ok(ErrorCode::NotSupported),
+            ErrorCode::try_from(0xffff_ffffu32)
+        );
+
+        assert_eq!(
+            Err(Error::UnrecognisedErrorCode(0)),
+            ErrorCode::try_from(0u64)
+        );
+
+        assert_eq!(
+            Err(Error::OverflowingErrorCode(0x7fff_ffff_ffff_ffff)),
+            ErrorCode::try_from(0x7fff_ffff_ffff_ffffu64)
+        );
+
+        assert_eq!(
+            Ok(ErrorCode::NotSupported),
+            ErrorCode::try_from(0xffff_ffff_ffff_ffffu64)
+        );
+
+        assert_eq!(0xffff_fffe, u32::from(ErrorCode::InvalidParameters));
+        assert_eq!(
+            0xffff_ffff_ffff_fffe,
+            u64::from(ErrorCode::InvalidParameters)
+        );
     }
 
     #[test]