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 to make PSCI calls.
6
7 use super::{
8 error::Error, AffinityState, LowestAffinityLevel, MigrateType, PowerState, SuspendMode,
9 PSCI_AFFINITY_INFO_64, PSCI_CPU_DEFAULT_SUSPEND_64, PSCI_CPU_FREEZE, PSCI_CPU_OFF,
10 PSCI_CPU_ON_64, PSCI_CPU_SUSPEND_64, PSCI_FEATURES, PSCI_MEM_PROTECT,
11 PSCI_MEM_PROTECT_CHECK_RANGE_64, PSCI_MIGRATE_64, PSCI_MIGRATE_INFO_TYPE,
12 PSCI_MIGRATE_INFO_UP_CPU_64, PSCI_NODE_HW_STATE_64, PSCI_SET_SUSPEND_MODE, PSCI_STAT_COUNT_64,
13 PSCI_STAT_RESIDENCY_64, PSCI_SYSTEM_OFF, PSCI_SYSTEM_RESET, PSCI_SYSTEM_RESET2_64,
14 PSCI_SYSTEM_SUSPEND_64, PSCI_VERSION,
15 };
16 use crate::{
17 error::{positive_or_error_32, success_or_error_32, success_or_error_64},
18 Call,
19 };
20
21 /// Returns the version of PSCI implemented.
version<C: Call>() -> u3222 pub fn version<C: Call>() -> u32 {
23 C::call32(PSCI_VERSION, [0; 7])[0]
24 }
25
26 /// Suspends execution of a core or topology node.
cpu_suspend<C: Call>( power_state: u32, entry_point_address: u64, context_id: u64, ) -> Result<(), Error>27 pub fn cpu_suspend<C: Call>(
28 power_state: u32,
29 entry_point_address: u64,
30 context_id: u64,
31 ) -> Result<(), Error> {
32 success_or_error_64(
33 C::call64(
34 PSCI_CPU_SUSPEND_64,
35 [
36 power_state.into(),
37 entry_point_address,
38 context_id,
39 0,
40 0,
41 0,
42 0,
43 0,
44 0,
45 0,
46 0,
47 0,
48 0,
49 0,
50 0,
51 0,
52 0,
53 ],
54 )[0],
55 )
56 }
57
58 /// Powers down the current core.
cpu_off<C: Call>() -> Result<(), Error>59 pub fn cpu_off<C: Call>() -> Result<(), Error> {
60 success_or_error_32(C::call32(PSCI_CPU_OFF, [0; 7])[0])
61 }
62
63 /// Powers up a core.
cpu_on<C: Call>( target_cpu: u64, entry_point_address: u64, context_id: u64, ) -> Result<(), Error>64 pub fn cpu_on<C: Call>(
65 target_cpu: u64,
66 entry_point_address: u64,
67 context_id: u64,
68 ) -> Result<(), Error> {
69 success_or_error_64(
70 C::call64(
71 PSCI_CPU_ON_64,
72 [
73 target_cpu,
74 entry_point_address,
75 context_id,
76 0,
77 0,
78 0,
79 0,
80 0,
81 0,
82 0,
83 0,
84 0,
85 0,
86 0,
87 0,
88 0,
89 0,
90 ],
91 )[0],
92 )
93 }
94
95 /// Gets the status of an affinity instance.
affinity_info<C: Call>( target_affinity: u64, lowest_affinity_level: LowestAffinityLevel, ) -> Result<AffinityState, Error>96 pub fn affinity_info<C: Call>(
97 target_affinity: u64,
98 lowest_affinity_level: LowestAffinityLevel,
99 ) -> Result<AffinityState, Error> {
100 (C::call64(
101 PSCI_AFFINITY_INFO_64,
102 [
103 target_affinity,
104 lowest_affinity_level as u64,
105 0,
106 0,
107 0,
108 0,
109 0,
110 0,
111 0,
112 0,
113 0,
114 0,
115 0,
116 0,
117 0,
118 0,
119 0,
120 ],
121 )[0] as i32)
122 .try_into()
123 }
124
125 /// Asks the Trusted OS to migrate its context to a specific core.
migrate<C: Call>(target_cpu: u64) -> Result<(), Error>126 pub fn migrate<C: Call>(target_cpu: u64) -> Result<(), Error> {
127 success_or_error_64(
128 C::call64(
129 PSCI_MIGRATE_64,
130 [target_cpu, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
131 )[0],
132 )
133 }
134
135 /// Identifies the levelof multicore support in the Trusted OS.
migrate_info_type<C: Call>() -> Result<MigrateType, Error>136 pub fn migrate_info_type<C: Call>() -> Result<MigrateType, Error> {
137 (C::call32(PSCI_MIGRATE_INFO_TYPE, [0; 7])[0] as i32).try_into()
138 }
139
140 /// Returns the MPIDR value of the current resident core of the Trusted OS.
migrate_info_up_cpu<C: Call>() -> u64141 pub fn migrate_info_up_cpu<C: Call>() -> u64 {
142 C::call64(PSCI_MIGRATE_INFO_UP_CPU_64, [0; 17])[0]
143 }
144
145 /// Shuts down the system.
system_off<C: Call>() -> Result<(), Error>146 pub fn system_off<C: Call>() -> Result<(), Error> {
147 success_or_error_32(C::call32(PSCI_SYSTEM_OFF, [0; 7])[0])
148 }
149
150 /// Resets the system.
system_reset<C: Call>() -> Result<(), Error>151 pub fn system_reset<C: Call>() -> Result<(), Error> {
152 success_or_error_32(C::call32(PSCI_SYSTEM_RESET, [0; 7])[0])
153 }
154
155 /// Resets the system in an architectural or vendor-specific way.
system_reset2<C: Call>(reset_type: u32, cookie: u64) -> Result<(), Error>156 pub fn system_reset2<C: Call>(reset_type: u32, cookie: u64) -> Result<(), Error> {
157 success_or_error_64(
158 C::call64(
159 PSCI_SYSTEM_RESET2_64,
160 [
161 reset_type.into(),
162 cookie,
163 0,
164 0,
165 0,
166 0,
167 0,
168 0,
169 0,
170 0,
171 0,
172 0,
173 0,
174 0,
175 0,
176 0,
177 0,
178 ],
179 )[0],
180 )
181 }
182
183 /// Enables or disables memory protection.
mem_protect<C: Call>(enable: bool) -> Result<bool, Error>184 pub fn mem_protect<C: Call>(enable: bool) -> Result<bool, Error> {
185 match C::call32(PSCI_MEM_PROTECT, [enable as u32, 0, 0, 0, 0, 0, 0])[0] as i32 {
186 0 => Ok(false),
187 1 => Ok(true),
188 error => Err(error.into()),
189 }
190 }
191
192 /// Checks whether a memory range is protected by `MEM_PROTECT`.
mem_protect_check_range<C: Call>(base: u64, length: u64) -> Result<(), Error>193 pub fn mem_protect_check_range<C: Call>(base: u64, length: u64) -> Result<(), Error> {
194 success_or_error_64(
195 C::call64(
196 PSCI_MEM_PROTECT_CHECK_RANGE_64,
197 [base, length, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
198 )[0],
199 )
200 }
201
202 /// Queries whether `SMCCC_VERSION` or a specific PSCI function is implemented, and what features
203 /// are supported.
psci_features<C: Call>(psci_function_id: u32) -> Result<u32, Error>204 pub fn psci_features<C: Call>(psci_function_id: u32) -> Result<u32, Error> {
205 positive_or_error_32(C::call32(PSCI_FEATURES, [psci_function_id, 0, 0, 0, 0, 0, 0])[0])
206 }
207
208 /// Puts the current core into an implementation-defined low power state.
cpu_freeze<C: Call>() -> Result<(), Error>209 pub fn cpu_freeze<C: Call>() -> Result<(), Error> {
210 success_or_error_32(C::call32(PSCI_CPU_FREEZE, [0; 7])[0])
211 }
212
213 /// Puts the current core into an implementation-defined low power state.
cpu_default_suspend<C: Call>( entry_point_address: u64, context_id: u64, ) -> Result<(), Error>214 pub fn cpu_default_suspend<C: Call>(
215 entry_point_address: u64,
216 context_id: u64,
217 ) -> Result<(), Error> {
218 success_or_error_64(
219 C::call64(
220 PSCI_CPU_DEFAULT_SUSPEND_64,
221 [
222 entry_point_address,
223 context_id,
224 0,
225 0,
226 0,
227 0,
228 0,
229 0,
230 0,
231 0,
232 0,
233 0,
234 0,
235 0,
236 0,
237 0,
238 0,
239 ],
240 )[0],
241 )
242 }
243
244 /// Retuns the true hardware state of a node in the power domain topology.
node_hw_state<C: Call>(target_cpu: u64, power_level: u32) -> Result<PowerState, Error>245 pub fn node_hw_state<C: Call>(target_cpu: u64, power_level: u32) -> Result<PowerState, Error> {
246 (C::call64(
247 PSCI_NODE_HW_STATE_64,
248 [
249 target_cpu,
250 power_level.into(),
251 0,
252 0,
253 0,
254 0,
255 0,
256 0,
257 0,
258 0,
259 0,
260 0,
261 0,
262 0,
263 0,
264 0,
265 0,
266 ],
267 )[0] as i32)
268 .try_into()
269 }
270
271 /// Suspends the system to RAM.
system_suspend<C: Call>(entry_point_address: u64, context_id: u64) -> Result<(), Error>272 pub fn system_suspend<C: Call>(entry_point_address: u64, context_id: u64) -> Result<(), Error> {
273 success_or_error_64(
274 C::call64(
275 PSCI_SYSTEM_SUSPEND_64,
276 [
277 entry_point_address,
278 context_id,
279 0,
280 0,
281 0,
282 0,
283 0,
284 0,
285 0,
286 0,
287 0,
288 0,
289 0,
290 0,
291 0,
292 0,
293 0,
294 ],
295 )[0],
296 )
297 }
298
299 /// Sets the mode used by `CPU_SUSPEND`.
set_suspend_mode<C: Call>(mode: SuspendMode) -> Result<(), Error>300 pub fn set_suspend_mode<C: Call>(mode: SuspendMode) -> Result<(), Error> {
301 success_or_error_32(C::call32(PSCI_SET_SUSPEND_MODE, [mode.into(), 0, 0, 0, 0, 0, 0])[0])
302 }
303
304 /// Returns the amount of time the platform has spend in the given power state since cold boot.
stat_residency<C: Call>(target_cpu: u64, power_state: u32) -> u64305 pub fn stat_residency<C: Call>(target_cpu: u64, power_state: u32) -> u64 {
306 C::call64(
307 PSCI_STAT_RESIDENCY_64,
308 [
309 target_cpu,
310 power_state.into(),
311 0,
312 0,
313 0,
314 0,
315 0,
316 0,
317 0,
318 0,
319 0,
320 0,
321 0,
322 0,
323 0,
324 0,
325 0,
326 ],
327 )[0]
328 }
329
330 /// Returns the number of times the platform has used the given power state since cold boot.
stat_count<C: Call>(target_cpu: u64, power_state: u32) -> u64331 pub fn stat_count<C: Call>(target_cpu: u64, power_state: u32) -> u64 {
332 C::call64(
333 PSCI_STAT_COUNT_64,
334 [
335 target_cpu,
336 power_state.into(),
337 0,
338 0,
339 0,
340 0,
341 0,
342 0,
343 0,
344 0,
345 0,
346 0,
347 0,
348 0,
349 0,
350 0,
351 0,
352 ],
353 )[0]
354 }
355