Nothing to see here, move along
1use crate::static_vec::StaticVec;
2
3use super::IrqOverride;
4
5const MADT_ENTRY_IOAPIC: u8 = 1;
6const MADT_ENTRY_OVERRIDE: u8 = 2;
7
8#[repr(C, packed)]
9struct MadtHeader {
10 _sdt_header: [u8; 36],
11 local_apic_addr: u32,
12 flags: u32,
13}
14
15#[repr(C, packed)]
16struct MadtEntryHeader {
17 entry_type: u8,
18 length: u8,
19}
20
21#[repr(C, packed)]
22struct IoApicEntry {
23 _header: MadtEntryHeader,
24 ioapic_id: u8,
25 _reserved: u8,
26 ioapic_addr: u32,
27 gsi_base: u32,
28}
29
30#[repr(C, packed)]
31struct InterruptOverrideEntry {
32 _header: MadtEntryHeader,
33 bus: u8,
34 source: u8,
35 gsi: u32,
36 flags: u16,
37}
38
39pub struct MadtInfo {
40 pub ioapic_addr: u64,
41 pub ioapic_gsi_base: u32,
42 pub irq_overrides: StaticVec<IrqOverride, 16>,
43}
44
45pub fn parse_madt(virt_addr: u64, length: u32) -> MadtInfo {
46 let base = virt_addr as *const u8;
47 let madt_header_size = core::mem::size_of::<MadtHeader>();
48
49 let entries = core::iter::successors(Some(madt_header_size), move |&offset| {
50 if offset >= length as usize {
51 return None;
52 }
53 let header_ptr = unsafe { base.add(offset) } as *const MadtEntryHeader;
54 let entry_len =
55 unsafe { core::ptr::addr_of!((*header_ptr).length).read_unaligned() } as usize;
56 if entry_len < 2 {
57 None
58 } else {
59 Some(offset + entry_len)
60 }
61 });
62
63 entries.take_while(|&offset| offset < length as usize).fold(
64 MadtInfo {
65 ioapic_addr: 0,
66 ioapic_gsi_base: 0,
67 irq_overrides: StaticVec::new(),
68 },
69 |mut info, offset| {
70 let entry_ptr = unsafe { base.add(offset) };
71 let header_ptr = entry_ptr as *const MadtEntryHeader;
72 let entry_type =
73 unsafe { core::ptr::addr_of!((*header_ptr).entry_type).read_unaligned() };
74
75 let entry_len =
76 unsafe { core::ptr::addr_of!((*header_ptr).length).read_unaligned() } as usize;
77
78 match entry_type {
79 MADT_ENTRY_IOAPIC if entry_len >= core::mem::size_of::<IoApicEntry>() => {
80 let ioapic_ptr = entry_ptr as *const IoApicEntry;
81 let addr =
82 unsafe { core::ptr::addr_of!((*ioapic_ptr).ioapic_addr).read_unaligned() };
83 let gsi_base =
84 unsafe { core::ptr::addr_of!((*ioapic_ptr).gsi_base).read_unaligned() };
85 match info.ioapic_addr {
86 0 => {}
87 _ => crate::kprintln!(
88 " MADT: WARN: multiple IOAPICs, overwriting previous at {:#x}",
89 info.ioapic_addr
90 ),
91 }
92 info.ioapic_addr = addr as u64;
93 info.ioapic_gsi_base = gsi_base;
94 crate::kprintln!(
95 " MADT: IOAPIC at {:#x}, GSI base {}",
96 info.ioapic_addr,
97 info.ioapic_gsi_base
98 );
99 }
100 MADT_ENTRY_OVERRIDE
101 if entry_len >= core::mem::size_of::<InterruptOverrideEntry>() =>
102 {
103 let override_ptr = entry_ptr as *const InterruptOverrideEntry;
104 let source =
105 unsafe { core::ptr::addr_of!((*override_ptr).source).read_unaligned() };
106 let gsi_raw =
107 unsafe { core::ptr::addr_of!((*override_ptr).gsi).read_unaligned() };
108 let flags =
109 unsafe { core::ptr::addr_of!((*override_ptr).flags).read_unaligned() };
110 let gsi = crate::arch::ioapic::Gsi::new(gsi_raw);
111 match info.irq_overrides.push(IrqOverride {
112 source_irq: source,
113 gsi,
114 flags,
115 }) {
116 Ok(()) => {
117 crate::kprintln!(" MADT: IRQ override {} -> GSI {}", source, gsi);
118 }
119 Err(_) => crate::kprintln!(
120 " MADT: IRQ override table full, dropping override {} -> GSI {}",
121 source,
122 gsi
123 ),
124 }
125 }
126 _ => {}
127 }
128
129 info
130 },
131 )
132}