瀏覽代碼

Merge #68

68: Make local NMI line table optional r=IsaacWoods a=tomaka

The Bochs and VirtualBox emulators both seem to be missing the `LocalApicNmi` entry, which causes the `NoLocalNmiLineSpecified` error to be produced when parsing their tables.

I briefly looked at the ACPI specs. I'm not familiar at all with these specs, so I don't really know if this field is supposed to be mandatory or not. What the specs say, however, is that you can have multiple NMI lines.

Quoting section 5.2.12.7:

> Each Local APIC NMI connection requires a separate Local APIC NMI structure. For example, if the platform has 4 processors with ID 0-3 and NMI is connected LINT1 for processor 3 and 2, two Local APIC NMI entries would be needed in the MADT.

I therefore turned the `Option<_>` into a `Vec<_>`.

(Warning: I have no real clue what I'm doing. I'm not super familiar with ACPI in general.)

Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com>
bors[bot] 5 年之前
父節點
當前提交
5aeef5baac
共有 2 個文件被更改,包括 29 次插入10 次删除
  1. 13 1
      acpi/src/interrupt.rs
  2. 16 9
      acpi/src/madt.rs

+ 13 - 1
acpi/src/interrupt.rs

@@ -7,12 +7,24 @@ pub struct IoApic {
     pub global_system_interrupt_base: u32,
 }
 
+#[derive(Debug)]
+pub struct NmiLine {
+    pub processor: NmiProcessor,
+    pub line: LocalInterruptLine,
+}
+
 #[derive(Debug)]
 pub enum LocalInterruptLine {
     Lint0,
     Lint1,
 }
 
+#[derive(Debug)]
+pub enum NmiProcessor {
+    All,
+    ProcessorUid(u8),
+}
+
 #[derive(Debug)]
 pub enum Polarity {
     SameAsBus,
@@ -52,7 +64,7 @@ pub struct NmiSource {
 pub struct Apic {
     pub local_apic_address: u64,
     pub io_apics: Vec<IoApic>,
-    pub local_apic_nmi_line: LocalInterruptLine,
+    pub local_apic_nmi_lines: Vec<NmiLine>,
     pub interrupt_source_overrides: Vec<InterruptSourceOverride>,
     pub nmi_sources: Vec<NmiSource>,
 

+ 16 - 9
acpi/src/madt.rs

@@ -1,5 +1,5 @@
 use crate::{
-    interrupt::{Apic, InterruptModel, InterruptSourceOverride, IoApic, NmiSource, Polarity, TriggerMode},
+    interrupt::{Apic, InterruptModel, InterruptSourceOverride, IoApic, NmiLine, NmiProcessor, NmiSource, Polarity, TriggerMode},
     sdt::SdtHeader,
     Acpi,
     AcpiError,
@@ -17,7 +17,6 @@ pub enum MadtError {
     UnexpectedEntry,
     InterruptOverrideEntryHasInvalidBus,
     InvalidLocalNmiLine,
-    NoLocalNmiLineSpecified,
     MpsIntiInvalidPolarity,
     MpsIntiInvalidTriggerMode,
 }
@@ -394,10 +393,10 @@ fn parse_apic_model(acpi: &mut Acpi, mapping: &PhysicalMapping<Madt>) -> Result<
     use crate::interrupt::LocalInterruptLine;
 
     let mut local_apic_address = (*mapping).local_apic_address as u64;
-    let mut local_apic_nmi_line = None;
     let mut io_apic_count = 0;
     let mut iso_count = 0;
     let mut nmi_source_count = 0;
+    let mut local_nmi_line_count = 0;
     let mut processor_count = 0usize;
 
     // Do a pass over the entries so we know how much space we should reserve in the vectors
@@ -406,6 +405,7 @@ fn parse_apic_model(acpi: &mut Acpi, mapping: &PhysicalMapping<Madt>) -> Result<
             MadtEntry::IoApic(_) => io_apic_count += 1,
             MadtEntry::InterruptSourceOverride(_) => iso_count += 1,
             MadtEntry::NmiSource(_) => nmi_source_count += 1,
+            MadtEntry::LocalApicNmi(_) => local_nmi_line_count += 1,
             MadtEntry::LocalApic(_) => processor_count += 1,
             _ => (),
         }
@@ -414,6 +414,7 @@ fn parse_apic_model(acpi: &mut Acpi, mapping: &PhysicalMapping<Madt>) -> Result<
     let mut io_apics = Vec::with_capacity(io_apic_count);
     let mut interrupt_source_overrides = Vec::with_capacity(iso_count);
     let mut nmi_sources = Vec::with_capacity(nmi_source_count);
+    let mut local_apic_nmi_lines = Vec::with_capacity(local_nmi_line_count);
     acpi.application_processors = Vec::with_capacity(processor_count.saturating_sub(1)); // Subtract one for the BSP
 
     for entry in (*mapping).entries() {
@@ -476,10 +477,17 @@ fn parse_apic_model(acpi: &mut Acpi, mapping: &PhysicalMapping<Madt>) -> Result<
             }
 
             MadtEntry::LocalApicNmi(ref entry) => {
-                local_apic_nmi_line = Some(match entry.nmi_line {
-                    0 => LocalInterruptLine::Lint0,
-                    1 => LocalInterruptLine::Lint1,
-                    _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
+                local_apic_nmi_lines.push(NmiLine {
+                    processor: if entry.processor_id == 0xff {
+                        NmiProcessor::All
+                    } else {
+                        NmiProcessor::ProcessorUid(entry.processor_id)
+                    },
+                    line: match entry.nmi_line {
+                        0 => LocalInterruptLine::Lint0,
+                        1 => LocalInterruptLine::Lint1,
+                        _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
+                    },
                 })
             }
 
@@ -496,8 +504,7 @@ fn parse_apic_model(acpi: &mut Acpi, mapping: &PhysicalMapping<Madt>) -> Result<
     Ok(InterruptModel::Apic(Apic {
         local_apic_address,
         io_apics,
-        local_apic_nmi_line: local_apic_nmi_line
-            .ok_or(AcpiError::InvalidMadt(MadtError::NoLocalNmiLineSpecified))?,
+        local_apic_nmi_lines,
         interrupt_source_overrides,
         nmi_sources,
         also_has_legacy_pics: (*mapping).supports_8259(),