diff --git a/local/patches/kernel/redox.patch b/local/patches/kernel/redox.patch index 1af7593e..0d69ead9 100644 --- a/local/patches/kernel/redox.patch +++ b/local/patches/kernel/redox.patch @@ -378,3 +378,197 @@ index 59e35265..80a40a01 100644 let signature = get_sdt_signature(sdt); if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { +diff --git a/src/acpi/madt/mod.rs b/src/acpi/madt/mod.rs +index abcdef12..bcdef123 100644 +--- a/src/acpi/madt/mod.rs ++++ b/src/acpi/madt/mod.rs +@@ -153,10 +153,45 @@ pub struct MadtLocalX2Apic { + _reserved: u16, + pub x2apic_id: u32, + pub flags: u32, + pub processor_uid: u32, + } + ++/// MADT Local APIC NMI (entry type 0x4) ++/// Configures NMI routing to a processor's LINT0/LINT1 pin. ++#[derive(Clone, Copy, Debug)] ++#[repr(C, packed)] ++pub struct MadtLocalApicNmi { ++ pub processor: u8, // 0xFF = all processors ++ pub flags: u16, // bits 0-1: polarity, bits 2-3: trigger mode ++ pub nmi_pin: u8, // 0 = LINT0, 1 = LINT1 ++} ++ ++/// MADT Local APIC Address Override (entry type 0x5) ++/// Provides 64-bit override for the 32-bit local APIC address. ++#[derive(Clone, Copy, Debug)] ++#[repr(C, packed)] ++pub struct MadtLapicAddressOverride { ++ _reserved: u16, ++ pub local_apic_address: u64, ++} ++ ++/// MADT Local x2APIC NMI (entry type 0xA) ++/// x2APIC equivalent of type 0x4 for APIC IDs >= 255. ++#[derive(Clone, Copy, Debug)] ++#[repr(C, packed)] ++pub struct MadtLocalX2ApicNmi { ++ _reserved: u16, ++ pub processor_uid: u32, // 0xFFFFFFFF = all processors ++ pub flags: u16, ++ pub nmi_pin: u8, // 0 = LINT0, 1 = LINT1 ++ _reserved2: u8, ++} ++ ++const _: () = assert!(size_of::() == 4); ++const _: () = assert!(size_of::() == 10); ++const _: () = assert!(size_of::() == 10); ++ + /// MADT Entries + #[derive(Debug)] + #[allow(dead_code)] + pub enum MadtEntry { +@@ -172,6 +207,12 @@ pub enum MadtEntry { + Gicd(&'static MadtGicd), + InvalidGicd(usize), + LocalX2Apic(&'static MadtLocalX2Apic), + InvalidLocalX2Apic(usize), ++ LocalApicNmi(&'static MadtLocalApicNmi), ++ InvalidLocalApicNmi(usize), ++ LapicAddressOverride(&'static MadtLapicAddressOverride), ++ InvalidLapicAddressOverride(usize), ++ LocalX2ApicNmi(&'static MadtLocalX2ApicNmi), ++ InvalidLocalX2ApicNmi(usize), + Unknown(u8), + } +diff --git a/src/acpi/madt/mod.rs b/src/acpi/madt/mod.rs +index bcdef123..cdef1234 100644 +--- a/src/acpi/madt/mod.rs ++++ b/src/acpi/madt/mod.rs +@@ -235,12 +235,40 @@ impl Iterator for MadtIter { + 0x9 => { + if entry_len == size_of::() + 2 { + MadtEntry::LocalX2Apic(unsafe { + &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalX2Apic) + }) + } else { + MadtEntry::InvalidLocalX2Apic(entry_len) + } + } ++ 0x4 => { ++ if entry_len == size_of::() + 2 { ++ MadtEntry::LocalApicNmi(unsafe { ++ &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalApicNmi) ++ }) ++ } else { ++ MadtEntry::InvalidLocalApicNmi(entry_len) ++ } ++ } ++ 0x5 => { ++ if entry_len == size_of::() + 2 { ++ MadtEntry::LapicAddressOverride(unsafe { ++ &*((self.sdt.data_address() + self.i + 2) ++ as *const MadtLapicAddressOverride) ++ }) ++ } else { ++ MadtEntry::InvalidLapicAddressOverride(entry_len) ++ } ++ } ++ 0xA => { ++ if entry_len == size_of::() + 2 { ++ MadtEntry::LocalX2ApicNmi(unsafe { ++ &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalX2ApicNmi) ++ }) ++ } else { ++ MadtEntry::InvalidLocalX2ApicNmi(entry_len) ++ } ++ } + _ => MadtEntry::Unknown(entry_type), + }; + +diff --git a/src/arch/x86_shared/device/local_apic.rs b/src/arch/x86_shared/device/local_apic.rs +index bfcc9a80..c0ffee01 100644 +--- a/src/arch/x86_shared/device/local_apic.rs ++++ b/src/arch/x86_shared/device/local_apic.rs +@@ -7,9 +7,12 @@ use crate::{ + arch::cpuid::cpuid, + ipi::IpiKind, + memory::{map_device_memory, PhysicalAddress}, + percpu::PercpuBlock, + }; + ++const IA32_X2APIC_LVT_LINT0: u32 = 0x835; ++const IA32_X2APIC_LVT_LINT1: u32 = 0x836; ++ + #[derive(Clone, Copy, Debug)] + pub struct ApicId(u32); + +@@ -260,9 +262,31 @@ impl LocalApic { + unsafe fn setup_error_int(&mut self) { + unsafe { + let vector = 49u32; + self.set_lvt_error(vector); + } + } ++ ++ /// Configure the LVT entry for NMI delivery on LINT0 or LINT1. ++ /// `nmi_pin`: 0 = LINT0, 1 = LINT1 ++ /// `flags`: MADT NMI flags — bits 0-1 polarity, bits 2-3 trigger mode ++ pub unsafe fn set_lvt_nmi(&mut self, nmi_pin: u8, flags: u16) { ++ let delivery_nmi: u32 = 0b100 << 8; ++ let polarity = if flags & 0x3 == 2 { 1u32 << 13 } else { 0 }; ++ let trigger = if (flags >> 2) & 0x3 == 2 { 1u32 << 15 } else { 0 }; ++ let lvt = delivery_nmi | polarity | trigger; ++ ++ if self.x2 { ++ let msr = if nmi_pin == 0 { ++ IA32_X2APIC_LVT_LINT0 ++ } else { ++ IA32_X2APIC_LVT_LINT1 ++ }; ++ wrmsr(msr, lvt.into()); ++ } else { ++ let offset: u32 = if nmi_pin == 0 { 0x350 } else { 0x360 }; ++ self.write(offset, lvt); ++ } ++ } + } + + #[repr(u8)] +diff --git a/src/acpi/madt/arch/x86.rs b/src/acpi/madt/arch/x86.rs +index 4203fec6..faceb00c 100644 +--- a/src/acpi/madt/arch/x86.rs ++++ b/src/acpi/madt/arch/x86.rs +@@ -132,6 +132,31 @@ pub(super) fn init(madt: Madt) { + RmmA::invalidate_all(); + } +- } ++ } else if let MadtEntry::LocalApicNmi(nmi) = madt_entry { ++ let target_id = nmi.processor; ++ if target_id == 0xFF { ++ debug!(" NMI: all processors, pin={}, flags={:#x}", nmi.nmi_pin, nmi.flags); ++ unsafe { local_apic.set_lvt_nmi(nmi.nmi_pin, nmi.flags); } ++ } else { ++ let my_apic_id = local_apic.id().get() as u8; ++ if target_id == my_apic_id { ++ debug!(" NMI: processor {}, pin={}, flags={:#x}", target_id, nmi.nmi_pin, nmi.flags); ++ unsafe { local_apic.set_lvt_nmi(nmi.nmi_pin, nmi.flags); } ++ } ++ } ++ } else if let MadtEntry::LocalX2ApicNmi(nmi) = madt_entry { ++ let target_uid = nmi.processor_uid; ++ if target_uid == 0xFFFFFFFF { ++ debug!(" x2APIC NMI: all processors, pin={}, flags={:#x}", nmi.nmi_pin, nmi.flags); ++ unsafe { local_apic.set_lvt_nmi(nmi.nmi_pin, nmi.flags); } ++ } else { ++ debug!(" x2APIC NMI: uid {}, pin={}, flags={:#x}", target_uid, nmi.nmi_pin, nmi.flags); ++ unsafe { local_apic.set_lvt_nmi(nmi.nmi_pin, nmi.flags); } ++ } ++ } else if let MadtEntry::LapicAddressOverride(addr) = madt_entry { ++ if addr.local_apic_address != 0 { ++ debug!(" LAPIC address override: {:#x}", addr.local_apic_address); ++ } ++ } + } + + // Unmap trampoline