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
16 pub mod arch;
17 pub mod error;
18 pub mod psci;
19
20 /// Use a Hypervisor Call (HVC).
21 #[cfg(target_arch = "aarch64")]
22 pub struct Hvc;
23
24 /// Use a Secure Moniter Call (SMC).
25 #[cfg(target_arch = "aarch64")]
26 pub struct Smc;
27
28 /// Functions to make an HVC or SMC call.
29 pub trait Call {
30 /// Makes a call using the 32-bit calling convention.
call32(function: u32, args: [u32; 7]) -> [u32; 8]31 fn call32(function: u32, args: [u32; 7]) -> [u32; 8];
32 /// Makes a call using the 64-bit calling convention.
call64(function: u32, args: [u64; 17]) -> [u64; 18]33 fn call64(function: u32, args: [u64; 17]) -> [u64; 18];
34 }
35
36 #[cfg(target_arch = "aarch64")]
37 impl Call for Hvc {
call32(function: u32, args: [u32; 7]) -> [u32; 8]38 fn call32(function: u32, args: [u32; 7]) -> [u32; 8] {
39 hvc32(function, args)
40 }
41
call64(function: u32, args: [u64; 17]) -> [u64; 18]42 fn call64(function: u32, args: [u64; 17]) -> [u64; 18] {
43 hvc64(function, args)
44 }
45 }
46
47 #[cfg(target_arch = "aarch64")]
48 impl Call for Smc {
call32(function: u32, args: [u32; 7]) -> [u32; 8]49 fn call32(function: u32, args: [u32; 7]) -> [u32; 8] {
50 smc32(function, args)
51 }
52
call64(function: u32, args: [u64; 17]) -> [u64; 18]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)]
hvc32(function: u32, args: [u32; 7]) -> [u32; 8]61 pub 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)]
smc32(function: u32, args: [u32; 7]) -> [u32; 8]85 pub 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)]
hvc64(function: u32, args: [u64; 17]) -> [u64; 18]109 pub 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)]
smc64(function: u32, args: [u64; 17]) -> [u64; 18]143 pub 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 }
173