smccc/
lib.rs

1// Copyright 2022 the authors.
2// This project is dual-licensed under Apache 2.0 and MIT terms.
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5//! Functions for version 1.4 of the Arm SMC Calling Convention and version 1.1 of the Arm Power
6//! State Coordination Interface (PSCI) version 1.1, and relevant constants.
7//!
8//! Note that the PSCI and SMCCC arch calls may be made via either HVC or SMC. You can choose which
9//! one to use by passing either [`Hvc`] or [`Smc`] as a type parameter to the relevant function.
10//!
11//! This crate currently only supports aarch64 and the SMC64 versions of the PSCI calls, in the
12//! cases that both SMC32 and SMC64 versions exist.
13
14#![no_std]
15
16pub mod arch;
17pub mod error;
18pub mod psci;
19
20/// Use a Hypervisor Call (HVC).
21#[cfg(target_arch = "aarch64")]
22pub struct Hvc;
23
24/// Use a Secure Moniter Call (SMC).
25#[cfg(target_arch = "aarch64")]
26pub struct Smc;
27
28/// Functions to make an HVC or SMC call.
29pub trait Call {
30    /// Makes a call using the 32-bit calling convention.
31    fn call32(function: u32, args: [u32; 7]) -> [u32; 8];
32    /// Makes a call using the 64-bit calling convention.
33    fn call64(function: u32, args: [u64; 17]) -> [u64; 18];
34}
35
36#[cfg(target_arch = "aarch64")]
37impl Call for Hvc {
38    fn call32(function: u32, args: [u32; 7]) -> [u32; 8] {
39        hvc32(function, args)
40    }
41
42    fn call64(function: u32, args: [u64; 17]) -> [u64; 18] {
43        hvc64(function, args)
44    }
45}
46
47#[cfg(target_arch = "aarch64")]
48impl Call for Smc {
49    fn call32(function: u32, args: [u32; 7]) -> [u32; 8] {
50        smc32(function, args)
51    }
52
53    fn call64(function: u32, args: [u64; 17]) -> [u64; 18] {
54        smc64(function, args)
55    }
56}
57
58/// Makes an HVC32 call to the hypervisor, following the SMC Calling Convention version 1.3.
59#[cfg(target_arch = "aarch64")]
60#[inline(always)]
61pub fn hvc32(function: u32, args: [u32; 7]) -> [u32; 8] {
62    unsafe {
63        let mut ret = [0; 8];
64
65        core::arch::asm!(
66            "hvc #0",
67            inout("w0") function => ret[0],
68            inout("w1") args[0] => ret[1],
69            inout("w2") args[1] => ret[2],
70            inout("w3") args[2] => ret[3],
71            inout("w4") args[3] => ret[4],
72            inout("w5") args[4] => ret[5],
73            inout("w6") args[5] => ret[6],
74            inout("w7") args[6] => ret[7],
75            options(nomem, nostack)
76        );
77
78        ret
79    }
80}
81
82/// Makes an SMC32 call to the firmware, following the SMC Calling Convention version 1.3.
83#[cfg(target_arch = "aarch64")]
84#[inline(always)]
85pub fn smc32(function: u32, args: [u32; 7]) -> [u32; 8] {
86    unsafe {
87        let mut ret = [0; 8];
88
89        core::arch::asm!(
90            "smc #0",
91            inout("w0") function => ret[0],
92            inout("w1") args[0] => ret[1],
93            inout("w2") args[1] => ret[2],
94            inout("w3") args[2] => ret[3],
95            inout("w4") args[3] => ret[4],
96            inout("w5") args[4] => ret[5],
97            inout("w6") args[5] => ret[6],
98            inout("w7") args[6] => ret[7],
99            options(nomem, nostack)
100        );
101
102        ret
103    }
104}
105
106/// Makes an HVC64 call to the hypervisor, following the SMC Calling Convention version 1.3.
107#[cfg(target_arch = "aarch64")]
108#[inline(always)]
109pub fn hvc64(function: u32, args: [u64; 17]) -> [u64; 18] {
110    unsafe {
111        let mut ret = [0; 18];
112
113        core::arch::asm!(
114            "hvc #0",
115            inout("x0") function as u64 => ret[0],
116            inout("x1") args[0] => ret[1],
117            inout("x2") args[1] => ret[2],
118            inout("x3") args[2] => ret[3],
119            inout("x4") args[3] => ret[4],
120            inout("x5") args[4] => ret[5],
121            inout("x6") args[5] => ret[6],
122            inout("x7") args[6] => ret[7],
123            inout("x8") args[7] => ret[8],
124            inout("x9") args[8] => ret[9],
125            inout("x10") args[9] => ret[10],
126            inout("x11") args[10] => ret[11],
127            inout("x12") args[11] => ret[12],
128            inout("x13") args[12] => ret[13],
129            inout("x14") args[13] => ret[14],
130            inout("x15") args[14] => ret[15],
131            inout("x16") args[15] => ret[16],
132            inout("x17") args[16] => ret[17],
133            options(nomem, nostack)
134        );
135
136        ret
137    }
138}
139
140/// Makes an SMC64 call to the firmware, following the SMC Calling Convention version 1.3.
141#[cfg(target_arch = "aarch64")]
142#[inline(always)]
143pub fn smc64(function: u32, args: [u64; 17]) -> [u64; 18] {
144    unsafe {
145        let mut ret = [0; 18];
146
147        core::arch::asm!(
148            "smc #0",
149            inout("x0") function as u64 => ret[0],
150            inout("x1") args[0] => ret[1],
151            inout("x2") args[1] => ret[2],
152            inout("x3") args[2] => ret[3],
153            inout("x4") args[3] => ret[4],
154            inout("x5") args[4] => ret[5],
155            inout("x6") args[5] => ret[6],
156            inout("x7") args[6] => ret[7],
157            inout("x8") args[7] => ret[8],
158            inout("x9") args[8] => ret[9],
159            inout("x10") args[9] => ret[10],
160            inout("x11") args[10] => ret[11],
161            inout("x12") args[11] => ret[12],
162            inout("x13") args[12] => ret[13],
163            inout("x14") args[13] => ret[14],
164            inout("x15") args[14] => ret[15],
165            inout("x16") args[15] => ret[16],
166            inout("x17") args[16] => ret[17],
167            options(nomem, nostack)
168        );
169
170        ret
171    }
172}