1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
//! Local APIC driver.
//!
//! Specification can be found in Intel's System Programmer's Guide. The chapters
//! used as reference here will be from [this version] of the guide.
//!
//! [this version]: https://web.archive.org/web/20190212230443/https://software.intel.com/sites/default/files/managed/a4/60/325384-sdm-vol-3abcd.pdf

use crate::frame_allocator::PhysicalMemRegion;
use crate::mem::PhysicalAddress;
use crate::paging::MappingAccessRights;
use sunrise_libutils::io::Io;
use crate::paging::PAGE_SIZE;
use crate::paging::kernel_memory::get_kernel_memory;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::fmt;
use bit_field::BitField;

/// Specifies how the APICs listed in the destination field should act upon
/// reception of this signal. Note that certain Delivery Modes only operate as
/// intended when used in conjunction with a specific trigger Mode.
#[derive(Debug, Clone, Copy)]
pub enum DeliveryMode {
    /// Delivers the interrupt specified in the vector field.
    Fixed,
    /// Delivers an SMI interrupt to the processor core through the processor’s
    /// local SMI signal path. When using this delivery mode, the vector field
    /// should be set to 0x00 for future compatibility.
    SMI,
    /// Delivers an NMI interrupt to the processor. The vector information is
    /// ignored.
    NMI,

    /// Delivers an INIT request to the processor core, which causes the
    /// processor to perform an INIT. When using this delivery mode, the vector
    /// field should be set to 0x00 for future compatibility. Not supported for
    /// the LVT CMCI register, the LVT thermal monitor register, or the LVT
    /// performance counter register.
    INIT,
    /// Causes the processor to respond to the interrupt as if the interrupt
    /// originated in an externally connected (8259A-compatible) interrupt
    /// controller. A special INTA bus cycle corresponding to ExtINT, is routed
    /// to the external controller. The external controller is expected to supply
    /// the vector information. The APIC architecture supports only one ExtINT
    /// source in a system, usually contained in the compatibility bridge. Only
    /// one processor in the system should have an LVT entry configured to use
    /// the ExtINT delivery mode. Not supported for the LVT CMCI register, the
    /// LVT thermal monitor register, or the LVT performance counter register.
    ExtINT,
    /// Unknown delivery mode encountered.
    Unknown(u32)
}

impl From<DeliveryMode> for u32 {
    fn from(mode: DeliveryMode) -> u32 {
        match mode {
            DeliveryMode::Fixed          => 0b000,
            DeliveryMode::SMI            => 0b010,
            // RESERVED                  => 0b011,
            DeliveryMode::NMI            => 0b100,
            DeliveryMode::INIT           => 0b101,
            // RESERVED                  => 0b110,
            DeliveryMode::ExtINT         => 0b111,
            DeliveryMode::Unknown(val)   => val,
        }
    }
}

impl From<u32> for DeliveryMode {
    fn from(mode: u32) -> DeliveryMode {
        match mode {
            0b000 => DeliveryMode::Fixed,
            0b010 => DeliveryMode::SMI,
            // 0b011 RESERVED
            0b100 => DeliveryMode::NMI,
            0b101 => DeliveryMode::INIT,
            // 0b110 RESERVED
            0b111 => DeliveryMode::ExtINT,
            val => DeliveryMode::Unknown(val),
        }
    }
}

/// Selects the Timer Mode of the LVT Timer.
#[derive(Debug, Clone, Copy)]
enum TimerMode {
    /// One-shot mode using a count-down value.
    OneShot,
    /// Periodic mode reloading a count-down value.
    Periodic,
    /// TSC-Deadline mode using absolute target value in IA32_TSC_DEADLINE MSR.
    TscDeadline,
    /// Reserved value, might be used in later revision.
    Reserved
}

impl From<TimerMode> for u32 {
    fn from(mode: TimerMode) -> u32 {
        match mode {
            TimerMode::OneShot     => 0b00,
            TimerMode::Periodic    => 0b01,
            TimerMode::TscDeadline => 0b10,
            TimerMode::Reserved    => 0b11,
        }
    }
}

impl From<u32> for TimerMode {
    fn from(mode: u32) -> TimerMode {
        match mode {
            0b00 => TimerMode::OneShot,
            0b01 => TimerMode::Periodic,
            0b10 => TimerMode::TscDeadline,
            0b11 => TimerMode::Reserved,
            _    => unreachable!(),
        }
    }
}

