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