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