/// Local APIC Registers are 128-bit wide, with the 32 lower bits containing the
/// actual register, and the top bits being reserved for future use.
#[repr(transparent)]
#[derive(Debug)]
struct LocalApicRegister<T = u32>(u128, PhantomData<T>);

impl<T: Copy> Io for LocalApicRegister<T> {
    type Value = T;

    fn read(&self) -> Self::Value {
        unsafe { (&self.0 as *const u128 as *const T).read_volatile() }
    }

    fn write(&mut self, value: Self::Value) {
        unsafe { (&mut self.0 as *mut u128 as *mut T).write_volatile(value) }
    }
}

bitfield! {
    /// The version and associated metadata of a Local APIC are described by this
    /// struct.
    ///
    /// See chapter 10.4.8: Local APIC Version Register
    #[repr(transparent)]
    #[derive(Clone, Copy)]
    pub struct LocalApicVersion(u32);
    impl Debug;
    /// The version numbers of the local APIC:
    ///
    /// - 00H - 0FH: 82489DX discrete APIC.
    /// - 10H - 15H: Integrated APIC.
    version, _: 7, 0;
    /// Shows the number of LVT entries minus 1.
    max_lvt_entry, _: 23, 16;
    /// Indicates whether software can inhibit the broadcast of EOI message by
    /// setting bit 12 of the Spurious Interrupt Vector Register.
    can_suppress_eoi_broadcast, _: 24;
}

bitfield! {
    /// Allows software to specify the manner in which the local interrupts are
    /// delivered to the processor core.
    ///
    /// See chapter 10.5.1: Local Vector Table
    #[repr(transparent)]
    #[derive(Clone, Copy)]
    pub struct LocalVector(u32);
    impl Debug;
    /// Interrupt vector number.
    vector, set_vector: 7, 0;
    /// Specifies the type of interrupt to be sent to the processor. Some
    /// delivery modes will only operate as intended when used in conjunction
    /// with a specific trigger mode. See [DeliveryMode] for documentation about
    /// available modes.
    from into DeliveryMode, delivery_mode, set_delivery_mode: 10, 8;
    /// Indicates the interrupt delivery status, as follows:
    ///
    /// - `false` (Idle): There is currently no activity for this interrupt
    ///   source, or the previous in-terrupt from this source was delivered to
    ///   the processor core and accepted.
    /// - `true` (Send Pending): Indicates that an interrupt from this source has
    ///   been delivered to the pro-cessor core but has not yet been accepted.
    delivery_status, _: 12;
    /// Specifies the polarity of the corresponding interrupt pin: (`false`)
    /// active high or (`true`) active low. 
    polarity, set_polarity: 13;
    /// For fixed mode, level-triggered interrupts; this flag is set when the
    /// local APIC accepts the interrupt for servicing and is reset when an EOI
    /// command is received from the processor. The meaning of this flag is
    /// undefined for edge-triggered interrupts and other delivery modes. 
    remote_irr, _: 14;
    /// Selects the trigger mode for the local LINT0 and LINT1 pins: (`false`)
    /// edge sensitive and (`true`) level sensitive. This flag is only used when
    /// the delivery mode is Fixed. When the delivery mode is NMI, SMI, or INIT,
    /// the trigger mode is always edge sensitive. When the delivery mode is
    /// ExtINT, the trigger mode is always level sensitive. The timer and error
    /// interrupts are always treated as edge sensitive.
    ///
    /// If the local APIC is not used in conjunction with an I/O APIC and fixed
    /// delivery mode is selected; the Pentium 4, Intel Xeon, and P6 family
    /// processors will always use level-sensitive triggering, regardless if
    /// edge-sensitive triggering is selected.
    ///
    /// Software should always set the trigger mode in the LVT LINT1 register to
    /// 0 (edge sensitive). Level-sensitive interrupts are not supported for
    /// LINT1.
    trigger_mode, set_trigger_mode: 15;
    /// Interrupt mask: (`false`) enables reception of the interrupt and (`true`)
    /// inhibits reception of the interrupt. When the local APIC handles a
    /// performance-monitoring counters interrupt, it automatically sets the mask
    /// flag in the LVT performance counter register. This flag is set to true on
    /// reset. It can be cleared only by software.
    masked, set_masked: 16;
    /// Selects timer mode. See [TimerMode] for possible values.
    from into TimerMode, timer_mode, set_timer_mode: 18, 17;
}

