diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-10 16:19:00 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-10 16:19:00 +0000 |
commit | b42c4f1730b17fb871540b4efa3c9dc2d91a6d90 (patch) | |
tree | 1bc2c7528414de3900e3b868e851c80723feb7cb | |
parent | 8cd84846c607a7469ba5334752870c69b681db94 (diff) | |
parent | ded408cf09001e7a4578b307eb1a526f0b92cc44 (diff) | |
download | psci-aml_tz5_341510010.tar.gz |
Snap for 10103804 from ded408cf09001e7a4578b307eb1a526f0b92cc44 to mainline-tzdata5-releaseaml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: I1f2777e80556208a84bab057615a1cf8ea369754
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 26 | ||||
-rw-r--r-- | CHANGELOG.md | 26 | ||||
-rw-r--r-- | Cargo.toml | 5 | ||||
-rw-r--r-- | Cargo.toml.orig | 4 | ||||
-rw-r--r-- | METADATA | 16 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | cargo2android.json | 10 | ||||
-rw-r--r-- | patches/Android.bp.patch | 17 | ||||
-rw-r--r-- | src/calls.rs | 31 | ||||
-rw-r--r-- | src/error.rs | 58 | ||||
-rw-r--r-- | src/lib.rs | 12 | ||||
-rw-r--r-- | src/smccc.rs | 3 | ||||
-rw-r--r-- | src/smccc/arch.rs | 90 | ||||
-rw-r--r-- | src/smccc/arch/calls.rs | 43 | ||||
-rw-r--r-- | src/smccc/arch/error.rs | 58 | ||||
-rw-r--r-- | src/smccc/error.rs | 75 |
17 files changed, 428 insertions, 63 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 5dc8b81..cea778b 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "12b9e3dc136b77b51b2a727408c7b894c0a10199" + "sha1": "bb36e58c69890d3b39e418f80ede8898e15aac44" }, "path_in_vcs": "" }
\ No newline at end of file @@ -1,4 +1,4 @@ -// This file is generated by cargo2android.py --run --device --tests --features=hvc --force-rlib. +// This file is generated by cargo2android.py --config cargo2android.json. // Do not modify this file as changes will be overridden on upgrade. package { @@ -41,10 +41,9 @@ license { rust_library_rlib { name: "libpsci", // has rustc warnings - host_supported: true, crate_name: "psci", cargo_env_compat: true, - cargo_pkg_version: "0.1.1", + cargo_pkg_version: "0.1.3", srcs: ["src/lib.rs"], edition: "2021", features: ["hvc"], @@ -52,4 +51,25 @@ rust_library_rlib { "//apex_available:platform", "//apex_available:anyapex", ], + product_available: true, + vendor_available: true, + prefer_rlib: true, + no_stdlibs: true, + stdlibs: [ + "libcompiler_builtins.rust_sysroot", + "libcore.rust_sysroot", + ], +} + +rust_test { + name: "psci_test_src_lib", + // has rustc warnings + crate_name: "psci", + cargo_env_compat: true, + cargo_pkg_version: "0.1.3", + srcs: ["src/lib.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + edition: "2021", + features: ["hvc"], } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7f539a9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +## 0.1.3 + +### Bugfixes + +- Fixed type of `smccc::error::success_or_error_64`. This is a breaking change relative to 0.1.2 but + it was yanked. + +## 0.1.2 (yanked) + +### New features + +- Added constants, types and functions for standard Arm architucture SMCCC calls, in `smccc::arch` + module. +- Added helpers in `smccc::error` module for handling negative return values as errors. + +## 0.1.1 + +### New features + +- Exposed functions for SMC and HVC calls for use outside of PSCI. + +## 0.1.0 + +Initial release with PSCI constants and functions. @@ -12,9 +12,9 @@ [package] edition = "2021" name = "psci" -version = "0.1.1" +version = "0.1.3" authors = ["Andrew Walbran <qwandor@google.com>"] -description = "Functions and constants for the Arm Power State Coordination Interface (PSCI) 1.1 on aarch64." +description = "Functions and constants for the Arm SMC Calling Convention (SMCCC) 1.4 and Arm Power State Coordination Interface (PSCI) 1.1 on aarch64." readme = "README.md" keywords = [ "arm", @@ -29,7 +29,6 @@ categories = [ ] license = "MIT OR Apache-2.0" repository = "https://github.com/google/psci" -resolver = "2" [dependencies] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index e329535..cd3e90c 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,9 +1,9 @@ [package] name = "psci" -version = "0.1.1" +version = "0.1.3" edition = "2021" license = "MIT OR Apache-2.0" -description = "Functions and constants for the Arm Power State Coordination Interface (PSCI) 1.1 on aarch64." +description = "Functions and constants for the Arm SMC Calling Convention (SMCCC) 1.4 and Arm Power State Coordination Interface (PSCI) 1.1 on aarch64." authors = ["Andrew Walbran <qwandor@google.com>"] repository = "https://github.com/google/psci" keywords = ["arm", "aarch64", "cortex-a", "psci"] @@ -1,5 +1,9 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/psci +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "psci" -description: "Functions and constants for the Arm Power State Coordination Interface (PSCI) 1.1 on aarch64." +description: "Functions and constants for the Arm SMC Calling Convention (SMCCC) 1.4 and Arm Power State Coordination Interface (PSCI) 1.1 on aarch64." third_party { url { type: HOMEPAGE @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/psci/psci-0.1.1.crate" + value: "https://static.crates.io/crates/psci/psci-0.1.3.crate" } - version: "0.1.1" + version: "0.1.3" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 10 - day: 6 + year: 2023 + month: 4 + day: 14 } } @@ -1,15 +1,16 @@ -# PSCI functions for bare-metal Rust on aarch64 +# SMCCC and PSCI functions for bare-metal Rust on aarch64 [![crates.io page](https://img.shields.io/crates/v/psci.svg)](https://crates.io/crates/psci) [![docs.rs page](https://docs.rs/psci/badge.svg)](https://docs.rs/psci) -This crate provides constants for version 1.1 of the Arm Power State Coordination Interface (PSCI), -and functions to call them. +This crate provides support for the Arm SMC Calling Convention version 1.4, including standard Arm +Architecture Calls constants, and version 1.1 of the Arm Power State Coordination Interface (PSCI). +It includes constants, functions to make the calls (on aarch64 targets), and error types. -Note that PSCI calls may be made via either HVC or SMC. You can choose which one to use by building -this crate with the corresponding feature (i.e. `hvc` or `smc`). By default `hvc` is enabled. If -neither feature is enabled then the functions to make calls will not be available, but the -constants are still provided. +Note that PSCI and other SMCCC calls may be made via either HVC or SMC. You can choose which one to +use by building this crate with the corresponding feature (i.e. `hvc` or `smc`). By default `hvc` is +enabled. If neither feature is enabled then the functions to make calls will not be available, but +the constants are still provided. This crate currently only supports aarch64 and the SMC64 versions of the various calls, in the cases that both SMC32 and SMC64 versions exist. diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..f3802fd --- /dev/null +++ b/cargo2android.json @@ -0,0 +1,10 @@ +{ + "dependencies": true, + "device": true, + "features": "hvc", + "force-rlib": true, + "no-host": true, + "patch": "patches/Android.bp.patch", + "run": true, + "tests": true +} diff --git a/patches/Android.bp.patch b/patches/Android.bp.patch new file mode 100644 index 0000000..1fa0e93 --- /dev/null +++ b/patches/Android.bp.patch @@ -0,0 +1,17 @@ +diff --git a/Android.bp b/Android.bp +index 34d110a..2348c03 100644 +--- a/Android.bp ++++ b/Android.bp +@@ -53,6 +53,12 @@ rust_library_rlib { + ], + product_available: true, + vendor_available: true, ++ prefer_rlib: true, ++ no_stdlibs: true, ++ stdlibs: [ ++ "libcompiler_builtins.rust_sysroot", ++ "libcore.rust_sysroot", ++ ], + } + + rust_test { diff --git a/src/calls.rs b/src/calls.rs index 59ef1af..885a481 100644 --- a/src/calls.rs +++ b/src/calls.rs @@ -4,9 +4,12 @@ //! Functions to make PSCI calls. -use crate::error::{success_or_error_32, success_or_error_64, Error}; -use crate::smccc::{call32, call64}; use crate::{ + error::Error, + smccc::{ + call32, call64, + error::{positive_or_error_32, success_or_error_32, success_or_error_64}, + }, AffinityState, LowestAffinityLevel, MigrateType, PowerState, SuspendMode, PSCI_AFFINITY_INFO_64, PSCI_CPU_DEFAULT_SUSPEND_64, PSCI_CPU_FREEZE, PSCI_CPU_OFF, PSCI_CPU_ON_64, PSCI_CPU_SUSPEND_64, PSCI_FEATURES, PSCI_MEM_PROTECT, @@ -18,7 +21,7 @@ use crate::{ /// Returns the version of PSCI implemented. pub fn version() -> u32 { - call32(PSCI_VERSION, [0, 0, 0, 0, 0, 0, 0])[0] + call32(PSCI_VERSION, [0; 7])[0] } /// Suspends execution of a core or topology node. @@ -55,7 +58,7 @@ pub fn cpu_suspend( /// Powers down the current core. pub fn cpu_off() -> Result<(), Error> { - success_or_error_32(call32(PSCI_CPU_OFF, [0, 0, 0, 0, 0, 0, 0])[0]) + success_or_error_32(call32(PSCI_CPU_OFF, [0; 7])[0]) } /// Powers up a core. @@ -128,25 +131,22 @@ pub fn migrate(target_cpu: u64) -> Result<(), Error> { /// Identifies the levelof multicore support in the Trusted OS. pub fn migrate_info_type() -> Result<MigrateType, Error> { - (call32(PSCI_MIGRATE_INFO_TYPE, [0, 0, 0, 0, 0, 0, 0])[0] as i32).try_into() + (call32(PSCI_MIGRATE_INFO_TYPE, [0; 7])[0] as i32).try_into() } /// Returns the MPIDR value of the current resident core of the Trusted OS. pub fn migrate_info_up_cpu() -> u64 { - call64( - PSCI_MIGRATE_INFO_UP_CPU_64, - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - )[0] + call64(PSCI_MIGRATE_INFO_UP_CPU_64, [0; 17])[0] } /// Shuts down the system. pub fn system_off() -> Result<(), Error> { - success_or_error_32(call32(PSCI_SYSTEM_OFF, [0, 0, 0, 0, 0, 0, 0])[0]) + success_or_error_32(call32(PSCI_SYSTEM_OFF, [0; 7])[0]) } /// Resets the system. pub fn system_reset() -> Result<(), Error> { - success_or_error_32(call32(PSCI_SYSTEM_RESET, [0, 0, 0, 0, 0, 0, 0])[0]) + success_or_error_32(call32(PSCI_SYSTEM_RESET, [0; 7])[0]) } /// Resets the system in an architectural or vendor-specific way. @@ -199,17 +199,12 @@ pub fn mem_protect_check_range(base: u64, length: u64) -> Result<(), Error> { /// Queries whether `SMCCC_VERSION` or a specific PSCI function is implemented, and what features /// are supported. pub fn psci_features(psci_function_id: u32) -> Result<u32, Error> { - let result = call32(PSCI_FEATURES, [psci_function_id, 0, 0, 0, 0, 0, 0])[0] as i32; - if result >= 0 { - Ok(result as u32) - } else { - Err(result.into()) - } + positive_or_error_32(call32(PSCI_FEATURES, [psci_function_id, 0, 0, 0, 0, 0, 0])[0]) } /// Puts the current core into an implementation-defined low power state. pub fn cpu_freeze() -> Result<(), Error> { - success_or_error_32(call32(PSCI_CPU_FREEZE, [0, 0, 0, 0, 0, 0, 0])[0]) + success_or_error_32(call32(PSCI_CPU_FREEZE, [0; 7])[0]) } /// Puts the current core into an implementation-defined low power state. diff --git a/src/error.rs b/src/error.rs index da1fa80..fb57fe6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,7 +4,9 @@ //! PSCI error codes. -pub const SUCCESS: i32 = 0; +pub use crate::smccc::error::SUCCESS; +use core::fmt::{self, Display, Formatter}; + pub const NOT_SUPPORTED: i32 = -1; pub const INVALID_PARAMETERS: i32 = -2; pub const DENIED: i32 = -3; @@ -18,35 +20,28 @@ pub const INVALID_ADDRESS: i32 = -9; /// Standard PSCI errors. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Error { + /// PSCI call not supported. NotSupported, + /// Invalid parameters to PSCI call. InvalidParameters, + /// PSCI call denied. Denied, + /// Core already on. AlreadyOn, + /// Core already being turned on. OnPending, + /// Internal failure in PSCI call. InternalFailure, + /// Trusted OS not present on target core. NotPresent, + /// Core disabled. Disabled, + /// Invalid address passed to PSCI call. InvalidAddress, /// An unexpected return value from a PSCI function. Unknown(i32), } -pub(crate) fn success_or_error_32(value: u32) -> Result<(), Error> { - success_or_error(value as i32) -} - -pub(crate) fn success_or_error_64(value: u64) -> Result<(), Error> { - success_or_error(value as i32) -} - -fn success_or_error(value: i32) -> Result<(), Error> { - if value == SUCCESS { - Ok(()) - } else { - Err(value.into()) - } -} - impl From<Error> for i32 { fn from(error: Error) -> i32 { match error { @@ -64,6 +59,12 @@ impl From<Error> for i32 { } } +impl From<Error> for i64 { + fn from(error: Error) -> i64 { + i32::from(error).into() + } +} + impl From<i32> for Error { fn from(value: i32) -> Self { match value { @@ -80,3 +81,26 @@ impl From<i32> for Error { } } } + +impl From<i64> for Error { + fn from(value: i64) -> Self { + Self::from(value as i32) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::NotSupported => write!(f, "PSCI call not supported"), + Self::InvalidParameters => write!(f, "Invalid parameters to PSCI call"), + Self::Denied => write!(f, "PSCI call denied"), + Self::AlreadyOn => write!(f, "Core already on"), + Self::OnPending => write!(f, "Core already being turned on"), + Self::InternalFailure => write!(f, "Internal failure in PSCI call"), + Self::NotPresent => write!(f, "Trusted OS not present on target core"), + Self::Disabled => write!(f, "Core disabled"), + Self::InvalidAddress => write!(f, "Invalid address passed to PSCI call"), + Self::Unknown(e) => write!(f, "Unknown PSCI return value {} ({0:#x})", e), + } + } +} @@ -2,13 +2,13 @@ // This project is dual-licensed under Apache 2.0 and MIT terms. // See LICENSE-APACHE and LICENSE-MIT for details. -//! Constants for version 1.1 of the Arm Power State Coordination Interface (PSCI) version 1.1, and -//! functions to call them. +//! Constants for version 1.4 of the Arm SMC Calling Convention and version 1.1 of the Arm Power +//! State Coordination Interface (PSCI) version 1.1, and functions to call them. //! -//! Note that PSCI calls may be made via either HVC or SMC. You can choose which one to use by -//! building this crate with the corresponding feature (i.e. `hvc` or `smc`). By default `hvc` is -//! enabled. If neither feature is enabled then the functions to make calls will not be available, -//! but the constants are still provided. +//! Note that PSCI and other SMCCC calls may be made via either HVC or SMC. You can choose which one +//! to use by building this crate with the corresponding feature (i.e. `hvc` or `smc`). By default +//! `hvc` is enabled. If neither feature is enabled then the functions to make calls will not be +//! available, but the constants and types are still provided. //! //! This crate currently only supports aarch64 and the SMC64 versions of the various calls, in the //! cases that both SMC32 and SMC64 versions exist. diff --git a/src/smccc.rs b/src/smccc.rs index 4b1b4a4..01ff00f 100644 --- a/src/smccc.rs +++ b/src/smccc.rs @@ -4,6 +4,9 @@ //! Functions for making SMCCC calls. +pub mod arch; +pub mod error; + #[cfg(any(feature = "hvc", feature = "smc"))] #[inline(always)] pub(crate) fn call32(function: u32, args: [u32; 7]) -> [u32; 8] { diff --git a/src/smccc/arch.rs b/src/smccc/arch.rs new file mode 100644 index 0000000..feaf590 --- /dev/null +++ b/src/smccc/arch.rs @@ -0,0 +1,90 @@ +// Copyright 2023 the authors. +// This project is dual-licensed under Apache 2.0 and MIT terms. +// See LICENSE-APACHE and LICENSE-MIT for details. + +//! Standard Arm architecture calls. + +#[cfg(any(feature = "hvc", feature = "smc"))] +mod calls; +pub mod error; + +#[cfg(any(feature = "hvc", feature = "smc"))] +pub use calls::{ + arch_workaround_1, arch_workaround_2, arch_workaround_3, features, soc_id, version, +}; +use core::fmt::{self, Debug, Display, Formatter}; +use error::Error; + +pub const SMCCC_VERSION: u32 = 0x8000_0000; +pub const SMCCC_ARCH_FEATURES: u32 = 0x8000_0001; +pub const SMCCC_ARCH_SOC_ID: u32 = 0x8000_0002; +pub const SMCCC_ARCH_WORKAROUND_1: u32 = 0x8000_8000; +pub const SMCCC_ARCH_WORKAROUND_2: u32 = 0x8000_7FFF; +pub const SMCCC_ARCH_WORKAROUND_3: u32 = 0x8000_3FFF; + +/// A version of the SMC Calling Convention. +#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] +pub struct Version { + pub major: u16, + pub minor: u16, +} + +impl Display for Version { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}.{}", self.major, self.minor) + } +} + +impl Debug for Version { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + Display::fmt(self, f) + } +} + +impl TryFrom<i32> for Version { + type Error = Error; + + fn try_from(value: i32) -> Result<Self, Error> { + if value < 0 { + Err(value.into()) + } else { + Ok(Self { + major: (value >> 16) as u16, + minor: value as u16, + }) + } + } +} + +impl From<Version> for u32 { + fn from(version: Version) -> Self { + u32::from(version.major) << 16 | u32::from(version.minor) + } +} + +#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] +#[repr(u32)] +pub enum SocIdType { + /// The SoC version. + Version, + /// The SoC revision. + Revision, +} + +impl From<SocIdType> for u32 { + fn from(id_type: SocIdType) -> Self { + id_type as Self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn convert_version() { + let version = Version { major: 1, minor: 2 }; + assert_eq!(u32::from(version), 0x0001_0002); + assert_eq!(0x0001_0002.try_into(), Ok(version)); + } +} diff --git a/src/smccc/arch/calls.rs b/src/smccc/arch/calls.rs new file mode 100644 index 0000000..0164616 --- /dev/null +++ b/src/smccc/arch/calls.rs @@ -0,0 +1,43 @@ +// Copyright 2023 the authors. +// This project is dual-licensed under Apache 2.0 and MIT terms. +// See LICENSE-APACHE and LICENSE-MIT for details. + +use super::{ + error::Error, SocIdType, Version, SMCCC_ARCH_FEATURES, SMCCC_ARCH_SOC_ID, + SMCCC_ARCH_WORKAROUND_1, SMCCC_ARCH_WORKAROUND_2, SMCCC_ARCH_WORKAROUND_3, SMCCC_VERSION, +}; +use crate::smccc::{ + call32, + error::{positive_or_error_32, success_or_error_32}, +}; + +/// Returns the implemented version of the SMC Calling Convention. +pub fn version() -> Result<Version, Error> { + (call32(SMCCC_VERSION, [0; 7])[0] as i32).try_into() +} + +/// Returns whether the given Arm Architecture Service function is implemented, and any feature +/// flags specific to the function. +pub fn features(arch_func_id: u32) -> Result<u32, Error> { + positive_or_error_32(call32(SMCCC_ARCH_FEATURES, [arch_func_id, 0, 0, 0, 0, 0, 0])[0]) +} + +/// Returns the SiP defined SoC identification details. +pub fn soc_id(soc_id_type: SocIdType) -> Result<u32, Error> { + positive_or_error_32(call32(SMCCC_ARCH_SOC_ID, [soc_id_type.into(), 0, 0, 0, 0, 0, 0])[0]) +} + +/// Executes a firmware workaround to mitigate CVE-2017-5715. +pub fn arch_workaround_1() -> Result<(), Error> { + success_or_error_32(call32(SMCCC_ARCH_WORKAROUND_1, [0; 7])[0]) +} + +/// Enables or disables the mitigation for CVE-2018-3639. +pub fn arch_workaround_2(enable: bool) -> Result<(), Error> { + success_or_error_32(call32(SMCCC_ARCH_WORKAROUND_2, [enable.into(), 0, 0, 0, 0, 0, 0])[0]) +} + +/// Executes a firmware workaround to mitigate CVE-2017-5715 and CVE-2022-23960. +pub fn arch_workaround_3() -> Result<(), Error> { + success_or_error_32(call32(SMCCC_ARCH_WORKAROUND_3, [0; 7])[0]) +} diff --git a/src/smccc/arch/error.rs b/src/smccc/arch/error.rs new file mode 100644 index 0000000..fa2fd4b --- /dev/null +++ b/src/smccc/arch/error.rs @@ -0,0 +1,58 @@ +// Copyright 2023 the authors. +// This project is dual-licensed under Apache 2.0 and MIT terms. +// See LICENSE-APACHE and LICENSE-MIT for details. + +//! Error codes for standard Arm Architecture SMCCC calls. + +pub use crate::smccc::error::SUCCESS; +use core::fmt::{self, Display, Formatter}; + +pub const NOT_SUPPORTED: i32 = -1; +pub const NOT_REQUIRED: i32 = -2; +pub const INVALID_PARAMETER: i32 = -3; + +/// Errors for standard Arm Architecture calls. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +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, + /// There was an unexpected return value. + Unknown(i32), +} + +impl From<Error> for i32 { + fn from(error: Error) -> i32 { + match error { + Error::NotSupported => NOT_SUPPORTED, + Error::NotRequired => NOT_REQUIRED, + Error::InvalidParameter => INVALID_PARAMETER, + Error::Unknown(value) => value, + } + } +} + +impl From<i32> for Error { + fn from(value: i32) -> Self { + match value { + NOT_SUPPORTED => Error::NotSupported, + NOT_REQUIRED => Error::NotRequired, + INVALID_PARAMETER => Error::InvalidParameter, + _ => Error::Unknown(value), + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut 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::Unknown(e) => write!(f, "Unknown SMCCC return value {} ({0:#x})", e), + } + } +} diff --git a/src/smccc/error.rs b/src/smccc/error.rs new file mode 100644 index 0000000..2fce48a --- /dev/null +++ b/src/smccc/error.rs @@ -0,0 +1,75 @@ +// Copyright 2023 the authors. +// This project is dual-licensed under Apache 2.0 and MIT terms. +// See LICENSE-APACHE and LICENSE-MIT for details. + +//! Utility functions for error handling. +//! +//! These functions can be combined with the appropriate HVC or SMC functions to wrap calls which +//! return a single value where negative values indicate an error. +//! +//! For example, the [`system_off`](crate::system_off) function is implemented approximately as: +//! +//! ``` +//! use psci::{ +//! error::Error, +//! smccc::{error::success_or_error_32, smc32}, +//! PSCI_SYSTEM_OFF, +//! }; +//! +//! pub fn system_off() -> Result<(), Error> { +//! success_or_error_32(smc32(PSCI_SYSTEM_OFF, [0; 7])[0]) +//! } +//! ``` + +/// A value commonly returned to indicate a successful SMCCC call. +pub const SUCCESS: i32 = 0; + +/// Converts the given value (returned from an HVC32 or SMC32 call) either to `Ok(())` if it is +/// equal to [`SUCCESS`], or else an error of the given type. +pub fn success_or_error_32<E: From<i32>>(value: u32) -> Result<(), E> { + let value = value as i32; + if value == SUCCESS { + Ok(()) + } else { + Err(value.into()) + } +} + +/// Converts the given value (returned from an HVC64 or SMC64 call) either to `Ok(())` if it is +/// equal to [`SUCCESS`], or else an error of the given type. +pub fn success_or_error_64<E: From<i64>>(value: u64) -> Result<(), E> { + let value = value as i64; + if value == SUCCESS.into() { + Ok(()) + } else { + Err(value.into()) + } +} + +/// Returns `Ok(value)` if the given value has its high bit unset (i.e. would be positive when +/// treated as a signed value), or an error of the given type if the high bit is set. +/// +/// This is intended to be used with the return value of [`hvc32`](super::hvc32) or +/// [`smc32`](super::smc32). +pub fn positive_or_error_32<E: From<i32>>(value: u32) -> Result<u32, E> { + let signed = value as i32; + if signed < 0 { + Err(signed.into()) + } else { + Ok(value) + } +} + +/// Returns `Ok(value)` if the given value has its high bit unset (i.e. would be positive when +/// treated as a signed value), or an error of the given type if the high bit is set. +/// +/// This is intended to be used with the return value of [`hvc64`](super::hvc64) or +/// [`smc64`](super::smc64). +pub fn positive_or_error_64<E: From<i64>>(value: u64) -> Result<u64, E> { + let signed = value as i64; + if signed < 0 { + Err(signed.into()) + } else { + Ok(value) + } +} |