| // Copyright 2022 the authors. |
| // This project is dual-licensed under Apache 2.0 and MIT terms. |
| // See LICENSE-APACHE and LICENSE-MIT for details. |
| |
| //! Functions 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 relevant constants. |
| //! |
| //! Note that the PSCI and SMCCC arch calls may be made via either HVC or SMC. You can choose which |
| //! one to use by passing either [`Hvc`] or [`Smc`] as a type parameter to the relevant function. |
| //! |
| //! This crate currently only supports aarch64 and the SMC64 versions of the PSCI calls, in the |
| //! cases that both SMC32 and SMC64 versions exist. |
| |
| #![no_std] |
| |
| pub mod arch; |
| pub mod error; |
| pub mod psci; |
| |
| /// Use a Hypervisor Call (HVC). |
| #[cfg(target_arch = "aarch64")] |
| pub struct Hvc; |
| |
| /// Use a Secure Moniter Call (SMC). |
| #[cfg(target_arch = "aarch64")] |
| pub struct Smc; |
| |
| /// Functions to make an HVC or SMC call. |
| pub trait Call { |
| /// Makes a call using the 32-bit calling convention. |
| fn call32(function: u32, args: [u32; 7]) -> [u32; 8]; |
| /// Makes a call using the 64-bit calling convention. |
| fn call64(function: u32, args: [u64; 17]) -> [u64; 18]; |
| } |
| |
| #[cfg(target_arch = "aarch64")] |
| impl Call for Hvc { |
| fn call32(function: u32, args: [u32; 7]) -> [u32; 8] { |
| hvc32(function, args) |
| } |
| |
| fn call64(function: u32, args: [u64; 17]) -> [u64; 18] { |
| hvc64(function, args) |
| } |
| } |
| |
| #[cfg(target_arch = "aarch64")] |
| impl Call for Smc { |
| fn call32(function: u32, args: [u32; 7]) -> [u32; 8] { |
| smc32(function, args) |
| } |
| |
| fn call64(function: u32, args: [u64; 17]) -> [u64; 18] { |
| smc64(function, args) |
| } |
| } |
| |
| /// Makes an HVC32 call to the hypervisor, following the SMC Calling Convention version 1.3. |
| #[cfg(target_arch = "aarch64")] |
| #[inline(always)] |
| pub fn hvc32(function: u32, args: [u32; 7]) -> [u32; 8] { |
| unsafe { |
| let mut ret = [0; 8]; |
| |
| core::arch::asm!( |
| "hvc #0", |
| inout("w0") function => ret[0], |
| inout("w1") args[0] => ret[1], |
| inout("w2") args[1] => ret[2], |
| inout("w3") args[2] => ret[3], |
| inout("w4") args[3] => ret[4], |
| inout("w5") args[4] => ret[5], |
| inout("w6") args[5] => ret[6], |
| inout("w7") args[6] => ret[7], |
| options(nomem, nostack) |
| ); |
| |
| ret |
| } |
| } |
| |
| /// Makes an SMC32 call to the firmware, following the SMC Calling Convention version 1.3. |
| #[cfg(target_arch = "aarch64")] |
| #[inline(always)] |
| pub fn smc32(function: u32, args: [u32; 7]) -> [u32; 8] { |
| unsafe { |
| let mut ret = [0; 8]; |
| |
| core::arch::asm!( |
| "smc #0", |
| inout("w0") function => ret[0], |
| inout("w1") args[0] => ret[1], |
| inout("w2") args[1] => ret[2], |
| inout("w3") args[2] => ret[3], |
| inout("w4") args[3] => ret[4], |
| inout("w5") args[4] => ret[5], |
| inout("w6") args[5] => ret[6], |
| inout("w7") args[6] => ret[7], |
| options(nomem, nostack) |
| ); |
| |
| ret |
| } |
| } |
| |
| /// Makes an HVC64 call to the hypervisor, following the SMC Calling Convention version 1.3. |
| #[cfg(target_arch = "aarch64")] |
| #[inline(always)] |
| pub fn hvc64(function: u32, args: [u64; 17]) -> [u64; 18] { |
| unsafe { |
| let mut ret = [0; 18]; |
| |
| core::arch::asm!( |
| "hvc #0", |
| inout("x0") function as u64 => ret[0], |
| inout("x1") args[0] => ret[1], |
| inout("x2") args[1] => ret[2], |
| inout("x3") args[2] => ret[3], |
| inout("x4") args[3] => ret[4], |
| inout("x5") args[4] => ret[5], |
| inout("x6") args[5] => ret[6], |
| inout("x7") args[6] => ret[7], |
| inout("x8") args[7] => ret[8], |
| inout("x9") args[8] => ret[9], |
| inout("x10") args[9] => ret[10], |
| inout("x11") args[10] => ret[11], |
| inout("x12") args[11] => ret[12], |
| inout("x13") args[12] => ret[13], |
| inout("x14") args[13] => ret[14], |
| inout("x15") args[14] => ret[15], |
| inout("x16") args[15] => ret[16], |
| inout("x17") args[16] => ret[17], |
| options(nomem, nostack) |
| ); |
| |
| ret |
| } |
| } |
| |
| /// Makes an SMC64 call to the firmware, following the SMC Calling Convention version 1.3. |
| #[cfg(target_arch = "aarch64")] |
| #[inline(always)] |
| pub fn smc64(function: u32, args: [u64; 17]) -> [u64; 18] { |
| unsafe { |
| let mut ret = [0; 18]; |
| |
| core::arch::asm!( |
| "smc #0", |
| inout("x0") function as u64 => ret[0], |
| inout("x1") args[0] => ret[1], |
| inout("x2") args[1] => ret[2], |
| inout("x3") args[2] => ret[3], |
| inout("x4") args[3] => ret[4], |
| inout("x5") args[4] => ret[5], |
| inout("x6") args[5] => ret[6], |
| inout("x7") args[6] => ret[7], |
| inout("x8") args[7] => ret[8], |
| inout("x9") args[8] => ret[9], |
| inout("x10") args[9] => ret[10], |
| inout("x11") args[10] => ret[11], |
| inout("x12") args[11] => ret[12], |
| inout("x13") args[12] => ret[13], |
| inout("x14") args[13] => ret[14], |
| inout("x15") args[14] => ret[15], |
| inout("x16") args[15] => ret[16], |
| inout("x17") args[16] => ret[17], |
| options(nomem, nostack) |
| ); |
| |
| ret |
| } |
| } |