bitfield! {
    /// See chapter 10.9: Spurious Interrupt
    #[repr(transparent)]
    #[derive(Clone, Copy)]
    pub struct SpuriousInterrupt(u32);
    impl Debug;
    /// Determines the vector number to be delivered to the processor when the
    /// local APIC generates a spurious vector.
    spurious_vector, set_spurious_vector: 7, 0;
    /// Allows software to temporarily enable (1) or disable (0) the local APIC.
    ///
    /// See Section 10.4.3, Enabling or Disabling the Local APIC.
    apic_software_enable, set_apic_software_enable: 8;
    /// Determines if focus processor checking is enabled when using the
    /// lowest-priority delivery mode. In Pentium 4 and Intel Xeon processors,
    /// this bit is reserved and should be cleared to 0.
    focus_processor_checking, _: 9;
    /// Determines whether an EOI for a level-triggered interrupt causes EOI
    /// messages to be broadcast to the I/O APICs or not. The default value for
    /// this bit is false, indicating that EOI broadcasts are performed. This bit
    /// is reserved to false if the processor does not support EOI-broadcast
    /// suppression.
    ///
    /// See chapter 10.8.5 Signaling Interrupt Servicing Completion
    suppress_eoi_broadcast, set_suppress_eoi_broadcast: 12;
}


bitflags! {
    /// Contains the set of errors the LAPIC has encountered while running.
    ///
    /// See 10.5.3: Error Handling
    struct Error: u32 {
        /// Set when the local APIC detects a checksum error for a message that
        /// it sent on the APIC bus. Used only on P6 family and Pentium
        /// processors.
        const SEND_CHECKSUM_ERROR      = 1 << 0;
        /// Set when the local APIC detects a checksum error for a message that
        /// it received on the APIC bus. Used only on P6 family and Pentium
        /// processors.
        const RECEIVE_CHECKSUM_ERROR   = 1 << 1;
        /// Set when the local APIC detects that a message it sent was not
        /// accepted by any APIC on the APIC bus. Used only on P6 family and
        /// Pentium processors.
        const SEND_ACCEPT_ERROR        = 1 << 2;
        /// Set when the local APIC detects that the message it received was not
        /// accepted by any APIC on the APIC bus, including itself. Used only on
        /// P6 family and Pentium processors
        const RECEIVE_ACCEPT_ERROR     = 1 << 3;
        /// Set when the local APIC detects an attempt to send an IPI with the
        /// lowest-priority delivery mode and the local APIC does not support the
        /// sending of such IPIs. This bit is used on some Intel Core and Intel
        /// Xeon processors. As noted in chapter 10.6.2: Determining IPI
        /// Destination, the ability of a processor to send a lowest-priority IPI
        /// is model-specific and should be avoided.
        const REDIRECTABLE_IPI         = 1 << 4;
        /// Set when the local APIC detects an illegal vector (one in the range 0
        /// to 15) in the message that it is sending. This occurs as the result
        /// of a write to the ICR (in both xAPIC and x2APIC modes) or to SELF IPI
        /// register (x2APIC mode only) with an illegal vector.
        ///
        /// If the local APIC does not support the sending of lowest-priority
        /// IPIs and software writes the ICR to send a lowest-priority IPI with
        /// an illegal vector, the local APIC sets only the "redirectable IPI"
        /// error bit. The interrupt is not processed and hence the "Send Illegal
        /// Vector" bit is not set in the ESR.
        const SEND_ILLEGAL_VECTOR      = 1 << 5;
        /// Set when the local APIC detects an illegal vector (one in the range 0
        /// to 15) in an interrupt message it receives or in an interrupt
        /// generated locally from the local vector table or via a self IPI. Such
        /// interrupts are not delivered to the processor; the local APIC will
        /// never set an IRR bit in the range 0 to 15.
        const RECEIVE_ILLEGAL_VECTOR   = 1 << 6;
        /// Set when the local APIC is in xAPIC mode and software attempts to
        /// access a register that is reserved in the processor's local-APIC
        /// register-address space; The local-APIC register-address space
        /// comprises the 4 KBytes at the physical address specified in the
        /// IA32_APIC_BASE MSR. Used only on Intel Core, Intel Atom™, Pentium 4,
        /// Intel Xeon, and P6 family processors.
        ///
        /// In x2APIC mode, software accesses the APIC registers using the RDMSR
        /// and WRMSR instructions. Use of one of these instructions to access a
        /// reserved register cause a general-protection exception. They do not
        /// set the “Illegal Register Access” bit in the ESR.
        const ILLEGAL_REGISTER_ADDRESS = 1 << 7;
    }
}

