Coverage Report

Created: 2026-06-07 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}