blob: 2857ebf1ad08bd54ce04c65b99ac12fcb3adb08c [file] [log] [blame]
// 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
}
}