1use bit_field::BitField;
7use core::fmt;
8
9use super::*;
10use crate::msr::{rdmsr, wrmsr, IA32_APIC_BASE, IA32_TSC_DEADLINE};
11
12pub const XAPIC_ID: u32 = 0x020;
14
15pub const XAPIC_VERSION: u32 = 0x030;
17
18pub const XAPIC_TPR: u32 = 0x080;
20
21pub const XAPIC_PPR: u32 = 0x0A0;
23
24pub const XAPIC_EOI: u32 = 0x0B0;
26
27pub const XAPIC_LDR: u32 = 0x0D0;
29
30pub const XAPIC_SVR: u32 = 0x0F0;
32
33pub const XAPIC_ISR0: u32 = 0x100;
35
36pub const XAPIC_ISR1: u32 = 0x110;
38
39pub const XAPIC_ISR2: u32 = 0x120;
41
42pub const XAPIC_ISR3: u32 = 0x130;
44
45pub const XAPIC_ISR4: u32 = 0x140;
47
48pub const XAPIC_ISR5: u32 = 0x150;
50
51pub const XAPIC_ISR6: u32 = 0x160;
53
54pub const XAPIC_ISR7: u32 = 0x170;
56
57pub const XAPIC_TMR0: u32 = 0x180;
59
60pub const XAPIC_TMR1: u32 = 0x190;
62
63pub const XAPIC_TMR2: u32 = 0x1A0;
65
66pub const XAPIC_TMR3: u32 = 0x1B0;
68
69pub const XAPIC_TMR4: u32 = 0x1C0;
71
72pub const XAPIC_TMR5: u32 = 0x1D0;
74
75pub const XAPIC_TMR6: u32 = 0x1E0;
77
78pub const XAPIC_TMR7: u32 = 0x1F0;
80
81pub const XAPIC_IRR0: u32 = 0x200;
83
84pub const XAPIC_IRR1: u32 = 0x210;
86
87pub const XAPIC_IRR2: u32 = 0x220;
89
90pub const XAPIC_IRR3: u32 = 0x230;
92
93pub const XAPIC_IRR4: u32 = 0x240;
95
96pub const XAPIC_IRR5: u32 = 0x250;
98
99pub const XAPIC_IRR6: u32 = 0x260;
101
102pub const XAPIC_IRR7: u32 = 0x270;
104
105pub const XAPIC_ESR: u32 = 0x280;
107
108pub const XAPIC_LVT_CMCI: u32 = 0x2F0;
110
111pub const XAPIC_ICR0: u32 = 0x300;
113
114pub const XAPIC_ICR1: u32 = 0x310;
116
117pub const XAPIC_LVT_TIMER: u32 = 0x320;
119
120pub const XAPIC_LVT_THERMAL: u32 = 0x330;
122
123pub const XAPIC_LVT_PMI: u32 = 0x340;
125
126pub const XAPIC_LVT_LINT0: u32 = 0x350;
128
129pub const XAPIC_LVT_LINT1: u32 = 0x360;
131
132pub const XAPIC_LVT_ERROR: u32 = 0x370;
134
135pub const XAPIC_TIMER_INIT_COUNT: u32 = 0x380;
137
138pub const XAPIC_TIMER_CURRENT_COUNT: u32 = 0x390;
140
141pub const XAPIC_TIMER_DIV_CONF: u32 = 0x3E0;
143
144#[derive(Copy, Clone)]
145#[allow(dead_code, non_camel_case_types)]
146enum 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#[allow(clippy::clippy::upper_case_acronyms)]
195pub struct XAPIC {
196 mmio_region: &'static mut [u32],
198 base: u64,
200}
201
202impl fmt::Debug for XAPIC {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 f.debug_struct("XAPIC")
205 .field("XAPIC_ID", &self.read(ApicRegister::XAPIC_ID))
206 .field("XAPIC_VERSION", &self.read(ApicRegister::XAPIC_VERSION))
207 .field("XAPIC_TPR", &self.read(ApicRegister::XAPIC_TPR))
208 .field("XAPIC_PPR", &self.read(ApicRegister::XAPIC_PPR))
209 .field("XAPIC_EOI", &self.read(ApicRegister::XAPIC_EOI))
210 .field("XAPIC_LDR", &self.read(ApicRegister::XAPIC_LDR))
211 .field("XAPIC_SVR", &self.read(ApicRegister::XAPIC_SVR))
212 .field("XAPIC_ISR0", &self.read(ApicRegister::XAPIC_ISR0))
213 .field("XAPIC_ISR1", &self.read(ApicRegister::XAPIC_ISR1))
214 .field("XAPIC_ISR2", &self.read(ApicRegister::XAPIC_ISR2))
215 .field("XAPIC_ISR3", &self.read(ApicRegister::XAPIC_ISR3))
216 .field("XAPIC_ISR4", &self.read(ApicRegister::XAPIC_ISR4))
217 .field("XAPIC_ISR5", &self.read(ApicRegister::XAPIC_ISR5))
218 .field("XAPIC_ISR6", &self.read(ApicRegister::XAPIC_ISR6))
219 .field("XAPIC_ISR7", &self.read(ApicRegister::XAPIC_ISR7))
220 .field("XAPIC_TMR0", &self.read(ApicRegister::XAPIC_TMR0))
221 .field("XAPIC_TMR1", &self.read(ApicRegister::XAPIC_TMR1))
222 .field("XAPIC_TMR2", &self.read(ApicRegister::XAPIC_TMR2))
223 .field("XAPIC_TMR3", &self.read(ApicRegister::XAPIC_TMR3))
224 .field("XAPIC_TMR4", &self.read(ApicRegister::XAPIC_TMR4))
225 .field("XAPIC_TMR5", &self.read(ApicRegister::XAPIC_TMR5))
226 .field("XAPIC_TMR6", &self.read(ApicRegister::XAPIC_TMR6))
227 .field("XAPIC_TMR7", &self.read(ApicRegister::XAPIC_TMR7))
228 .field("XAPIC_IRR0", &self.read(ApicRegister::XAPIC_IRR0))
229 .field("XAPIC_IRR1", &self.read(ApicRegister::XAPIC_IRR1))
230 .field("XAPIC_IRR2", &self.read(ApicRegister::XAPIC_IRR2))
231 .field("XAPIC_IRR3", &self.read(ApicRegister::XAPIC_IRR3))
232 .field("XAPIC_IRR4", &self.read(ApicRegister::XAPIC_IRR4))
233 .field("XAPIC_IRR5", &self.read(ApicRegister::XAPIC_IRR5))
234 .field("XAPIC_IRR6", &self.read(ApicRegister::XAPIC_IRR6))
235 .field("XAPIC_IRR7", &self.read(ApicRegister::XAPIC_IRR7))
236 .field("XAPIC_ESR", &self.read(ApicRegister::XAPIC_ESR))
237 .field("XAPIC_LVT_CMCI", &self.read(ApicRegister::XAPIC_LVT_CMCI))
238 .field("XAPIC_ICR0", &self.read(ApicRegister::XAPIC_ICR0))
239 .field("XAPIC_ICR1", &self.read(ApicRegister::XAPIC_ICR1))
240 .field("XAPIC_LVT_TIMER", &self.read(ApicRegister::XAPIC_LVT_TIMER))
241 .field(
242 "XAPIC_LVT_THERMAL",
243 &self.read(ApicRegister::XAPIC_LVT_THERMAL),
244 )
245 .field("XAPIC_LVT_PMI", &self.read(ApicRegister::XAPIC_LVT_PMI))
246 .field("XAPIC_LVT_LINT0", &self.read(ApicRegister::XAPIC_LVT_LINT0))
247 .field("XAPIC_LVT_LINT1", &self.read(ApicRegister::XAPIC_LVT_LINT1))
248 .field("XAPIC_LVT_ERROR", &self.read(ApicRegister::XAPIC_LVT_ERROR))
249 .field(
250 "XAPIC_TIMER_INIT_COUNT",
251 &self.read(ApicRegister::XAPIC_TIMER_INIT_COUNT),
252 )
253 .field(
254 "XAPIC_TIMER_CURRENT_COUNT",
255 &self.read(ApicRegister::XAPIC_TIMER_CURRENT_COUNT),
256 )
257 .field(
258 "XAPIC_TIMER_DIV_CONF",
259 &self.read(ApicRegister::XAPIC_TIMER_DIV_CONF),
260 )
261 .finish()
262 }
263}
264
265impl XAPIC {
266 pub fn new(apic_region: &'static mut [u32]) -> XAPIC {
271 unsafe {
272 XAPIC {
273 mmio_region: apic_region,
274 base: rdmsr(IA32_APIC_BASE),
275 }
276 }
277 }
278
279 pub fn attach(&mut self) {
281 unsafe {
283 self.base = rdmsr(IA32_APIC_BASE);
285 self.base.set_bit(11, true);
286 wrmsr(IA32_APIC_BASE, self.base);
287
288 let svr: u32 = 1 << 8 | 15;
290 self.write(ApicRegister::XAPIC_SVR, svr);
291 }
292 }
293
294 pub fn detach(&mut self) {
296 unsafe {
297 self.base = rdmsr(IA32_APIC_BASE);
298 self.base.set_bit(11, false); wrmsr(IA32_APIC_BASE, self.base);
300 }
301 }
302
303 fn read(&self, offset: ApicRegister) -> u32 {
305 assert!(offset as usize % 4 == 0);
306 let index = offset as usize / 4;
307 unsafe { core::ptr::read_volatile(&self.mmio_region[index]) }
308 }
309
310 fn write(&mut self, offset: ApicRegister, val: u32) {
312 assert!(offset as usize % 4 == 0);
313 let index = offset as usize / 4;
314 unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) }
315 }
316}
317
318impl ApicControl for XAPIC {
319 fn bsp(&self) -> bool {
321 (self.base & (1 << 8)) > 0
322 }
323
324 fn id(&self) -> u32 {
326 self.read(ApicRegister::XAPIC_ID)
327 }
328
329 fn logical_id(&self) -> u32 {
330 self.read(ApicRegister::XAPIC_LDR)
331 }
332
333 fn version(&self) -> u32 {
335 self.read(ApicRegister::XAPIC_VERSION)
336 }
337
338 fn eoi(&mut self) {
340 self.write(ApicRegister::XAPIC_EOI, 0);
341 }
342
343 fn tsc_enable(&mut self, vector: u8) {
345 let mut lvt: u32 = self.read(ApicRegister::XAPIC_LVT_TIMER);
346 lvt &= !0xff;
347 lvt |= vector as u32;
348
349 lvt.set_bit(16, false);
350 lvt.set_bit(17, false);
351 lvt.set_bit(18, true);
352 self.write(ApicRegister::XAPIC_LVT_TIMER, lvt);
353 }
354
355 fn tsc_set(&self, value: u64) {
357 unsafe {
358 wrmsr(IA32_TSC_DEADLINE, value);
359 }
360 }
361
362 unsafe fn ipi_init(&mut self, core: ApicId) {
364 let icr = Icr::for_xapic(
365 0,
366 core,
367 DestinationShorthand::NoShorthand,
368 DeliveryMode::Init,
369 DestinationMode::Physical,
370 DeliveryStatus::Idle,
371 Level::Assert,
372 TriggerMode::Level,
373 );
374 self.send_ipi(icr);
375 }
376
377 unsafe fn ipi_init_deassert(&mut self) {
379 let icr = Icr::for_xapic(
380 0,
381 ApicId::XApic(0),
382 DestinationShorthand::AllIncludingSelf,
384 DeliveryMode::Init,
385 DestinationMode::Physical,
386 DeliveryStatus::Idle,
387 Level::Deassert,
388 TriggerMode::Level,
389 );
390 self.send_ipi(icr);
391 }
392
393 unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8) {
395 let icr = Icr::for_xapic(
396 start_page,
397 core,
398 DestinationShorthand::NoShorthand,
399 DeliveryMode::StartUp,
400 DestinationMode::Physical,
401 DeliveryStatus::Idle,
402 Level::Assert,
403 TriggerMode::Edge,
404 );
405 self.send_ipi(icr);
406 }
407
408 unsafe fn send_ipi(&mut self, icr: Icr) {
410 self.write(ApicRegister::XAPIC_ESR, 0);
411 self.write(ApicRegister::XAPIC_ESR, 0);
412
413 self.write(ApicRegister::XAPIC_ICR1, icr.upper());
415 self.write(ApicRegister::XAPIC_ICR0, icr.lower());
416
417 loop {
418 let icr = self.read(ApicRegister::XAPIC_ICR0);
419 if (icr >> 12 & 0x1) == 0 {
420 break;
421 }
422 if self.read(ApicRegister::XAPIC_ESR) > 0 {
423 break;
424 }
425 }
426 }
427}