[pvmfw] Extract smccc into a separate library for reuse

Test: m pvmfw_img
Bug: 272226230
Change-Id: Ie6e03e92acca8f0947febefa80587c0db0010c49
diff --git a/libs/smccc/src/lib.rs b/libs/smccc/src/lib.rs
new file mode 100644
index 0000000..2cd31dc
--- /dev/null
+++ b/libs/smccc/src/lib.rs
@@ -0,0 +1,22 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Structs and functions for making SMCCC calls following the SMC Calling
+//! Convention version 1.4.
+
+#![no_std]
+
+mod smccc;
+
+pub use smccc::{checked_hvc64, checked_hvc64_expect_zero, hvc64, Error, Result};
diff --git a/libs/smccc/src/smccc.rs b/libs/smccc/src/smccc.rs
new file mode 100644
index 0000000..c0070e0
--- /dev/null
+++ b/libs/smccc/src/smccc.rs
@@ -0,0 +1,72 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Structs and functions for making SMCCC calls.
+
+use core::{fmt, result};
+// Ideally, smccc shouldn't depend on psci. Smccc isn't split as a separate
+// upstream crate currently mostly for maintenance consideration.
+// See b/245889995 for more context.
+pub use psci::smccc::hvc64;
+
+/// Standard SMCCC error values as described in DEN 0028E.
+#[derive(Debug, Clone)]
+pub enum Error {
+    /// The call is not supported by the implementation.
+    NotSupported,
+    /// The call is deemed not required by the implementation.
+    NotRequired,
+    /// One of the call parameters has a non-supported value.
+    InvalidParameter,
+    /// Negative values indicate error.
+    Unknown(i64),
+    /// The call returned a positive value when 0 was expected.
+    Unexpected(u64),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::NotSupported => write!(f, "SMCCC call not supported"),
+            Self::NotRequired => write!(f, "SMCCC call not required"),
+            Self::InvalidParameter => write!(f, "SMCCC call received non-supported value"),
+            Self::Unexpected(v) => write!(f, "Unexpected SMCCC return value {} ({0:#x})", v),
+            Self::Unknown(e) => write!(f, "Unknown SMCCC return value {} ({0:#x})", e),
+        }
+    }
+}
+
+/// Result type with smccc::Error.
+pub type Result<T> = result::Result<T, Error>;
+
+/// Makes a checked HVC64 call to the hypervisor, following the SMC Calling Convention version 1.4.
+/// Returns Ok only when the return code is 0.
+pub fn checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()> {
+    match checked_hvc64(function, args)? {
+        0 => Ok(()),
+        v => Err(Error::Unexpected(v)),
+    }
+}
+
+/// Makes a checked HVC64 call to the hypervisor, following the SMC Calling Convention version 1.4.
+/// Returns Ok with the return code only when the return code >= 0.
+pub fn checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64> {
+    match hvc64(function, args)[0] as i64 {
+        ret if ret >= 0 => Ok(ret as u64),
+        -1 => Err(Error::NotSupported),
+        -2 => Err(Error::NotRequired),
+        -3 => Err(Error::InvalidParameter),
+        ret => Err(Error::Unknown(ret)),
+    }
+}