/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x86-0.47.0/src/apic/mod.rs
Line | Count | Source |
1 | | //! Register information and driver to program xAPIC, X2APIC and I/O APIC |
2 | | |
3 | | use bit_field::BitField; |
4 | | |
5 | | pub mod ioapic; |
6 | | pub mod x2apic; |
7 | | pub mod xapic; |
8 | | |
9 | | /// Specify IPI Delivery Mode |
10 | | #[allow(clippy::upper_case_acronyms)] |
11 | | #[derive(Debug, Eq, PartialEq)] |
12 | | #[repr(u64)] |
13 | | pub enum DeliveryMode { |
14 | | /// Delivers the interrupt specified in the vector field to the target processor or processors. |
15 | | Fixed = 0b000, |
16 | | /// Same as fixed mode, except that the interrupt is delivered to the processor executing at the |
17 | | /// lowest priority among the set of processors specified in the destination field. The ability |
18 | | /// for a processor to send a lowest priority IPI is model specific and should be avoided by |
19 | | /// BIOS and operating system software. |
20 | | LowestPriority = 0b001, |
21 | | /// Delivers an SMI interrupt to the target processor or processors. |
22 | | /// The vector field must be programmed to 00H for future compatibility. |
23 | | SMI = 0b010, |
24 | | /// Reserved |
25 | | _Reserved = 0b11, |
26 | | /// Delivers an NMI interrupt to the target processor or processors. |
27 | | /// The vector information is ignored. |
28 | | NMI = 0b100, |
29 | | /// Delivers an INIT request to the target processor or processors, which causes them to perform an INIT. |
30 | | Init = 0b101, |
31 | | /// Sends a special start-up IPI (called a SIPI) to the target processor or processors. |
32 | | /// The vector typically points to a start-up routine that is part of the |
33 | | /// BIOS boot-strap code (see Section 8.4, Multiple-Processor (MP) Initialization). I |
34 | | /// PIs sent with this delivery mode are not automatically retried if the source |
35 | | /// APIC is unable to deliver it. It is up to the software to deter- mine if the |
36 | | /// SIPI was not successfully delivered and to reissue the SIPI if necessary. |
37 | | StartUp = 0b110, |
38 | | } |
39 | | |
40 | | /// Specify IPI Destination Mode. |
41 | | #[derive(Debug, Eq, PartialEq)] |
42 | | #[repr(u64)] |
43 | | pub enum DestinationMode { |
44 | | Physical = 0, |
45 | | Logical = 1, |
46 | | } |
47 | | |
48 | | /// Specify Delivery Status |
49 | | #[derive(Debug, Eq, PartialEq)] |
50 | | #[repr(u64)] |
51 | | pub enum DeliveryStatus { |
52 | | Idle = 0, |
53 | | SendPending = 1, |
54 | | } |
55 | | |
56 | | /// IPI Level |
57 | | #[derive(Debug, Eq, PartialEq)] |
58 | | #[repr(u64)] |
59 | | pub enum Level { |
60 | | Deassert = 0, |
61 | | Assert = 1, |
62 | | } |
63 | | |
64 | | /// IPI Trigger Mode |
65 | | #[derive(Debug, Eq, PartialEq)] |
66 | | #[repr(u64)] |
67 | | pub enum TriggerMode { |
68 | | Edge = 0, |
69 | | Level = 1, |
70 | | } |
71 | | |
72 | | /// IPI Destination Shorthand |
73 | | #[derive(Debug, Eq, PartialEq)] |
74 | | #[repr(u64)] |
75 | | pub enum DestinationShorthand { |
76 | | NoShorthand = 0b00, |
77 | | Myself = 0b01, |
78 | | AllIncludingSelf = 0b10, |
79 | | AllExcludingSelf = 0b11, |
80 | | } |
81 | | |
82 | | /// Abstract the IPI control register |
83 | | #[derive(Debug, Eq, PartialEq)] |
84 | | pub struct Icr(u64); |
85 | | |
86 | | impl Icr { |
87 | 0 | fn id_to_xapic_destination(destination: ApicId) -> u64 { |
88 | | // XApic destination are encoded in bytes 56--63 in the Icr |
89 | 0 | match destination { |
90 | 0 | ApicId::XApic(d) => (d as u64) << 56, |
91 | 0 | ApicId::X2Apic(_d) => { |
92 | 0 | unreachable!("x2APIC IDs are not supported for xAPIC (use the x2APIC controller)") |
93 | | } |
94 | | } |
95 | 0 | } |
96 | | |
97 | 0 | fn id_to_x2apic_destination(destination: ApicId) -> u64 { |
98 | | // whereas, X2Apic destinations are encoded in bytes 32--63 in the Icr |
99 | | // The ACPI tables will can name the first 255 processors |
100 | | // with xAPIC IDs and no x2APIC entry exists in SRAT |
101 | | // However, the IDs should be compatible (I hope) |
102 | 0 | let d: u64 = match destination { |
103 | 0 | ApicId::XApic(d) => d as u64, |
104 | 0 | ApicId::X2Apic(d) => d as u64, |
105 | | }; |
106 | | |
107 | 0 | d << 32 |
108 | 0 | } |
109 | | |
110 | | #[allow(clippy::too_many_arguments)] |
111 | 0 | fn new( |
112 | 0 | dest_encoder: fn(ApicId) -> u64, |
113 | 0 | vector: u8, |
114 | 0 | destination: ApicId, |
115 | 0 | destination_shorthand: DestinationShorthand, |
116 | 0 | delivery_mode: DeliveryMode, |
117 | 0 | destination_mode: DestinationMode, |
118 | 0 | delivery_status: DeliveryStatus, |
119 | 0 | level: Level, |
120 | 0 | trigger_mode: TriggerMode, |
121 | 0 | ) -> Icr { |
122 | 0 | Icr(dest_encoder(destination) |
123 | 0 | | (destination_shorthand as u64) << 18 |
124 | 0 | | (trigger_mode as u64) << 15 |
125 | 0 | | (level as u64) << 14 |
126 | 0 | | (delivery_status as u64) << 12 |
127 | 0 | | (destination_mode as u64) << 11 |
128 | 0 | | (delivery_mode as u64) << 8 |
129 | 0 | | (vector as u64)) |
130 | 0 | } |
131 | | |
132 | | /// Short-hand to create a Icr value that will work for an x2APIC controller. |
133 | | #[allow(clippy::too_many_arguments)] |
134 | 0 | pub fn for_x2apic( |
135 | 0 | vector: u8, |
136 | 0 | destination: ApicId, |
137 | 0 | destination_shorthand: DestinationShorthand, |
138 | 0 | delivery_mode: DeliveryMode, |
139 | 0 | destination_mode: DestinationMode, |
140 | 0 | delivery_status: DeliveryStatus, |
141 | 0 | level: Level, |
142 | 0 | trigger_mode: TriggerMode, |
143 | 0 | ) -> Icr { |
144 | 0 | Icr::new( |
145 | 0 | Icr::id_to_x2apic_destination, |
146 | 0 | vector, |
147 | 0 | destination, |
148 | 0 | destination_shorthand, |
149 | 0 | delivery_mode, |
150 | 0 | destination_mode, |
151 | 0 | delivery_status, |
152 | 0 | level, |
153 | 0 | trigger_mode, |
154 | | ) |
155 | 0 | } |
156 | | |
157 | | #[allow(clippy::too_many_arguments)] |
158 | 0 | pub fn for_xapic( |
159 | 0 | vector: u8, |
160 | 0 | destination: ApicId, |
161 | 0 | destination_shorthand: DestinationShorthand, |
162 | 0 | delivery_mode: DeliveryMode, |
163 | 0 | destination_mode: DestinationMode, |
164 | 0 | delivery_status: DeliveryStatus, |
165 | 0 | level: Level, |
166 | 0 | trigger_mode: TriggerMode, |
167 | 0 | ) -> Icr { |
168 | 0 | Icr::new( |
169 | 0 | Icr::id_to_xapic_destination, |
170 | 0 | vector, |
171 | 0 | destination, |
172 | 0 | destination_shorthand, |
173 | 0 | delivery_mode, |
174 | 0 | destination_mode, |
175 | 0 | delivery_status, |
176 | 0 | level, |
177 | 0 | trigger_mode, |
178 | | ) |
179 | 0 | } |
180 | | |
181 | | /// Get lower 32-bits of the Icr register. |
182 | 0 | pub fn lower(&self) -> u32 { |
183 | 0 | self.0 as u32 |
184 | 0 | } |
185 | | |
186 | | /// Get upper 32-bits of the Icr register. |
187 | 0 | pub fn upper(&self) -> u32 { |
188 | 0 | (self.0 >> 32) as u32 |
189 | 0 | } |
190 | | } |
191 | | |
192 | | /// Encodes the id of a core. |
193 | | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
194 | | pub enum ApicId { |
195 | | /// A core destination encoded as an xAPIC ID. |
196 | | XApic(u8), |
197 | | /// A core destination encoded as an x2APIC ID. |
198 | | X2Apic(u32), |
199 | | } |
200 | | |
201 | | impl ApicId { |
202 | | /// Returns the Logical x2APIC ID. |
203 | | /// |
204 | | /// In x2APIC mode, the 32-bit logical x2APIC ID, which can be read from LDR, |
205 | | /// is derived from the 32-bit local x2APIC ID: |
206 | | /// Logical x2APIC ID = [(x2APIC ID[19:4] « 16) | (1 « x2APIC ID[3:0])] |
207 | 0 | pub fn x2apic_logical_id(&self) -> u32 { |
208 | 0 | self.x2apic_logical_cluster_id() << 16 | 1 << self.x2apic_logical_cluster_address() |
209 | 0 | } |
210 | | |
211 | | /// Returns the logical address relative to a cluster |
212 | | /// for a given APIC ID (assuming x2APIC addressing). |
213 | 0 | pub fn x2apic_logical_cluster_address(&self) -> u32 { |
214 | 0 | let d = match *self { |
215 | | // We support conversion for XApic IDs too because ACPI can |
216 | | // report <255 cores as XApic entries |
217 | 0 | ApicId::XApic(id) => id as u32, |
218 | 0 | ApicId::X2Apic(id) => id as u32, |
219 | | }; |
220 | | |
221 | 0 | d.get_bits(0..=3) |
222 | 0 | } |
223 | | |
224 | | /// Returns the cluster ID a given APIC ID belongs to |
225 | | /// (assuming x2APIC addressing). |
226 | 0 | pub fn x2apic_logical_cluster_id(&self) -> u32 { |
227 | 0 | let d = match *self { |
228 | | // We support conversion for XApic IDs too because ACPI can |
229 | | // report <255 cores as XApic entries |
230 | 0 | ApicId::XApic(id) => id as u32, |
231 | 0 | ApicId::X2Apic(id) => id as u32, |
232 | | }; |
233 | | |
234 | 0 | d.get_bits(4..=19) |
235 | 0 | } |
236 | | } |
237 | | |
238 | | #[allow(clippy::clippy::from_over_into)] |
239 | | impl Into<usize> for ApicId { |
240 | 0 | fn into(self) -> usize { |
241 | 0 | match self { |
242 | 0 | ApicId::XApic(id) => id as usize, |
243 | 0 | ApicId::X2Apic(id) => id as usize, |
244 | | } |
245 | 0 | } |
246 | | } |
247 | | |
248 | | /// Abstracts common interface of local APIC (x2APIC, xAPIC) hardware devices. |
249 | | pub trait ApicControl { |
250 | | /// Is a bootstrap processor? |
251 | | fn bsp(&self) -> bool; |
252 | | |
253 | | /// Return APIC ID. |
254 | | fn id(&self) -> u32; |
255 | | |
256 | | /// Returns the logical APIC ID. |
257 | | fn logical_id(&self) -> u32; |
258 | | |
259 | | /// Read APIC version |
260 | | fn version(&self) -> u32; |
261 | | |
262 | | /// End Of Interrupt -- Acknowledge interrupt delivery. |
263 | | fn eoi(&mut self); |
264 | | |
265 | | /// Enable TSC deadline timer. |
266 | | fn tsc_enable(&mut self, vector: u8); |
267 | | |
268 | | /// Set TSC deadline value. |
269 | | fn tsc_set(&self, value: u64); |
270 | | |
271 | | /// Send a INIT IPI to a core. |
272 | | /// |
273 | | /// # Safety |
274 | | /// Should only be used to reset or boot a new core. |
275 | | unsafe fn ipi_init(&mut self, core: ApicId); |
276 | | |
277 | | /// Deassert INIT IPI. |
278 | | /// |
279 | | /// # Safety |
280 | | /// Should only be used to reset or boot a new core. |
281 | | unsafe fn ipi_init_deassert(&mut self); |
282 | | |
283 | | /// Send a STARTUP IPI to a core. |
284 | | /// |
285 | | /// # Safety |
286 | | /// Should only be used to reset or boot a new core. |
287 | | unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8); |
288 | | |
289 | | /// Send a generic IPI. |
290 | | /// |
291 | | /// # Safety |
292 | | /// Interrupts one or multiple cores. |
293 | | unsafe fn send_ipi(&mut self, icr: Icr); |
294 | | } |