/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x86-0.47.0/src/apic/xapic.rs
Line | Count | Source |
1 | | //! Information about the xAPIC for the local APIC. |
2 | | //! |
3 | | //! Table 10-1 Local APIC Register Address Map |
4 | | //! the MMIO base values are found in this file. |
5 | | |
6 | | use bit_field::BitField; |
7 | | use core::fmt; |
8 | | |
9 | | use super::*; |
10 | | use crate::msr::{rdmsr, wrmsr, IA32_APIC_BASE, IA32_TSC_DEADLINE}; |
11 | | |
12 | | /// Local APIC ID register. Read-only. See Section 10.12.5.1 for initial values. |
13 | | pub const XAPIC_ID: u32 = 0x020; |
14 | | |
15 | | /// Local APIC Version register. Read-only. Same version used in xAPIC mode and x2APIC mode. |
16 | | pub const XAPIC_VERSION: u32 = 0x030; |
17 | | |
18 | | /// Task Priority Register (TPR). Read/write. Bits 31:8 are reserved. |
19 | | pub const XAPIC_TPR: u32 = 0x080; |
20 | | |
21 | | /// Processor Priority Register (PPR). Read-only. |
22 | | pub const XAPIC_PPR: u32 = 0x0A0; |
23 | | |
24 | | /// EOI register. Write-only. |
25 | | pub const XAPIC_EOI: u32 = 0x0B0; |
26 | | |
27 | | /// Logical Destination Register (LDR). Read/write in xAPIC mode. |
28 | | pub const XAPIC_LDR: u32 = 0x0D0; |
29 | | |
30 | | /// Spurious Interrupt Vector Register (SVR). Read/write. See Section 10.9 for reserved bits. |
31 | | pub const XAPIC_SVR: u32 = 0x0F0; |
32 | | |
33 | | /// In-Service Register (ISR); bits 31:0. Read-only. |
34 | | pub const XAPIC_ISR0: u32 = 0x100; |
35 | | |
36 | | /// ISR bits 63:32. Read-only. |
37 | | pub const XAPIC_ISR1: u32 = 0x110; |
38 | | |
39 | | /// ISR bits 95:64. Read-only. |
40 | | pub const XAPIC_ISR2: u32 = 0x120; |
41 | | |
42 | | /// ISR bits 127:96. Read-only. |
43 | | pub const XAPIC_ISR3: u32 = 0x130; |
44 | | |
45 | | /// ISR bits 159:128. Read-only. |
46 | | pub const XAPIC_ISR4: u32 = 0x140; |
47 | | |
48 | | /// ISR bits 191:160. Read-only. |
49 | | pub const XAPIC_ISR5: u32 = 0x150; |
50 | | |
51 | | /// ISR bits 223:192. Read-only. |
52 | | pub const XAPIC_ISR6: u32 = 0x160; |
53 | | |
54 | | /// ISR bits 255:224. Read-only. |
55 | | pub const XAPIC_ISR7: u32 = 0x170; |
56 | | |
57 | | /// Trigger Mode Register (TMR); bits 31:0. Read-only. |
58 | | pub const XAPIC_TMR0: u32 = 0x180; |
59 | | |
60 | | /// TMR bits 63:32. Read-only. |
61 | | pub const XAPIC_TMR1: u32 = 0x190; |
62 | | |
63 | | /// TMR bits 95:64. Read-only. |
64 | | pub const XAPIC_TMR2: u32 = 0x1A0; |
65 | | |
66 | | /// TMR bits 127:96. Read-only. |
67 | | pub const XAPIC_TMR3: u32 = 0x1B0; |
68 | | |
69 | | /// TMR bits 159:128. Read-only. |
70 | | pub const XAPIC_TMR4: u32 = 0x1C0; |
71 | | |
72 | | /// TMR bits 191:160. Read-only. |
73 | | pub const XAPIC_TMR5: u32 = 0x1D0; |
74 | | |
75 | | /// TMR bits 223:192. Read-only. |
76 | | pub const XAPIC_TMR6: u32 = 0x1E0; |
77 | | |
78 | | /// TMR bits 255:224. Read-only. |
79 | | pub const XAPIC_TMR7: u32 = 0x1F0; |
80 | | |
81 | | /// Interrupt Request Register (IRR); bits 31:0. Read-only. |
82 | | pub const XAPIC_IRR0: u32 = 0x200; |
83 | | |
84 | | /// IRR bits 63:32. Read-only. |
85 | | pub const XAPIC_IRR1: u32 = 0x210; |
86 | | |
87 | | /// IRR bits 95:64. Read-only. |
88 | | pub const XAPIC_IRR2: u32 = 0x220; |
89 | | |
90 | | /// IRR bits 127:96. Read-only. |
91 | | pub const XAPIC_IRR3: u32 = 0x230; |
92 | | |
93 | | /// IRR bits 159:128. Read-only. |
94 | | pub const XAPIC_IRR4: u32 = 0x240; |
95 | | |
96 | | /// IRR bits 191:160. Read-only. |
97 | | pub const XAPIC_IRR5: u32 = 0x250; |
98 | | |
99 | | /// IRR bits 223:192. Read-only. |
100 | | pub const XAPIC_IRR6: u32 = 0x260; |
101 | | |
102 | | /// IRR bits 255:224. Read-only. |
103 | | pub const XAPIC_IRR7: u32 = 0x270; |
104 | | |
105 | | /// Error Status Register (ESR). Read/write. See Section 10.5.3. |
106 | | pub const XAPIC_ESR: u32 = 0x280; |
107 | | |
108 | | /// LVT CMCI register. Read/write. See Figure 10-8 for reserved bits. |
109 | | pub const XAPIC_LVT_CMCI: u32 = 0x2F0; |
110 | | |
111 | | /// Interrupt Command Register (ICR). Read/write. See Figure 10-28 for reserved bits |
112 | | pub const XAPIC_ICR0: u32 = 0x300; |
113 | | |
114 | | /// Interrupt Command Register (ICR). Read/write. See Figure 10-28 for reserved bits |
115 | | pub const XAPIC_ICR1: u32 = 0x310; |
116 | | |
117 | | /// LVT Timer register. Read/write. See Figure 10-8 for reserved bits. |
118 | | pub const XAPIC_LVT_TIMER: u32 = 0x320; |
119 | | |
120 | | /// LVT Thermal Sensor register. Read/write. See Figure 10-8 for reserved bits. |
121 | | pub const XAPIC_LVT_THERMAL: u32 = 0x330; |
122 | | |
123 | | /// LVT Performance Monitoring register. Read/write. See Figure 10-8 for reserved bits. |
124 | | pub const XAPIC_LVT_PMI: u32 = 0x340; |
125 | | |
126 | | /// LVT LINT0 register. Read/write. See Figure 10-8 for reserved bits. |
127 | | pub const XAPIC_LVT_LINT0: u32 = 0x350; |
128 | | |
129 | | /// LVT LINT1 register. Read/write. See Figure 10-8 for reserved bits. |
130 | | pub const XAPIC_LVT_LINT1: u32 = 0x360; |
131 | | |
132 | | /// LVT Error register. Read/write. See Figure 10-8 for reserved bits. |
133 | | pub const XAPIC_LVT_ERROR: u32 = 0x370; |
134 | | |
135 | | /// Initial Count register (for Timer). Read/write. |
136 | | pub const XAPIC_TIMER_INIT_COUNT: u32 = 0x380; |
137 | | |
138 | | /// Current Count register (for Timer). Read-only. |
139 | | pub const XAPIC_TIMER_CURRENT_COUNT: u32 = 0x390; |
140 | | |
141 | | /// Divide Configuration Register (DCR; for Timer). Read/write. See Figure 10-10 for reserved bits. |
142 | | pub const XAPIC_TIMER_DIV_CONF: u32 = 0x3E0; |
143 | | |
144 | | #[derive(Copy, Clone)] |
145 | | #[allow(dead_code, non_camel_case_types)] |
146 | | enum ApicRegister { |
147 | | XAPIC_ID = XAPIC_ID as isize, |
148 | | XAPIC_VERSION = XAPIC_VERSION as isize, |
149 | | XAPIC_TPR = XAPIC_TPR as isize, |
150 | | XAPIC_PPR = XAPIC_PPR as isize, |
151 | | XAPIC_EOI = XAPIC_EOI as isize, |
152 | | XAPIC_LDR = XAPIC_LDR as isize, |
153 | | XAPIC_SVR = XAPIC_SVR as isize, |
154 | | XAPIC_ISR0 = XAPIC_ISR0 as isize, |
155 | | XAPIC_ISR1 = XAPIC_ISR1 as isize, |
156 | | XAPIC_ISR2 = XAPIC_ISR2 as isize, |
157 | | XAPIC_ISR3 = XAPIC_ISR3 as isize, |
158 | | XAPIC_ISR4 = XAPIC_ISR4 as isize, |
159 | | XAPIC_ISR5 = XAPIC_ISR5 as isize, |
160 | | XAPIC_ISR6 = XAPIC_ISR6 as isize, |
161 | | XAPIC_ISR7 = XAPIC_ISR7 as isize, |
162 | | XAPIC_TMR0 = XAPIC_TMR0 as isize, |
163 | | XAPIC_TMR1 = XAPIC_TMR1 as isize, |
164 | | XAPIC_TMR2 = XAPIC_TMR2 as isize, |
165 | | XAPIC_TMR3 = XAPIC_TMR3 as isize, |
166 | | XAPIC_TMR4 = XAPIC_TMR4 as isize, |
167 | | XAPIC_TMR5 = XAPIC_TMR5 as isize, |
168 | | XAPIC_TMR6 = XAPIC_TMR6 as isize, |
169 | | XAPIC_TMR7 = XAPIC_TMR7 as isize, |
170 | | XAPIC_IRR0 = XAPIC_IRR0 as isize, |
171 | | XAPIC_IRR1 = XAPIC_IRR1 as isize, |
172 | | XAPIC_IRR2 = XAPIC_IRR2 as isize, |
173 | | XAPIC_IRR3 = XAPIC_IRR3 as isize, |
174 | | XAPIC_IRR4 = XAPIC_IRR4 as isize, |
175 | | XAPIC_IRR5 = XAPIC_IRR5 as isize, |
176 | | XAPIC_IRR6 = XAPIC_IRR6 as isize, |
177 | | XAPIC_IRR7 = XAPIC_IRR7 as isize, |
178 | | XAPIC_ESR = XAPIC_ESR as isize, |
179 | | XAPIC_LVT_CMCI = XAPIC_LVT_CMCI as isize, |
180 | | XAPIC_ICR0 = XAPIC_ICR0 as isize, |
181 | | XAPIC_ICR1 = XAPIC_ICR1 as isize, |
182 | | XAPIC_LVT_TIMER = XAPIC_LVT_TIMER as isize, |
183 | | XAPIC_LVT_THERMAL = XAPIC_LVT_THERMAL as isize, |
184 | | XAPIC_LVT_PMI = XAPIC_LVT_PMI as isize, |
185 | | XAPIC_LVT_LINT0 = XAPIC_LVT_LINT0 as isize, |
186 | | XAPIC_LVT_LINT1 = XAPIC_LVT_LINT1 as isize, |
187 | | XAPIC_LVT_ERROR = XAPIC_LVT_ERROR as isize, |
188 | | XAPIC_TIMER_INIT_COUNT = XAPIC_TIMER_INIT_COUNT as isize, |
189 | | XAPIC_TIMER_CURRENT_COUNT = XAPIC_TIMER_CURRENT_COUNT as isize, |
190 | | XAPIC_TIMER_DIV_CONF = XAPIC_TIMER_DIV_CONF as isize, |
191 | | } |
192 | | |
193 | | /// State for the XAPIC driver. |
194 | | #[allow(clippy::clippy::upper_case_acronyms)] |
195 | | pub struct XAPIC { |
196 | | /// Reference to the xAPCI region |
197 | | mmio_region: &'static mut [u32], |
198 | | /// Initial APIC Base register value. |
199 | | base: u64, |
200 | | } |
201 | | |
202 | | impl fmt::Debug for XAPIC { |
203 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
204 | 0 | f.debug_struct("XAPIC") |
205 | 0 | .field("XAPIC_ID", &self.read(ApicRegister::XAPIC_ID)) |
206 | 0 | .field("XAPIC_VERSION", &self.read(ApicRegister::XAPIC_VERSION)) |
207 | 0 | .field("XAPIC_TPR", &self.read(ApicRegister::XAPIC_TPR)) |
208 | 0 | .field("XAPIC_PPR", &self.read(ApicRegister::XAPIC_PPR)) |
209 | 0 | .field("XAPIC_EOI", &self.read(ApicRegister::XAPIC_EOI)) |
210 | 0 | .field("XAPIC_LDR", &self.read(ApicRegister::XAPIC_LDR)) |
211 | 0 | .field("XAPIC_SVR", &self.read(ApicRegister::XAPIC_SVR)) |
212 | 0 | .field("XAPIC_ISR0", &self.read(ApicRegister::XAPIC_ISR0)) |
213 | 0 | .field("XAPIC_ISR1", &self.read(ApicRegister::XAPIC_ISR1)) |
214 | 0 | .field("XAPIC_ISR2", &self.read(ApicRegister::XAPIC_ISR2)) |
215 | 0 | .field("XAPIC_ISR3", &self.read(ApicRegister::XAPIC_ISR3)) |
216 | 0 | .field("XAPIC_ISR4", &self.read(ApicRegister::XAPIC_ISR4)) |
217 | 0 | .field("XAPIC_ISR5", &self.read(ApicRegister::XAPIC_ISR5)) |
218 | 0 | .field("XAPIC_ISR6", &self.read(ApicRegister::XAPIC_ISR6)) |
219 | 0 | .field("XAPIC_ISR7", &self.read(ApicRegister::XAPIC_ISR7)) |
220 | 0 | .field("XAPIC_TMR0", &self.read(ApicRegister::XAPIC_TMR0)) |
221 | 0 | .field("XAPIC_TMR1", &self.read(ApicRegister::XAPIC_TMR1)) |
222 | 0 | .field("XAPIC_TMR2", &self.read(ApicRegister::XAPIC_TMR2)) |
223 | 0 | .field("XAPIC_TMR3", &self.read(ApicRegister::XAPIC_TMR3)) |
224 | 0 | .field("XAPIC_TMR4", &self.read(ApicRegister::XAPIC_TMR4)) |
225 | 0 | .field("XAPIC_TMR5", &self.read(ApicRegister::XAPIC_TMR5)) |
226 | 0 | .field("XAPIC_TMR6", &self.read(ApicRegister::XAPIC_TMR6)) |
227 | 0 | .field("XAPIC_TMR7", &self.read(ApicRegister::XAPIC_TMR7)) |
228 | 0 | .field("XAPIC_IRR0", &self.read(ApicRegister::XAPIC_IRR0)) |
229 | 0 | .field("XAPIC_IRR1", &self.read(ApicRegister::XAPIC_IRR1)) |
230 | 0 | .field("XAPIC_IRR2", &self.read(ApicRegister::XAPIC_IRR2)) |
231 | 0 | .field("XAPIC_IRR3", &self.read(ApicRegister::XAPIC_IRR3)) |
232 | 0 | .field("XAPIC_IRR4", &self.read(ApicRegister::XAPIC_IRR4)) |
233 | 0 | .field("XAPIC_IRR5", &self.read(ApicRegister::XAPIC_IRR5)) |
234 | 0 | .field("XAPIC_IRR6", &self.read(ApicRegister::XAPIC_IRR6)) |
235 | 0 | .field("XAPIC_IRR7", &self.read(ApicRegister::XAPIC_IRR7)) |
236 | 0 | .field("XAPIC_ESR", &self.read(ApicRegister::XAPIC_ESR)) |
237 | 0 | .field("XAPIC_LVT_CMCI", &self.read(ApicRegister::XAPIC_LVT_CMCI)) |
238 | 0 | .field("XAPIC_ICR0", &self.read(ApicRegister::XAPIC_ICR0)) |
239 | 0 | .field("XAPIC_ICR1", &self.read(ApicRegister::XAPIC_ICR1)) |
240 | 0 | .field("XAPIC_LVT_TIMER", &self.read(ApicRegister::XAPIC_LVT_TIMER)) |
241 | 0 | .field( |
242 | 0 | "XAPIC_LVT_THERMAL", |
243 | 0 | &self.read(ApicRegister::XAPIC_LVT_THERMAL), |
244 | 0 | ) |
245 | 0 | .field("XAPIC_LVT_PMI", &self.read(ApicRegister::XAPIC_LVT_PMI)) |
246 | 0 | .field("XAPIC_LVT_LINT0", &self.read(ApicRegister::XAPIC_LVT_LINT0)) |
247 | 0 | .field("XAPIC_LVT_LINT1", &self.read(ApicRegister::XAPIC_LVT_LINT1)) |
248 | 0 | .field("XAPIC_LVT_ERROR", &self.read(ApicRegister::XAPIC_LVT_ERROR)) |
249 | 0 | .field( |
250 | 0 | "XAPIC_TIMER_INIT_COUNT", |
251 | 0 | &self.read(ApicRegister::XAPIC_TIMER_INIT_COUNT), |
252 | 0 | ) |
253 | 0 | .field( |
254 | 0 | "XAPIC_TIMER_CURRENT_COUNT", |
255 | 0 | &self.read(ApicRegister::XAPIC_TIMER_CURRENT_COUNT), |
256 | 0 | ) |
257 | 0 | .field( |
258 | 0 | "XAPIC_TIMER_DIV_CONF", |
259 | 0 | &self.read(ApicRegister::XAPIC_TIMER_DIV_CONF), |
260 | 0 | ) |
261 | 0 | .finish() |
262 | 0 | } |
263 | | } |
264 | | |
265 | | impl XAPIC { |
266 | | /// Create a new xAPIC object for the local CPU. |
267 | | /// |
268 | | /// Pass the xAPCI region which is at XXX unless you have |
269 | | /// relocated the region. |
270 | 0 | pub fn new(apic_region: &'static mut [u32]) -> XAPIC { |
271 | | unsafe { |
272 | 0 | XAPIC { |
273 | 0 | mmio_region: apic_region, |
274 | 0 | base: rdmsr(IA32_APIC_BASE), |
275 | 0 | } |
276 | | } |
277 | 0 | } |
278 | | |
279 | | /// Attach driver to the xAPIC (enables device). |
280 | 0 | pub fn attach(&mut self) { |
281 | | // Enable |
282 | 0 | unsafe { |
283 | 0 | // Enable xAPIC globally |
284 | 0 | self.base = rdmsr(IA32_APIC_BASE); |
285 | 0 | self.base.set_bit(11, true); |
286 | 0 | wrmsr(IA32_APIC_BASE, self.base); |
287 | 0 |
|
288 | 0 | // Enable this XAPIC (set bit 8, spurious IRQ vector 15) |
289 | 0 | let svr: u32 = 1 << 8 | 15; |
290 | 0 | self.write(ApicRegister::XAPIC_SVR, svr); |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | | /// Detach driver form the xAPIC (disables device). |
295 | 0 | pub fn detach(&mut self) { |
296 | 0 | unsafe { |
297 | 0 | self.base = rdmsr(IA32_APIC_BASE); |
298 | 0 | self.base.set_bit(11, false); // Disable xAPIC |
299 | 0 | wrmsr(IA32_APIC_BASE, self.base); |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | /// Read a register from the MMIO region. |
304 | 0 | fn read(&self, offset: ApicRegister) -> u32 { |
305 | 0 | assert!(offset as usize % 4 == 0); |
306 | 0 | let index = offset as usize / 4; |
307 | 0 | unsafe { core::ptr::read_volatile(&self.mmio_region[index]) } |
308 | 0 | } |
309 | | |
310 | | /// write a register in the MMIO region. |
311 | 0 | fn write(&mut self, offset: ApicRegister, val: u32) { |
312 | 0 | assert!(offset as usize % 4 == 0); |
313 | 0 | let index = offset as usize / 4; |
314 | 0 | unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) } |
315 | 0 | } |
316 | | } |
317 | | |
318 | | impl ApicControl for XAPIC { |
319 | | /// Is this the bootstrap core? |
320 | 0 | fn bsp(&self) -> bool { |
321 | 0 | (self.base & (1 << 8)) > 0 |
322 | 0 | } |
323 | | |
324 | | /// Read local APIC ID. |
325 | 0 | fn id(&self) -> u32 { |
326 | 0 | self.read(ApicRegister::XAPIC_ID) |
327 | 0 | } |
328 | | |
329 | 0 | fn logical_id(&self) -> u32 { |
330 | 0 | self.read(ApicRegister::XAPIC_LDR) |
331 | 0 | } |
332 | | |
333 | | /// Read APIC version |
334 | 0 | fn version(&self) -> u32 { |
335 | 0 | self.read(ApicRegister::XAPIC_VERSION) |
336 | 0 | } |
337 | | |
338 | | /// End Of Interrupt -- Acknowledge interrupt delivery. |
339 | 0 | fn eoi(&mut self) { |
340 | 0 | self.write(ApicRegister::XAPIC_EOI, 0); |
341 | 0 | } |
342 | | |
343 | | /// Enable TSC timer. |
344 | 0 | fn tsc_enable(&mut self, vector: u8) { |
345 | 0 | let mut lvt: u32 = self.read(ApicRegister::XAPIC_LVT_TIMER); |
346 | 0 | lvt &= !0xff; |
347 | 0 | lvt |= vector as u32; |
348 | | |
349 | 0 | lvt.set_bit(16, false); |
350 | 0 | lvt.set_bit(17, false); |
351 | 0 | lvt.set_bit(18, true); |
352 | 0 | self.write(ApicRegister::XAPIC_LVT_TIMER, lvt); |
353 | 0 | } |
354 | | |
355 | | /// Set TSC deadline value. |
356 | 0 | fn tsc_set(&self, value: u64) { |
357 | 0 | unsafe { |
358 | 0 | wrmsr(IA32_TSC_DEADLINE, value); |
359 | 0 | } |
360 | 0 | } |
361 | | |
362 | | /// Send a INIT IPI to a core. |
363 | 0 | unsafe fn ipi_init(&mut self, core: ApicId) { |
364 | 0 | let icr = Icr::for_xapic( |
365 | | 0, |
366 | 0 | core, |
367 | 0 | DestinationShorthand::NoShorthand, |
368 | 0 | DeliveryMode::Init, |
369 | 0 | DestinationMode::Physical, |
370 | 0 | DeliveryStatus::Idle, |
371 | 0 | Level::Assert, |
372 | 0 | TriggerMode::Level, |
373 | | ); |
374 | 0 | self.send_ipi(icr); |
375 | 0 | } |
376 | | |
377 | | /// Deassert INIT IPI. |
378 | 0 | unsafe fn ipi_init_deassert(&mut self) { |
379 | 0 | let icr = Icr::for_xapic( |
380 | | 0, |
381 | 0 | ApicId::XApic(0), |
382 | | // INIT deassert is always sent to everyone, so we are supposed to specify: |
383 | 0 | DestinationShorthand::AllIncludingSelf, |
384 | 0 | DeliveryMode::Init, |
385 | 0 | DestinationMode::Physical, |
386 | 0 | DeliveryStatus::Idle, |
387 | 0 | Level::Deassert, |
388 | 0 | TriggerMode::Level, |
389 | | ); |
390 | 0 | self.send_ipi(icr); |
391 | 0 | } |
392 | | |
393 | | /// Send a STARTUP IPI to a core. |
394 | 0 | unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8) { |
395 | 0 | let icr = Icr::for_xapic( |
396 | 0 | start_page, |
397 | 0 | core, |
398 | 0 | DestinationShorthand::NoShorthand, |
399 | 0 | DeliveryMode::StartUp, |
400 | 0 | DestinationMode::Physical, |
401 | 0 | DeliveryStatus::Idle, |
402 | 0 | Level::Assert, |
403 | 0 | TriggerMode::Edge, |
404 | | ); |
405 | 0 | self.send_ipi(icr); |
406 | 0 | } |
407 | | |
408 | | /// Send a generic IPI. |
409 | 0 | unsafe fn send_ipi(&mut self, icr: Icr) { |
410 | 0 | self.write(ApicRegister::XAPIC_ESR, 0); |
411 | 0 | self.write(ApicRegister::XAPIC_ESR, 0); |
412 | | |
413 | | // 10.6 ISSUING INTERPROCESSOR INTERRUPTS |
414 | 0 | self.write(ApicRegister::XAPIC_ICR1, icr.upper()); |
415 | 0 | self.write(ApicRegister::XAPIC_ICR0, icr.lower()); |
416 | | |
417 | | loop { |
418 | 0 | let icr = self.read(ApicRegister::XAPIC_ICR0); |
419 | 0 | if (icr >> 12 & 0x1) == 0 { |
420 | 0 | break; |
421 | 0 | } |
422 | 0 | if self.read(ApicRegister::XAPIC_ESR) > 0 { |
423 | 0 | break; |
424 | 0 | } |
425 | | } |
426 | 0 | } |
427 | | } |