Nothing to see here, move along
at main 132 lines 4.5 kB view raw
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}