/// Local APIC Register structure.
#[repr(C)]
#[allow(clippy::missing_docs_in_private_items)]
#[allow(missing_debug_implementations)] // Implementation is on LocalApic
struct LocalApicInternal {
    reserved_000: LocalApicRegister,
    reserved_010: LocalApicRegister,

    /// Unique ID of this Local APIC. May also be used as a way to uniquely
    /// identify a CPU.
    ///
    /// On power up, system hardware assigns a unique APIC ID to each local APIC.
    /// The hardware assigned APIC ID is based on system topology and includes
    /// encoding for socket position and cluster information.
    ///
    /// See chapter 10.4.6: Local APIC ID.
    local_apic_id: LocalApicRegister,
    /// Can be used to identify the APIC version. In addition, the register
    /// specifies the number of entries in the local vector table (LVT) for a
    /// specific implementation.
    ///
    /// See chapter 10.4.8: Local APIC Version.
    local_apic_version: LocalApicRegister<LocalApicVersion>,

    reserved_040: LocalApicRegister,
    reserved_050: LocalApicRegister,
    reserved_060: LocalApicRegister,
    reserved_070: LocalApicRegister,

    /// The task priority allows software to set a priority threshold for
    /// interrupting the processor. This mechanism enables the operating system
    /// to temporarily block low priority interrupts from disturbing
    /// high-priority work that the processor is doing. The ability to block such
    /// interrupts using task priority results from the way that the TPR controls
    /// the value of the processor-priority register.
    ///
    /// See chapter 10.8.3.1: Task and Processor Priorities
    task_priority: LocalApicRegister,
    /// Priority used for lowest-priority arbitration.
    ///
    /// Only available on Nahalem CPUs.
    ///
    /// See chapter 10.6.2.4: Lowest Priority Delivery Mode.
    arbitration_priority: LocalApicRegister,
    /// The processor-priority class determines the priority threshold for
    /// interrupting the processor. The processor will deliver only those
    /// interrupts that have an interrupt-priority class higher than the
    /// processor-priority class in the PPR. If the processor-priority class is
    /// 0, the PPR does not inhibit the delivery any interrupt; if it is 15, the
    /// processor inhibits the delivery of all interrupts. (The
    /// processor-priority mechanism does not affect the delivery of interrupts
    /// with the NMI, SMI, INIT, ExtINT, INIT-deassert, and start-up delivery
    /// modes.)
    ///
    /// See chapter 10.8.3.1: Task and Processor Priorities
    processor_priority: LocalApicRegister,
    /// For all interrupts except those delivered with the NMI, SMI, INIT,
    /// ExtINT, the start-up, or INIT-Deassert delivery mode, the interrupt
    /// handler must include a write to the end-of-interrupt (EOI) register. This
    /// write must occur at the end of the handler routine, sometime before the
    /// IRET instruction. This action indicates that the servicing of the current
    /// interrupt is complete and the local APIC can issue the next interrupt
    /// from the ISR.
    ///
    /// See chapter 10.8.5: Signaling Interrupt Servicing Completion
    end_of_interrupt: LocalApicRegister,
    /// Only available on Nahalem CPUs. Undocumented...
    remote_read: LocalApicRegister,
    /// Upon receiving an interrupt that was sent using logical destination mode,
    /// a local APIC compares the Message Destination Address with the values in
    /// its Logical Destination Register and Destination Format Register to
    /// determine if it should accept and handle the interrupt request.
    ///
    /// See chapter 10.6.2.2: Logical Destination Mode
    logical_destination: LocalApicRegister,
    /// See chapter 10.6.2.2: Logical Destination Mode
    destination_format: LocalApicRegister,
    /// A special situation may occur when a processor raises its task priority
    /// to be greater than or equal to the level of the interrupt for which the
    /// processor INTR signal is currently being asserted. If at the time the
    /// INTA cycle is issued, the interrupt that was to be dispensed has become
    /// masked (programmed by software), the local APIC will deliver a
    /// spurious-interrupt vector. Dispensing the spurious-interrupt vector does
    /// not affect the ISR, so the handler for this vector should return without
    /// an EOI.
    ///
    /// See chapter 10.9: Spurious Interrupt
    spurious_interrupt_vector: LocalApicRegister<SpuriousInterrupt>,
    /// See [LocalApic::in_service()] documentation.
    in_service0: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service1: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service2: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service3: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service4: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service5: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service6: LocalApicRegister,
    /// See [LocalApic::in_service()] documentation.
    in_service7: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode0: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode1: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode2: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode3: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode4: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode5: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode6: LocalApicRegister,
    /// See [LocalApic::trigger_mode()] documentation.
    trigger_mode7: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request0: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request1: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request2: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request3: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request4: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request5: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request6: LocalApicRegister,
    /// See [LocalApic::interrupt_request_register()] documentation.
    interrupt_request7: LocalApicRegister,
    /// The local APIC records errors detected during interrupt handling in the
    /// error status register (ESR).
    ///
    /// See chapter 10.5.3: Error Handling.
    error_status: LocalApicRegister<Error>,

