|
| 1 | +pub use self::register::ErrorStatus; |
1 | 2 | use super::{PinPolarity, TriggerMode};
|
2 | 3 | use crate::{
|
3 | 4 | cpu::{local, FeatureNotSupported, Msr},
|
@@ -331,6 +332,46 @@ impl LocalApic {
|
331 | 332 | self.register(register::END_OF_INTERRUPT).write(0);
|
332 | 333 | }
|
333 | 334 |
|
| 335 | + /// Reads the error stauts register (`ESR`) of the local APIC. |
| 336 | + /// |
| 337 | + /// Calling this method resets the value of the error status register. Any |
| 338 | + /// currently set error bits are cleared. If the same error bits are present |
| 339 | + /// in a subsequent call to `LocalApic::check_error`, they represent *new* |
| 340 | + /// instances of the same error. |
| 341 | + /// |
| 342 | + /// # Returns |
| 343 | + /// |
| 344 | + /// If any error bits are set, this method returns |
| 345 | + /// [`Err`]`(`[`ErrorStatus`]`)`. Otherwise, if no error bits are present, |
| 346 | + /// this method returns [`Ok`]`()`. |
| 347 | + pub fn check_error(&self) -> Result<(), register::ErrorStatus> { |
| 348 | + let esr = unsafe { |
| 349 | + let mut reg = self.register(register::ERROR_STATUS); |
| 350 | + |
| 351 | + // Per the Intel SDM, Vol 3A, Ch 7, Section 12.5.3, "Error |
| 352 | + // Handling": |
| 353 | + // |
| 354 | + // > The ESR is a write/read register. Before attempt to read from |
| 355 | + // > the ESR, software should first write to it. (The value written |
| 356 | + // > does not affect the values read subsequently; only zero may be |
| 357 | + // > written in x2APIC mode.) This write clears any previously |
| 358 | + // > logged errors and updates the ESR with any errors detected |
| 359 | + // > since the last write to the ESR. This write also rearms the |
| 360 | + // > APIC error interrupt triggering mechanism. |
| 361 | + // |
| 362 | + // So, first write a zero. |
| 363 | + reg.write(register::ErrorStatus::default()); |
| 364 | + reg.read() |
| 365 | + }; |
| 366 | + |
| 367 | + // Return the ESR value if error bits are set. |
| 368 | + if esr.is_error() { |
| 369 | + Err(esr) |
| 370 | + } else { |
| 371 | + Ok(()) |
| 372 | + } |
| 373 | + } |
| 374 | + |
334 | 375 | unsafe fn write_register<T, A>(&self, register: LocalApicRegister<T, A>, value: T)
|
335 | 376 | where
|
336 | 377 | LocalApicRegister<T, A>: RegisterAccess<Target = T, Access = A>,
|
@@ -517,8 +558,8 @@ pub mod register {
|
517 | 558 |
|
518 | 559 | /// Error Status Register (ESR)
|
519 | 560 | ///
|
520 |
| - /// **Access**: read-only |
521 |
| - ERROR_STATUS = 0x280, ReadOnly; |
| 561 | + /// **Access**: read/write |
| 562 | + ERROR_STATUS<ErrorStatus> = 0x280, ReadWrite; |
522 | 563 |
|
523 | 564 | /// LVT Corrected Machine Check Interrupt (CMCI) Register
|
524 | 565 | ///
|
@@ -575,6 +616,91 @@ pub mod register {
|
575 | 616 | TscDeadline = 0b10,
|
576 | 617 | }
|
577 | 618 | }
|
| 619 | + |
| 620 | + bitfield! { |
| 621 | + /// Value of the Error Status Register (ESR). |
| 622 | + /// |
| 623 | + /// See Intel SDM Vol. 3A, Ch. 7, Section 12.5.3, "Error Handling". |
| 624 | + #[derive(Default)] |
| 625 | + pub struct ErrorStatus<u32> { |
| 626 | + /// Set when the local APIC detects a checksum error for a message |
| 627 | + /// that it sent on the APIC bus. |
| 628 | + /// |
| 629 | + /// Used only on P6 family and Pentium processors. |
| 630 | + pub const SEND_CHECKSUM_ERROR: bool; |
| 631 | + |
| 632 | + /// Set when the local APIC detects a checksum error for a message |
| 633 | + /// that it received on the APIC bus. |
| 634 | + /// |
| 635 | + /// Used only on P6 family and Pentium processors. |
| 636 | + pub const RECV_CHECKSUM_ERROR: bool; |
| 637 | + |
| 638 | + /// Set when the local APIC detects that a message it sent was not |
| 639 | + /// accepted by any APIC on the APIC bus |
| 640 | + /// |
| 641 | + /// Used only on P6 family and Pentium processors. |
| 642 | + pub const SEND_ACCEPT_ERROR: bool; |
| 643 | + |
| 644 | + /// Set when the local APIC detects that a message it received was |
| 645 | + /// not accepted by any APIC on the APIC bus. |
| 646 | + /// |
| 647 | + /// Used only on P6 family and Pentium processors. |
| 648 | + pub const RECV_ACCEPT_ERROR: bool; |
| 649 | + |
| 650 | + /// Set when the local APIC detects an attempt to send an IPI with |
| 651 | + /// the lowest-priority delivery mode and the local APIC does not |
| 652 | + /// support the sending of such IPIs. This bit is used on some Intel |
| 653 | + /// Core and Intel Xeon processors. |
| 654 | + pub const REDIRECTABLE_IPI: bool; |
| 655 | + |
| 656 | + /// Set when the local APIC detects an illegal vector (one in the |
| 657 | + /// range 0 to 15) in the message that it is sending. This occurs as |
| 658 | + /// the result of a write to the ICR (in both xAPIC and x2APIC |
| 659 | + /// modes) or to SELF IPI register (x2APIC mode only) with an |
| 660 | + /// illegal vector. |
| 661 | + /// |
| 662 | + /// If the local APIC does not support the sending of |
| 663 | + /// lowest-priority IPIs and software writes the ICR to send a |
| 664 | + /// lowest-priority IPI with an illegal vector, the local APIC sets |
| 665 | + /// only the “redirectable IPI” error bit. The interrupt is not |
| 666 | + /// processed and hence the “Send Illegal Vector” bit is not set in |
| 667 | + /// the ESR. |
| 668 | + pub const SEND_ILLEGAL_VECTOR: bool; |
| 669 | + |
| 670 | + /// Set when the local APIC detects an illegal vector (one in the |
| 671 | + /// range 0 to 15) in an interrupt message it receives or in an |
| 672 | + /// interrupt generated locally from the local vector table or via a |
| 673 | + /// self IPI. Such interrupts are not delivered to the processor; |
| 674 | + /// the local APIC will never set an IRR bit in the range 0 to 15. |
| 675 | + pub const RECV_ILLEGAL_VECTOR: bool; |
| 676 | + |
| 677 | + /// Set when the local APIC is in xAPIC mode and software attempts |
| 678 | + /// to access a register that is reserved in the processor's |
| 679 | + /// local-APIC register-address space; see Table 10-1. (The |
| 680 | + /// local-APIC register-address spacemprises the 4 KBytes at the |
| 681 | + /// physical address specified in the `IA32_APIC_BASE` MSR.) Used only |
| 682 | + /// on Intel Core, Intel Atom, Pentium 4, Intel Xeon, and P6 family |
| 683 | + /// processors. |
| 684 | + /// |
| 685 | + /// In x2APIC mode, software accesses the APIC registers using the |
| 686 | + /// `RDMSR` and `WRMSR` instructions. Use of one of these |
| 687 | + /// instructions to access a reserved register cause a |
| 688 | + /// general-protection exception (see Section 10.12.1.3). They do |
| 689 | + /// not set the “Illegal Register Access” bit in the ESR. |
| 690 | + pub const ILLEGAL_REGISTER_ACCESS: bool; |
| 691 | + } |
| 692 | + |
| 693 | + } |
| 694 | + |
| 695 | + impl ErrorStatus { |
| 696 | + /// Returns `true` if an error is present, or `false` if no error |
| 697 | + /// bits are set. |
| 698 | + pub fn is_error(&self) -> bool { |
| 699 | + // Mask out the reserved bits, just in case they have values in the, |
| 700 | + // (they shouldn't, per the SDM, but...who knows!) |
| 701 | + self.bits() & 0b1111_1111 != 0 |
| 702 | + } |
| 703 | + } |
578 | 704 | }
|
579 | 705 |
|
580 | 706 | #[cfg(test)]
|
|
0 commit comments