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