    reserved_290: LocalApicRegister,
    reserved_2a0: LocalApicRegister,
    reserved_2b0: LocalApicRegister,
    reserved_2c0: LocalApicRegister,
    reserved_2d0: LocalApicRegister,
    reserved_2e0: LocalApicRegister,

    /// Specifies interrupt delivery when an overflow condition of corrected
    /// machine check error count reaching a threshold value occurred in a
    /// machine check bank supporting CMCI.
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_corrected_machine_interrupt: LocalApicRegister<LocalVector>,
    /// See [LocalApic::send_interrupt_command()] documentation.
    interrupt_command_register0: LocalApicRegister,
    /// See [LocalApic::send_interrupt_command()] documentation.
    interrupt_command_register1: LocalApicRegister,
    /// Specifies interrupt delivery when the APIC timer signals an interrupt.
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_timer: LocalApicRegister<LocalVector>,
    /// Specifies interrupt delivery when the thermal sensor generates an
    /// interrupt.
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_thermal_sensor: LocalApicRegister<LocalVector>,
    /// Specifies interrupt delivery when a performance counter generates an
    /// interrupt on overflow
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_performance_monitoring_counter: LocalApicRegister<LocalVector>,
    /// Specifies interrupt delivery when an interrupt is signaled at the LINT0.
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_lint0: LocalApicRegister<LocalVector>,
    /// Specifies interrupt delivery when an interrupt is signaled at the LINT1.
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_lint1: LocalApicRegister<LocalVector>,
    /// Specifies interrupt delivery when the APIC detects an internal error.
    ///
    /// See Section 10.5.1, "Local Vector Table".
    lvt_error: LocalApicRegister<LocalVector>,
    /// Initial count used by the APIC Timer.
    ///
    /// See Section 10.5.4: APIC Timer.
    initial_count: LocalApicRegister,
    /// Current count used by the APIC Timer.
    ///
    /// See Section 10.5.4: APIC Timer.
    current_count: LocalApicRegister,

    reserved_3a0: LocalApicRegister,
    reserved_3b0: LocalApicRegister,
    reserved_3c0: LocalApicRegister,
    reserved_3d0: LocalApicRegister,

    /// Divide configuration used by the APIC timer.
    ///
    /// See Section 10.5.4: APIC Timer.
    divide_configuration: LocalApicRegister,

    reserved_3f0: LocalApicRegister,
}
assert_eq_size!(LocalApicInternal, [u8; 0x400]);

// LocalApic should be cpu_local.
/// LocalApic driver.
pub struct LocalApic {
    /// Pointer to the LocalApic registers.
    internal: &'static UnsafeCell<LocalApicInternal>,
}

