1 | //! Multi-processor management protocols. |
2 | //! |
3 | //! On any system with more than one logical processor we can categorize them as: |
4 | //! |
5 | //! * BSP — bootstrap processor, executes modules that are necessary for booting the system |
6 | //! * AP — application processor, any processor other than the bootstrap processor |
7 | //! |
8 | //! This module contains protocols that provide a generalized way of performing the following tasks on these logical processors: |
9 | //! |
10 | //! * retrieving information of multi-processor environment and MP-related status of specific processors |
11 | //! * dispatching user-provided function to APs |
12 | //! * maintaining MP-related processor status |
13 | |
14 | use crate::proto::unsafe_protocol ; |
15 | use crate::{Result, Status}; |
16 | use bitflags::bitflags; |
17 | use core::ffi::c_void; |
18 | use core::ptr; |
19 | use core::time::Duration; |
20 | |
21 | /// Callback to be called on the AP. |
22 | pub type Procedure = extern "efiapi" fn(*mut c_void); |
23 | |
24 | bitflags! { |
25 | /// Flags indicating if the processor is BSP or AP, |
26 | /// if the processor is enabled or disabled, and if |
27 | /// the processor is healthy. |
28 | #[derive (Default)] |
29 | struct StatusFlag: u32 { |
30 | /// Processor is playing the role of BSP. |
31 | const PROCESSOR_AS_BSP_BIT = 1; |
32 | /// Processor is enabled. |
33 | const PROCESSOR_ENABLED_BIT = 1 << 1; |
34 | /// Processor is healthy. |
35 | const PROCESSOR_HEALTH_STATUS_BIT = 1 << 2; |
36 | } |
37 | } |
38 | |
39 | /// Information about number of logical processors on the platform. |
40 | #[derive (Default, Debug)] |
41 | pub struct ProcessorCount { |
42 | /// Total number of processors (including BSP). |
43 | pub total: usize, |
44 | /// Number of processors (including BSP) that are currently enabled. |
45 | pub enabled: usize, |
46 | } |
47 | |
48 | /// Information about processor on the platform. |
49 | #[repr (C)] |
50 | #[derive (Default, Debug)] |
51 | pub struct ProcessorInformation { |
52 | /// Unique processor ID determined by system hardware. |
53 | pub processor_id: u64, |
54 | /// Flags indicating BSP, enabled and healthy status. |
55 | status_flag: StatusFlag, |
56 | /// Physical location of the processor. |
57 | pub location: CpuPhysicalLocation, |
58 | } |
59 | |
60 | impl ProcessorInformation { |
61 | /// Returns `true` if the processor is playing the role of BSP. |
62 | #[must_use ] |
63 | pub const fn is_bsp(&self) -> bool { |
64 | self.status_flag.contains(StatusFlag::PROCESSOR_AS_BSP_BIT) |
65 | } |
66 | |
67 | /// Returns `true` if the processor is enabled. |
68 | #[must_use ] |
69 | pub const fn is_enabled(&self) -> bool { |
70 | self.status_flag.contains(StatusFlag::PROCESSOR_ENABLED_BIT) |
71 | } |
72 | |
73 | /// Returns `true` if the processor is healthy. |
74 | #[must_use ] |
75 | pub const fn is_healthy(&self) -> bool { |
76 | self.status_flag |
77 | .contains(StatusFlag::PROCESSOR_HEALTH_STATUS_BIT) |
78 | } |
79 | } |
80 | |
81 | /// Information about physical location of the processor. |
82 | #[repr (C)] |
83 | #[derive (Default, Debug)] |
84 | pub struct CpuPhysicalLocation { |
85 | /// Zero-based physical package number that identifies |
86 | /// the cartridge of the processor. |
87 | pub package: u32, |
88 | /// Zero-based physical core number within package of the processor. |
89 | pub core: u32, |
90 | /// Zero-based logical thread number within core of the processor. |
91 | pub thread: u32, |
92 | } |
93 | |
94 | /// Protocol that provides services needed for multi-processor management. |
95 | #[repr (C)] |
96 | #[unsafe_protocol ("3fdda605-a76e-4f46-ad29-12f4531b3d08" )] |
97 | pub struct MpServices { |
98 | get_number_of_processors: extern "efiapi" fn( |
99 | this: *const MpServices, |
100 | number_of_processors: *mut usize, |
101 | number_of_enabled_processors: *mut usize, |
102 | ) -> Status, |
103 | get_processor_info: extern "efiapi" fn( |
104 | this: *const MpServices, |
105 | processor_number: usize, |
106 | processor_info_buffer: *mut ProcessorInformation, |
107 | ) -> Status, |
108 | startup_all_aps: extern "efiapi" fn( |
109 | this: *const MpServices, |
110 | procedure: Procedure, |
111 | single_thread: bool, |
112 | wait_event: *mut c_void, |
113 | timeout_in_micro_seconds: usize, |
114 | procedure_argument: *mut c_void, |
115 | failed_cpu_list: *mut *mut usize, |
116 | ) -> Status, |
117 | startup_this_ap: extern "efiapi" fn( |
118 | this: *const MpServices, |
119 | procedure: Procedure, |
120 | processor_number: usize, |
121 | wait_event: *mut c_void, |
122 | timeout_in_micro_seconds: usize, |
123 | procedure_argument: *mut c_void, |
124 | finished: *mut bool, |
125 | ) -> Status, |
126 | switch_bsp: extern "efiapi" fn( |
127 | this: *const MpServices, |
128 | processor_number: usize, |
129 | enable_old_bsp: bool, |
130 | ) -> Status, |
131 | enable_disable_ap: extern "efiapi" fn( |
132 | this: *const MpServices, |
133 | processor_number: usize, |
134 | enable_ap: bool, |
135 | health_flag: *const u32, |
136 | ) -> Status, |
137 | who_am_i: extern "efiapi" fn(this: *const MpServices, processor_number: *mut usize) -> Status, |
138 | } |
139 | |
140 | impl MpServices { |
141 | /// Retrieves the number of logical processors and the number of enabled logical processors in the system. |
142 | pub fn get_number_of_processors(&self) -> Result<ProcessorCount> { |
143 | let mut total: usize = 0; |
144 | let mut enabled: usize = 0; |
145 | (self.get_number_of_processors)(self, &mut total, &mut enabled) |
146 | .into_with_val(|| ProcessorCount { total, enabled }) |
147 | } |
148 | |
149 | /// Gets detailed information on the requested processor at the instant this call is made. |
150 | pub fn get_processor_info(&self, processor_number: usize) -> Result<ProcessorInformation> { |
151 | let mut pi: ProcessorInformation = Default::default(); |
152 | (self.get_processor_info)(self, processor_number, &mut pi).into_with_val(|| pi) |
153 | } |
154 | |
155 | /// Executes provided function on all APs in blocking mode. |
156 | pub fn startup_all_aps( |
157 | &self, |
158 | single_thread: bool, |
159 | procedure: Procedure, |
160 | procedure_argument: *mut c_void, |
161 | timeout: Option<Duration>, |
162 | ) -> Result { |
163 | let timeout_arg = match timeout { |
164 | Some(timeout) => timeout.as_micros().try_into().unwrap(), |
165 | None => 0, |
166 | }; |
167 | |
168 | (self.startup_all_aps)( |
169 | self, |
170 | procedure, |
171 | single_thread, |
172 | ptr::null_mut(), |
173 | timeout_arg, |
174 | procedure_argument, |
175 | ptr::null_mut(), |
176 | ) |
177 | .into() |
178 | } |
179 | |
180 | /// Executes provided function on a specific AP in blocking mode. |
181 | pub fn startup_this_ap( |
182 | &self, |
183 | processor_number: usize, |
184 | procedure: Procedure, |
185 | procedure_argument: *mut c_void, |
186 | timeout: Option<Duration>, |
187 | ) -> Result { |
188 | let timeout_arg = match timeout { |
189 | Some(timeout) => timeout.as_micros().try_into().unwrap(), |
190 | None => 0, |
191 | }; |
192 | |
193 | (self.startup_this_ap)( |
194 | self, |
195 | procedure, |
196 | processor_number, |
197 | ptr::null_mut(), |
198 | timeout_arg, |
199 | procedure_argument, |
200 | ptr::null_mut(), |
201 | ) |
202 | .into() |
203 | } |
204 | |
205 | /// Switches the requested AP to be the BSP from that point onward. |
206 | pub fn switch_bsp(&self, processor_number: usize, enable_old_bsp: bool) -> Result { |
207 | (self.switch_bsp)(self, processor_number, enable_old_bsp).into() |
208 | } |
209 | |
210 | /// Enables or disables an AP from this point onward. |
211 | /// |
212 | /// The `healthy` argument can be used to specify the new health status of the AP. |
213 | pub fn enable_disable_ap( |
214 | &self, |
215 | processor_number: usize, |
216 | enable_ap: bool, |
217 | healthy: Option<bool>, |
218 | ) -> Result { |
219 | let health_flag_raw: u32; |
220 | let health_flag_ptr = match healthy { |
221 | Some(healthy) => { |
222 | let mut sf = StatusFlag::empty(); |
223 | sf.set(StatusFlag::PROCESSOR_HEALTH_STATUS_BIT, healthy); |
224 | health_flag_raw = sf.bits(); |
225 | &health_flag_raw |
226 | } |
227 | None => ptr::null(), |
228 | }; |
229 | (self.enable_disable_ap)(self, processor_number, enable_ap, health_flag_ptr).into() |
230 | } |
231 | |
232 | /// Gets the handle number of the caller processor. |
233 | pub fn who_am_i(&self) -> Result<usize> { |
234 | let mut processor_number: usize = 0; |
235 | (self.who_am_i)(self, &mut processor_number).into_with_val(|| processor_number) |
236 | } |
237 | } |
238 | |