Nothing to see here, move along
at main 252 lines 7.7 kB view raw
1pub mod dmar; 2pub mod madt; 3pub mod mcfg; 4 5use x86_64::structures::paging::OffsetPageTable; 6 7use crate::mem::addr; 8use crate::mem::phys::BitmapFrameAllocator; 9use crate::mem::virt; 10use crate::static_vec::StaticVec; 11 12const RSDP_SIGNATURE: &[u8; 8] = b"RSD PTR "; 13 14#[repr(C, packed)] 15struct Rsdp { 16 signature: [u8; 8], 17 checksum: u8, 18 oem_id: [u8; 6], 19 revision: u8, 20 rsdt_address: u32, 21} 22 23#[repr(C, packed)] 24struct Xsdp { 25 rsdp: Rsdp, 26 length: u32, 27 xsdt_address: u64, 28 extended_checksum: u8, 29 _reserved: [u8; 3], 30} 31 32#[repr(C, packed)] 33pub(crate) struct AcpiSdtHeader { 34 pub signature: [u8; 4], 35 pub length: u32, 36 pub revision: u8, 37 pub checksum: u8, 38 pub oem_id: [u8; 6], 39 pub oem_table_id: [u8; 8], 40 pub oem_revision: u32, 41 pub creator_id: u32, 42 pub creator_revision: u32, 43} 44 45pub struct AcpiInfo { 46 pub ioapic_addr: u64, 47 #[allow(dead_code)] 48 pub ioapic_gsi_base: u32, 49 pub irq_overrides: StaticVec<IrqOverride, 16>, 50 pub mcfg_entries: StaticVec<mcfg::McfgEntry, 4>, 51 pub dmar_info: Option<dmar::DmarInfo>, 52} 53 54#[derive(Clone, Copy)] 55pub struct IrqOverride { 56 pub source_irq: u8, 57 pub gsi: crate::arch::ioapic::Gsi, 58 #[allow(dead_code)] 59 pub flags: u16, 60} 61 62impl AcpiInfo { 63 pub fn gsi_for_irq(&self, irq: u8) -> crate::arch::ioapic::Gsi { 64 self.irq_overrides 65 .iter() 66 .find(|o| o.source_irq == irq) 67 .map(|o| o.gsi) 68 .unwrap_or(crate::arch::ioapic::Gsi::new(irq as u32)) 69 } 70} 71 72fn ensure_mapped( 73 phys: u64, 74 mapper: &mut OffsetPageTable, 75 allocator: &mut BitmapFrameAllocator, 76 hhdm_offset: u64, 77) -> Result<(), crate::error::KernelError> { 78 let page_aligned = phys & !0xFFF; 79 virt::map_mmio(mapper, allocator, page_aligned, hhdm_offset) 80} 81 82struct XsdtEntry { 83 table_phys: u64, 84 sig: [u8; 4], 85 length: u32, 86 virt_addr: u64, 87} 88 89pub fn parse( 90 rsdp_addr: u64, 91 mapper: &mut OffsetPageTable, 92 allocator: &mut BitmapFrameAllocator, 93 hhdm_offset: u64, 94) -> Option<AcpiInfo> { 95 if ensure_mapped(rsdp_addr, mapper, allocator, hhdm_offset).is_err() { 96 crate::kprintln!(" ACPI: failed to map RSDP page"); 97 return None; 98 } 99 100 let rsdp_virt = addr::phys_to_virt(x86_64::PhysAddr::new(rsdp_addr)); 101 let rsdp_ptr = rsdp_virt.as_ptr::<Rsdp>(); 102 103 let signature = unsafe { core::ptr::addr_of!((*rsdp_ptr).signature).read_unaligned() }; 104 if signature != *RSDP_SIGNATURE { 105 crate::kprintln!(" ACPI: invalid RSDP signature"); 106 return None; 107 } 108 109 let rsdp_checksum = (0u8..20).fold(0u8, |sum, i| { 110 sum.wrapping_add(unsafe { *(rsdp_virt.as_ptr::<u8>()).add(i as usize) }) 111 }); 112 if rsdp_checksum != 0 { 113 crate::kprintln!(" ACPI: RSDP checksum invalid"); 114 return None; 115 } 116 117 let revision = unsafe { core::ptr::addr_of!((*rsdp_ptr).revision).read_unaligned() }; 118 if revision < 2 { 119 crate::kprintln!(" ACPI: RSDP revision 0 (no XSDT)"); 120 return None; 121 } 122 123 let xsdp_checksum = (0u8..36).fold(0u8, |sum, i| { 124 sum.wrapping_add(unsafe { *(rsdp_virt.as_ptr::<u8>()).add(i as usize) }) 125 }); 126 if xsdp_checksum != 0 { 127 crate::kprintln!(" ACPI: XSDP extended checksum invalid"); 128 return None; 129 } 130 131 let xsdt_phys = { 132 let xsdp_ptr = rsdp_virt.as_ptr::<Xsdp>(); 133 unsafe { core::ptr::addr_of!((*xsdp_ptr).xsdt_address).read_unaligned() } 134 }; 135 136 if ensure_mapped(xsdt_phys, mapper, allocator, hhdm_offset).is_err() { 137 crate::kprintln!(" ACPI: failed to map XSDT page"); 138 return None; 139 } 140 141 let xsdt_virt = addr::phys_to_virt(x86_64::PhysAddr::new(xsdt_phys)); 142 let xsdt_hdr_ptr = xsdt_virt.as_ptr::<AcpiSdtHeader>(); 143 let entries_offset = core::mem::size_of::<AcpiSdtHeader>(); 144 let xsdt_length = 145 unsafe { core::ptr::addr_of!((*xsdt_hdr_ptr).length).read_unaligned() } as usize; 146 147 if xsdt_length < entries_offset { 148 crate::kprintln!(" ACPI: XSDT length too small"); 149 return None; 150 } 151 152 let xsdt_end_phys = xsdt_phys + xsdt_length as u64; 153 let xsdt_start_page = xsdt_phys & !0xFFF; 154 let xsdt_end_page = (xsdt_end_phys.saturating_sub(1)) & !0xFFF; 155 let xsdt_map_ok = (xsdt_start_page..=xsdt_end_page) 156 .step_by(4096) 157 .skip(1) 158 .try_fold((), |(), page| { 159 ensure_mapped(page, mapper, allocator, hhdm_offset) 160 }); 161 if xsdt_map_ok.is_err() { 162 crate::kprintln!(" ACPI: failed to map XSDT span"); 163 return None; 164 } 165 166 let xsdt_checksum = (0..xsdt_length).fold(0u8, |sum, i| { 167 sum.wrapping_add(unsafe { *(xsdt_virt.as_ptr::<u8>()).add(i) }) 168 }); 169 if xsdt_checksum != 0 { 170 crate::kprintln!(" ACPI: XSDT checksum invalid"); 171 return None; 172 } 173 174 let entry_count = (xsdt_length - entries_offset) / 8; 175 176 crate::kprintln!(" ACPI: XSDT at {:#x}, {} entries", xsdt_phys, entry_count); 177 178 let entries_ptr = unsafe { (xsdt_virt.as_ptr::<u8>()).add(entries_offset) as *const u64 }; 179 180 let seed = AcpiInfo { 181 ioapic_addr: 0, 182 ioapic_gsi_base: 0, 183 irq_overrides: StaticVec::new(), 184 mcfg_entries: StaticVec::new(), 185 dmar_info: None, 186 }; 187 188 let result = (0..entry_count) 189 .map(|i| unsafe { core::ptr::read_unaligned(entries_ptr.add(i)) }) 190 .filter_map(|table_phys| { 191 ensure_mapped(table_phys, mapper, allocator, hhdm_offset).ok()?; 192 let table_virt = addr::phys_to_virt(x86_64::PhysAddr::new(table_phys)); 193 let hdr_ptr = table_virt.as_ptr::<AcpiSdtHeader>(); 194 let sig = unsafe { core::ptr::addr_of!((*hdr_ptr).signature).read_unaligned() }; 195 let length = unsafe { core::ptr::addr_of!((*hdr_ptr).length).read_unaligned() }; 196 197 let table_end = table_phys + length as u64; 198 let start_page = table_phys & !0xFFF; 199 let end_page = (table_end.saturating_sub(1)) & !0xFFF; 200 let span_ok = (start_page..=end_page) 201 .step_by(4096) 202 .skip(1) 203 .try_fold((), |(), page| { 204 ensure_mapped(page, mapper, allocator, hhdm_offset) 205 }); 206 span_ok.ok()?; 207 208 Some(XsdtEntry { 209 table_phys, 210 sig, 211 length, 212 virt_addr: table_virt.as_u64(), 213 }) 214 }) 215 .fold(seed, |acc, entry| match &entry.sig { 216 b"APIC" => { 217 crate::kprintln!(" ACPI: found MADT at {:#x}", entry.table_phys); 218 let madt = madt::parse_madt(entry.virt_addr, entry.length); 219 AcpiInfo { 220 ioapic_addr: madt.ioapic_addr, 221 ioapic_gsi_base: madt.ioapic_gsi_base, 222 irq_overrides: madt.irq_overrides, 223 ..acc 224 } 225 } 226 b"MCFG" => { 227 crate::kprintln!(" ACPI: found MCFG at {:#x}", entry.table_phys); 228 let mcfg_entries = mcfg::parse_mcfg(entry.virt_addr, entry.length); 229 AcpiInfo { 230 mcfg_entries, 231 ..acc 232 } 233 } 234 b"DMAR" => { 235 crate::kprintln!(" ACPI: found DMAR at {:#x}", entry.table_phys); 236 let dmar = dmar::parse_dmar(entry.virt_addr, entry.length); 237 AcpiInfo { 238 dmar_info: Some(dmar), 239 ..acc 240 } 241 } 242 _ => acc, 243 }); 244 245 match result.ioapic_addr { 246 0 => { 247 crate::kprintln!(" ACPI: no MADT found"); 248 None 249 } 250 _ => Some(result), 251 } 252}