impl fmt::Debug for LocalApic {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            f.debug_struct("LocalApic")
                .field("local_apic_id", &(*self.internal.get()).local_apic_id.read())
                .field("local_apic_version", &(*self.internal.get()).local_apic_version.read())
                .field("task_priority", &(*self.internal.get()).task_priority.read())
                .field("arbitration_priority", &(*self.internal.get()).arbitration_priority.read())
                .field("processor_priority", &(*self.internal.get()).processor_priority.read())
                .field("end_of_interrupt", &(*self.internal.get()).end_of_interrupt.read())
                .field("remote_read", &(*self.internal.get()).remote_read.read())
                .field("logical_destination", &(*self.internal.get()).logical_destination.read())
                .field("destination_format", &(*self.internal.get()).destination_format.read())
                .field("spurious_interrupt_vector", &(*self.internal.get()).spurious_interrupt_vector.read())
                .field("in_service", &self.in_service())
                .field("trigger_mode", &self.trigger_mode())
                .field("interrupt_request_register", &self.interrupt_request_register())
                .field("error_status", &(*self.internal.get()).error_status.read())
                .field("lvt_corrected_machine_interrupt", &(*self.internal.get()).lvt_corrected_machine_interrupt.read())
                //.field("interrupt_command_register", &self.interrupt_command_register())
                .field("lvt_timer", &(*self.internal.get()).lvt_timer.read())
                .field("lvt_thermal_sensor", &(*self.internal.get()).lvt_thermal_sensor.read())
                .field("lvt_performance_monitoring_counter", &(*self.internal.get()).lvt_performance_monitoring_counter.read())
                .field("lvt_lint0", &(*self.internal.get()).lvt_lint0.read())
                .field("lvt_lint1", &(*self.internal.get()).lvt_lint1.read())
                .field("lvt_error", &(*self.internal.get()).lvt_error.read())
                .field("initial_count", &(*self.internal.get()).initial_count.read())
                .field("current_count", &(*self.internal.get()).current_count.read())
                .field("divide_configuration", &(*self.internal.get()).divide_configuration.read())
                .finish()
        }
    }
}

// TODO: LocalAPIC should not be Send/Sync.
// BODY: LocalApic should be stored in a cpu_local, removing the need for Send/
// BODY: Sync bounds. Problem is, we don't really have a way to create CPU Locals
// BODY: yet.
unsafe impl Send for LocalApic {}
unsafe impl Sync for LocalApic {}

impl LocalApic {
    /// Create a new LocalApic at the specified address.
    ///
    /// # Panics
    ///
    /// Panics if address is not page-aligned.
    ///
    /// # Safety
    ///
    /// `address` should be the physical address of a LocalApic device, and
    /// should not be shared.
    pub unsafe fn new(address: PhysicalAddress) -> Self {
        assert!(address.addr() % PAGE_SIZE == 0, "Unaligned local APIC address");

        let lapic = get_kernel_memory().map_phys_region(PhysicalMemRegion::on_fixed_mmio(address, 0x1000).unwrap(), MappingAccessRights::k_rw());

        let lapic = LocalApic {
            internal: (lapic.addr() as *const UnsafeCell<LocalApicInternal>).as_ref().unwrap(),
        };

        // Mask all the interrupt vectors.
        let mut masked_vector = LocalVector(0);
        masked_vector.set_masked(true);
        (*lapic.internal.get()).lvt_corrected_machine_interrupt.write(masked_vector);
        (*lapic.internal.get()).lvt_thermal_sensor.write(masked_vector);
        (*lapic.internal.get()).lvt_performance_monitoring_counter.write(masked_vector);
        (*lapic.internal.get()).lvt_lint0.write(masked_vector);
        (*lapic.internal.get()).lvt_lint1.write(masked_vector);
        (*lapic.internal.get()).lvt_error.write(masked_vector);

        lapic
    }

    /// 10.4.3 Enabling or Disabling the Local APIC
    ///
    /// The local APIC can be enabled or disabled in either of two ways:
    ///
    /// - Using the APIC global enable/disable flag in the IA32_APIC_BASE MSR (MSR address 1BH; see Figure 10-5)
    /// - Using the APIC software enable/disable flag in the spurious-interrupt vector register (see Figure 10-23)
    pub fn enable(&self) {
        // Enable the LAPIC. The MSR should be set by the BIOS, so we're only
        // going to set the spurious-interrupt vector register.
        unsafe {
            let mut val = (*self.internal.get()).spurious_interrupt_vector.read();
            val.set_apic_software_enable(true);
            (*self.internal.get()).spurious_interrupt_vector.write(val);
        }
    }

    /// Acknowledge the last interrupt, signaling an end of interrupt.
    ///
    /// See chapter 10.8: Handling Interrupts
    pub fn acknowledge(&self) {
        unsafe { (*self.internal.get()).end_of_interrupt.write(0); }
    }

