Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 1 | // Copyright 2022, The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
Pierre-Clément Tosi | 8cb2317 | 2022-10-19 16:38:25 +0100 | [diff] [blame] | 15 | use core::{fmt, result}; |
Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 16 | |
| 17 | // TODO(b/245889995): use psci-0.1.1 crate |
| 18 | #[inline(always)] |
Pierre-Clément Tosi | a59103d | 2023-02-02 14:46:55 +0000 | [diff] [blame] | 19 | pub fn hvc64(function: u32, args: [u64; 17]) -> [u64; 18] { |
Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 20 | #[cfg(target_arch = "aarch64")] |
| 21 | unsafe { |
| 22 | let mut ret = [0; 18]; |
| 23 | |
| 24 | core::arch::asm!( |
| 25 | "hvc #0", |
| 26 | inout("x0") function as u64 => ret[0], |
| 27 | inout("x1") args[0] => ret[1], |
| 28 | inout("x2") args[1] => ret[2], |
| 29 | inout("x3") args[2] => ret[3], |
| 30 | inout("x4") args[3] => ret[4], |
| 31 | inout("x5") args[4] => ret[5], |
| 32 | inout("x6") args[5] => ret[6], |
| 33 | inout("x7") args[6] => ret[7], |
| 34 | inout("x8") args[7] => ret[8], |
| 35 | inout("x9") args[8] => ret[9], |
| 36 | inout("x10") args[9] => ret[10], |
| 37 | inout("x11") args[10] => ret[11], |
| 38 | inout("x12") args[11] => ret[12], |
| 39 | inout("x13") args[12] => ret[13], |
| 40 | inout("x14") args[13] => ret[14], |
| 41 | inout("x15") args[14] => ret[15], |
| 42 | inout("x16") args[15] => ret[16], |
| 43 | inout("x17") args[16] => ret[17], |
| 44 | options(nomem, nostack) |
| 45 | ); |
| 46 | |
| 47 | ret |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | /// Standard SMCCC error values as described in DEN 0028E. |
| 52 | #[derive(Debug, Clone)] |
| 53 | pub enum Error { |
| 54 | /// The call is not supported by the implementation. |
| 55 | NotSupported, |
| 56 | /// The call is deemed not required by the implementation. |
| 57 | NotRequired, |
| 58 | /// One of the call parameters has a non-supported value. |
| 59 | InvalidParameter, |
| 60 | /// Negative values indicate error. |
| 61 | Unknown(i64), |
| 62 | /// The call returned a positive value when 0 was expected. |
| 63 | Unexpected(u64), |
| 64 | } |
| 65 | |
| 66 | impl fmt::Display for Error { |
| 67 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 68 | match self { |
| 69 | Self::NotSupported => write!(f, "SMCCC call not supported"), |
| 70 | Self::NotRequired => write!(f, "SMCCC call not required"), |
| 71 | Self::InvalidParameter => write!(f, "SMCCC call received non-supported value"), |
Pierre-Clément Tosi | 4cd3f0d | 2022-10-17 13:26:28 +0100 | [diff] [blame] | 72 | Self::Unexpected(v) => write!(f, "Unexpected SMCCC return value {} ({0:#x})", v), |
| 73 | Self::Unknown(e) => write!(f, "Unknown SMCCC return value {} ({0:#x})", e), |
Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 74 | } |
| 75 | } |
| 76 | } |
| 77 | |
Pierre-Clément Tosi | 6c4c4f7 | 2022-10-21 16:44:16 +0100 | [diff] [blame] | 78 | pub type Result<T> = result::Result<T, Error>; |
Pierre-Clément Tosi | 8cb2317 | 2022-10-19 16:38:25 +0100 | [diff] [blame] | 79 | |
Pierre-Clément Tosi | 6c4c4f7 | 2022-10-21 16:44:16 +0100 | [diff] [blame] | 80 | pub fn checked_hvc64_expect_zero(function: u32, args: [u64; 17]) -> Result<()> { |
| 81 | match checked_hvc64(function, args)? { |
Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 82 | 0 => Ok(()), |
| 83 | v => Err(Error::Unexpected(v)), |
| 84 | } |
| 85 | } |
| 86 | |
Pierre-Clément Tosi | 6c4c4f7 | 2022-10-21 16:44:16 +0100 | [diff] [blame] | 87 | pub fn checked_hvc64(function: u32, args: [u64; 17]) -> Result<u64> { |
| 88 | match hvc64(function, args)[0] as i64 { |
| 89 | ret if ret >= 0 => Ok(ret as u64), |
Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 90 | -1 => Err(Error::NotSupported), |
| 91 | -2 => Err(Error::NotRequired), |
| 92 | -3 => Err(Error::InvalidParameter), |
Pierre-Clément Tosi | 6c4c4f7 | 2022-10-21 16:44:16 +0100 | [diff] [blame] | 93 | ret => Err(Error::Unknown(ret)), |
Pierre-Clément Tosi | da4440a | 2022-08-22 18:06:32 +0100 | [diff] [blame] | 94 | } |
| 95 | } |