    /// Unique ID of this Local APIC. May also be used as a way to uniquely
    /// identify a CPU.
    pub fn local_apic_id(&self) -> u32 {
        unsafe { (*self.internal.get()).local_apic_id.read() }
    }

    // Sucks that we don't have an u256 :').
    /// The ISR contains interrupt requests that have been dispatched to the
    /// processor for servicing, but not yet acknowledged by said processor.
    ///
    /// See chapter 10.8.4: Interrupt Acceptance for Fixed Interrupts.
    pub fn in_service(&self) -> [u32; 8] {
        unsafe {
            let in_service0 = (*self.internal.get()).in_service0.read();
            let in_service1 = (*self.internal.get()).in_service1.read();
            let in_service2 = (*self.internal.get()).in_service2.read();
            let in_service3 = (*self.internal.get()).in_service3.read();
            let in_service4 = (*self.internal.get()).in_service4.read();
            let in_service5 = (*self.internal.get()).in_service5.read();
            let in_service6 = (*self.internal.get()).in_service6.read();
            let in_service7 = (*self.internal.get()).in_service7.read();

            [
                in_service0,
                in_service1,
                in_service2,
                in_service3,
                in_service4,
                in_service5,
                in_service6,
                in_service7
            ]
        }
    }

    /// The trigger mode register (TMR) indicates the trigger mode of the
    /// interrupt. Upon acceptance of an interrupt into the IRR, the
    /// corresponding TMR bit is cleared for edge-triggered interrupts and set
    /// for level-triggered interrupts. If a TMR bit is set when an EOI cycle for
    /// its corresponding interrupt vector is generated, an EOI message is sent
    /// to all I/O APICs.
    ///
    /// See chapter 10.8.4: Interrupt Acceptance for Fixed Interrupts.
    pub fn trigger_mode(&self) -> [u32; 8] {
        unsafe {
            let trigger_mode0 = (*self.internal.get()).trigger_mode0.read();
            let trigger_mode1 = (*self.internal.get()).trigger_mode1.read();
            let trigger_mode2 = (*self.internal.get()).trigger_mode2.read();
            let trigger_mode3 = (*self.internal.get()).trigger_mode3.read();
            let trigger_mode4 = (*self.internal.get()).trigger_mode4.read();
            let trigger_mode5 = (*self.internal.get()).trigger_mode5.read();
            let trigger_mode6 = (*self.internal.get()).trigger_mode6.read();
            let trigger_mode7 = (*self.internal.get()).trigger_mode7.read();

            [
                trigger_mode0,
                trigger_mode1,
                trigger_mode2,
                trigger_mode3,
                trigger_mode4,
                trigger_mode5,
                trigger_mode6,
                trigger_mode7
            ]
        }
    }

    /// The IRR contains the active interrupt requests that have been accepted,
    /// but not yet dispatched to the processor for servicing.
    ///
    /// See chapter 10.8.4: Interrupt Acceptance for Fixed Interrupts.
    pub fn interrupt_request_register(&self) -> [u32; 8] {
        unsafe {
            let interrupt_request0 = (*self.internal.get()).interrupt_request0.read();
            let interrupt_request1 = (*self.internal.get()).interrupt_request1.read();
            let interrupt_request2 = (*self.internal.get()).interrupt_request2.read();
            let interrupt_request3 = (*self.internal.get()).interrupt_request3.read();
            let interrupt_request4 = (*self.internal.get()).interrupt_request4.read();
            let interrupt_request5 = (*self.internal.get()).interrupt_request5.read();
            let interrupt_request6 = (*self.internal.get()).interrupt_request6.read();
            let interrupt_request7 = (*self.internal.get()).interrupt_request7.read();

            [
                interrupt_request0,
                interrupt_request1,
                interrupt_request2,
                interrupt_request3,
                interrupt_request4,
                interrupt_request5,
                interrupt_request6,
                interrupt_request7
            ]
        }
    }

    /// Sends an IPI.
    ///
    /// See 10.6 Issuing Interprocessor Interrupts
    pub fn send_interrupt_command(&mut self, val: u64) {
        // First write the top bits, since writing to the low bits triggers the
        // IPI.
        unsafe {
            (*self.internal.get()).interrupt_command_register1.write(val.get_bits(32..64) as u32);
            (*self.internal.get()).interrupt_command_register0.write(val.get_bits(0..32) as u32);
        }
    }
}