1pub mod facp;
2
3pub use facp::Facp;
4
5use core::{
6 any::Any,
7 fmt,
8 mem::{self, MaybeUninit},
9 slice,
10};
11
12use alloc::{boxed::Box, vec::Vec};
13use byteorder::{ByteOrder, LittleEndian};
14
15use crate::{
16 cmdline::{self, LogAml},
17 io::{ByteStr, HexArray},
18 memory_management::{memory_layout::physical2virtual, virtual_space::VirtualSpace},
19 multiboot2::MultiBoot2Info,
20 sync::once::OnceLock,
21};
22
23use super::aml::Aml;
24
25const BIOS_RO_MEM_START: u64 = 0x000E0000;
26const BIOS_RO_MEM_END: u64 = 0x000FFFFF;
27
28unsafe fn get_acpi_table_bytes(physical_addr: u64) -> (DescriptionHeader, VirtualSpace<[u8]>) {
35 let header = VirtualSpace::<DescriptionHeader>::new(physical_addr).expect("Failed to map");
36 let len = header.length as usize;
37 let header_copy = *header;
38 drop(header);
39
40 let data_start_phys = physical_addr + mem::size_of::<DescriptionHeader>() as u64;
41 let data_len = len - mem::size_of::<DescriptionHeader>();
42
43 let header_data =
44 VirtualSpace::<u8>::new_slice(data_start_phys, data_len).expect("Failed to get slice");
45
46 let sum = header_copy
48 .sum()
49 .wrapping_add(header_data.iter().fold(0u8, |acc, &x| acc.wrapping_add(x)));
50 assert_eq!(sum, 0);
51
52 (header_copy, header_data)
54}
55
56unsafe fn get_table_from_body<T>(body: &[u8]) -> T {
62 let mut our_data_value = MaybeUninit::zeroed();
63 let out_data_slice =
64 slice::from_raw_parts_mut(our_data_value.as_mut_ptr() as *mut u8, mem::size_of::<T>());
65 out_data_slice[..body.len()].copy_from_slice(body);
66
67 our_data_value.assume_init()
68}
69
70fn get_struct_from_bytes<T>(data: &[u8]) -> T {
78 assert_eq!(data.len(), mem::size_of::<T>());
79
80 let mut our_data_value = MaybeUninit::zeroed();
81 let out_data_slice = unsafe {
83 slice::from_raw_parts_mut(our_data_value.as_mut_ptr() as *mut u8, mem::size_of::<T>())
84 };
85 out_data_slice.copy_from_slice(data);
86
87 unsafe { our_data_value.assume_init() }
90}
91
92static BIOS_TABLES: OnceLock<BiosTables> = OnceLock::new();
94
95pub fn init_acpi_tables(multiboot_info: &MultiBoot2Info) -> &'static BiosTables {
97 BIOS_TABLES.get_or_init(|| {
98 let rdsp = multiboot_info
99 .get_most_recent_rsdp()
100 .or_else(|| {
101 let mut rsdp_ptr = physical2virtual(BIOS_RO_MEM_START) as *const u8;
104 let end = physical2virtual(BIOS_RO_MEM_END) as *const u8;
105
106 while rsdp_ptr < end {
107 let str = unsafe { slice::from_raw_parts(rsdp_ptr, 8) };
110 if str == b"RSD PTR " {
111 let sum = unsafe {
114 slice::from_raw_parts(rsdp_ptr, 20)
115 .iter()
116 .fold(0u8, |acc, &x| acc.wrapping_add(x))
117 };
118 if sum == 0 {
119 let rsdp_ref = unsafe { &*(rsdp_ptr as *const RsdpV2) };
121 return if rsdp_ref.rsdp_v1.revision >= 2 {
122 Some(Rsdp::from_v2(rsdp_ref))
123 } else {
124 Some(Rsdp::from_v1(&rsdp_ref.rsdp_v1))
125 };
126 }
127 }
128 rsdp_ptr = unsafe { rsdp_ptr.add(1) };
130 }
131
132 None
133 })
134 .expect("No RSDP found");
135
136 unsafe { BiosTables::new(rdsp) }
138 })
139}
140
141pub fn get_acpi_tables() -> &'static BiosTables {
142 BIOS_TABLES.get()
143}
144
145#[repr(C, packed)]
146pub struct RsdpV1 {
147 signature: ByteStr<[u8; 8]>,
148 checksum: u8,
149 oem_id: ByteStr<[u8; 6]>,
150 revision: u8,
151 rsdt_address: u32,
152}
153
154#[repr(C, packed)]
156pub struct RsdpV2 {
157 rsdp_v1: RsdpV1,
158 length: u32,
160 xsdt_address: u64,
161 extended_checksum: u8,
162 reserved: [u8; 3],
163}
164
165#[repr(C, packed)]
167#[derive(Debug, Clone)]
168pub struct Rsdp {
169 pub signature: ByteStr<[u8; 8]>,
170 pub checksum: u8,
171 pub oem_id: ByteStr<[u8; 6]>,
172 pub revision: u8,
173 pub rsdt_address: u32,
174 pub length: u32,
175 pub xsdt_address: u64,
176 pub extended_checksum: u8,
177 pub reserved: [u8; 3],
178}
179
180impl Rsdp {
181 pub fn from_v1(v0: &RsdpV1) -> Self {
182 Self {
183 signature: v0.signature,
184 checksum: v0.checksum,
185 oem_id: v0.oem_id,
186 revision: v0.revision,
187 rsdt_address: v0.rsdt_address,
188 length: 0,
189 xsdt_address: 0,
190 extended_checksum: 0,
191 reserved: [0; 3],
192 }
193 }
194
195 pub fn from_v2(v2: &RsdpV2) -> Self {
196 Self {
197 signature: v2.rsdp_v1.signature,
198 checksum: v2.rsdp_v1.checksum,
199 oem_id: v2.rsdp_v1.oem_id,
200 revision: v2.rsdp_v1.revision,
201 rsdt_address: v2.rsdp_v1.rsdt_address,
202 length: v2.length,
203 xsdt_address: v2.xsdt_address,
204 extended_checksum: v2.extended_checksum,
205 reserved: v2.reserved,
206 }
207 }
208
209 unsafe fn rdst(&self) -> Rsdt {
216 let (header, body_bytes) = get_acpi_table_bytes(self.rsdt_address as _);
218
219 let entries_ptrs = body_bytes
222 .chunks(4)
223 .map(|a| u32::from_le_bytes(a.try_into().unwrap()))
224 .filter(|&a| a != 0)
225 .collect::<Vec<_>>();
226
227 drop(body_bytes);
229
230 let entries = entries_ptrs
231 .into_iter()
232 .map(|p| unsafe { DescriptorTable::from_physical_ptr(p) })
235 .collect();
236
237 let mut s = Rsdt { header, entries };
238 if let Some(facp) = s.get_table::<Facp>() {
240 if facp.dsdt != 0 {
241 s.entries
243 .push(DescriptorTable::from_physical_ptr(facp.dsdt));
244 }
245 }
246
247 s
248 }
249}
250
251#[derive(Debug, Clone)]
252pub struct Rsdt {
253 pub header: DescriptionHeader,
254 entries: Vec<DescriptorTable>,
255}
256
257impl Rsdt {
258 pub fn get_table<T: Any>(&self) -> Option<&T> {
259 self.entries
260 .iter()
261 .filter_map(|entry| match &entry.body {
262 DescriptorTableBody::Unknown(_) => None,
263 DescriptorTableBody::Apic(a) => Some(a.as_ref() as &dyn Any),
264 DescriptorTableBody::Facp(a) => Some(a.as_ref() as &dyn Any),
265 DescriptorTableBody::Hpet(a) => Some(a.as_ref() as &dyn Any),
266 DescriptorTableBody::Dsdt(a) => Some(a.as_ref() as &dyn Any),
267 DescriptorTableBody::Ssdt(a) => Some(a.as_ref() as &dyn Any),
268 DescriptorTableBody::Bgrt(a) => Some(a.as_ref() as &dyn Any),
269 DescriptorTableBody::Waet(a) => Some(a.as_ref() as &dyn Any),
270 DescriptorTableBody::Srat(a) => Some(a.as_ref() as &dyn Any),
271 })
272 .find_map(|obj| obj.downcast_ref::<T>())
273 }
274
275 pub fn iter_tables<T: Any>(&self) -> impl Iterator<Item = &T> {
276 self.entries
277 .iter()
278 .filter_map(|entry| match &entry.body {
279 DescriptorTableBody::Unknown(_) => None,
280 DescriptorTableBody::Apic(a) => Some(a.as_ref() as &dyn Any),
281 DescriptorTableBody::Facp(a) => Some(a.as_ref() as &dyn Any),
282 DescriptorTableBody::Hpet(a) => Some(a.as_ref() as &dyn Any),
283 DescriptorTableBody::Dsdt(a) => Some(a.as_ref() as &dyn Any),
284 DescriptorTableBody::Ssdt(a) => Some(a.as_ref() as &dyn Any),
285 DescriptorTableBody::Bgrt(a) => Some(a.as_ref() as &dyn Any),
286 DescriptorTableBody::Waet(a) => Some(a.as_ref() as &dyn Any),
287 DescriptorTableBody::Srat(a) => Some(a.as_ref() as &dyn Any),
288 })
289 .filter_map(|obj| obj.downcast_ref::<T>())
290 }
291}
292
293#[repr(C, packed)]
294#[derive(Debug, Clone, Copy)]
295pub struct DescriptionHeader {
296 pub signature: ByteStr<[u8; 4]>,
297 pub length: u32,
298 pub revision: u8,
299 pub checksum: u8,
300 pub oem_id: ByteStr<[u8; 6]>,
301 pub oem_table_id: ByteStr<[u8; 8]>,
302 pub oem_revision: u32,
303 pub creator_id: u32,
304 pub creator_revision: u32,
305}
306
307impl DescriptionHeader {
308 pub fn sum(&self) -> u8 {
309 let mut sum = 0u8;
310 let ptr = self as *const Self as *const u8;
311 for i in 0..mem::size_of::<Self>() {
312 sum = sum.wrapping_add(unsafe { ptr.add(i).read() });
313 }
314 sum
315 }
316}
317
318#[derive(Debug, Clone)]
319pub struct DescriptorTable {
320 pub header: DescriptionHeader,
321 pub body: DescriptorTableBody,
322}
323
324impl DescriptorTable {
325 pub unsafe fn from_physical_ptr(ptr: u32) -> Self {
331 let (header, body_bytes) = unsafe { get_acpi_table_bytes(ptr as _) };
333
334 let body = match &header.signature.0 {
335 b"APIC" => DescriptorTableBody::Apic(Box::new(Apic::from_body_bytes(&body_bytes))),
336 b"FACP" => DescriptorTableBody::Facp(Box::new(get_table_from_body(&body_bytes))),
337 b"HPET" => DescriptorTableBody::Hpet(Box::new(get_table_from_body(&body_bytes))),
338 b"DSDT" => DescriptorTableBody::Dsdt(Box::new(Xsdt::from_body_bytes(&body_bytes))),
339 b"SSDT" => DescriptorTableBody::Ssdt(Box::new(Xsdt::from_body_bytes(&body_bytes))),
340 b"BGRT" => DescriptorTableBody::Bgrt(Box::new(get_table_from_body(&body_bytes))),
341 b"WAET" => DescriptorTableBody::Waet(Box::new(get_table_from_body(&body_bytes))),
342 b"SRAT" => DescriptorTableBody::Srat(Box::new(Srat::from_body_bytes(&body_bytes))),
343 _ => DescriptorTableBody::Unknown(HexArray(body_bytes.to_vec())),
344 };
345
346 Self { header, body }
347 }
348}
349
350#[derive(Debug, Clone)]
351pub enum DescriptorTableBody {
352 Apic(Box<Apic>),
353 Facp(Box<Facp>),
354 Hpet(Box<Hpet>),
355 Dsdt(Box<Xsdt>),
356 Ssdt(Box<Xsdt>),
357 Bgrt(Box<Bgrt>),
358 Waet(Box<Waet>),
359 Srat(Box<Srat>),
360 #[allow(dead_code)]
361 Unknown(HexArray<Vec<u8>>),
362}
363
364#[derive(Debug, Clone)]
365#[allow(dead_code)]
366pub struct Apic {
367 pub local_apic_address: u32,
368 pub flags: u32,
369 pub interrupt_controller_structs: Vec<InterruptControllerStruct>,
370}
371
372impl Apic {
373 fn from_body_bytes(body: &[u8]) -> Self {
376 let mut apic = Self {
377 local_apic_address: LittleEndian::read_u32(body),
378 flags: LittleEndian::read_u32(&body[4..]),
379 interrupt_controller_structs: Vec::new(),
380 };
381
382 let mut remaining_body = &body[8..];
383 let mut remaining = body.len() - 8;
384 while remaining > 0 {
385 let struct_type = remaining_body[0];
386 let struct_len = remaining_body[1];
387 let struct_bytes = &remaining_body[2..struct_len as usize];
388 apic.interrupt_controller_structs
389 .push(InterruptControllerStruct::from_type_and_bytes(
390 struct_type,
391 struct_bytes,
392 ));
393 remaining -= struct_len as usize;
394 remaining_body = &remaining_body[struct_len as usize..];
395 }
396 apic
397 }
398}
399
400#[repr(u8)]
401#[derive(Debug, Clone)]
402#[allow(dead_code)]
403pub enum InterruptControllerStruct {
404 ProcessorLocalApic(ProcessorLocalApic) = 0,
405 IoApic(IoApic) = 1,
406 InterruptSourceOverride(InterruptSourceOverride) = 2,
407 NonMaskableInterrupt(NonMaskableInterrupt) = 3,
408 LocalApicNmi(LocalApicNmi) = 4,
409 LocalApicAddressOverride(LocalApicAddressOverride) = 5,
410 Unknown {
411 struct_type: u8,
412 bytes: HexArray<Vec<u8>>,
413 } = 255,
414}
415
416impl InterruptControllerStruct {
417 fn from_type_and_bytes(struct_type: u8, bytes: &[u8]) -> Self {
418 match struct_type {
419 0 => Self::ProcessorLocalApic(get_struct_from_bytes(bytes)),
420 1 => Self::IoApic(get_struct_from_bytes(bytes)),
421 2 => Self::InterruptSourceOverride(get_struct_from_bytes(bytes)),
422 3 => Self::NonMaskableInterrupt(get_struct_from_bytes(bytes)),
423 4 => Self::LocalApicNmi(get_struct_from_bytes(bytes)),
424 5 => Self::LocalApicAddressOverride(get_struct_from_bytes(bytes)),
425 _ => Self::Unknown {
426 struct_type,
427 bytes: HexArray(bytes.to_vec()),
428 },
429 }
430 }
431}
432
433#[repr(C, packed)]
435#[derive(Debug, Clone)]
436pub struct ProcessorLocalApic {
437 pub acpi_processor_id: u8,
438 pub apic_id: u8,
439 pub flags: u32,
440}
441
442#[repr(C, packed)]
443#[derive(Debug, Clone)]
444pub struct IoApic {
445 pub io_apic_id: u8,
446 pub reserved: u8,
447 pub io_apic_address: u32,
448 pub global_system_interrupt_base: u32,
449}
450
451#[repr(C, packed)]
452#[derive(Debug, Clone)]
453pub struct InterruptSourceOverride {
454 pub bus: u8,
455 pub source: u8,
456 pub global_system_interrupt: u32,
457 pub flags: u16,
458}
459
460#[repr(C, packed)]
461#[derive(Debug, Clone)]
462pub struct NonMaskableInterrupt {
463 pub flags: u16,
464 pub global_system_interrupt: u32,
465}
466
467#[repr(C, packed)]
468#[derive(Debug, Clone)]
469pub struct LocalApicNmi {
470 pub acpi_processor_uid: u8,
471 pub flags: u16,
472 pub local_apic_lint: u8,
473}
474
475#[repr(C, packed)]
476#[derive(Debug, Clone)]
477pub struct LocalApicAddressOverride {
478 pub reserved: u16,
479 pub local_apic_address: u64,
480}
481
482#[derive(Debug, Clone, Copy)]
483#[repr(C, packed)]
484pub struct ApicGenericAddress {
485 pub address_space_id: u8,
486 pub register_bit_width: u8,
487 pub register_bit_offset: u8,
488 pub reserved: u8,
489 pub address: u64,
490}
491impl ApicGenericAddress {
492 fn is_zero(&self) -> bool {
493 self.address == 0
494 && self.address_space_id == 0
495 && self.register_bit_offset == 0
496 && self.register_bit_width == 0
497 && self.reserved == 0
498 }
499}
500
501#[repr(C, packed)]
502#[derive(Debug, Clone)]
503pub struct Hpet {
504 pub event_timer_block_id: u32,
505 pub base_address: ApicGenericAddress,
506 pub hpet_number: u8,
507 pub main_counter_minimum_clock_tick: u16,
508 pub page_protection: u8,
509}
510
511#[derive(Debug, Clone)]
512#[allow(dead_code)]
513pub struct Xsdt {
515 pub aml: Aml,
516}
517
518impl Xsdt {
519 fn from_body_bytes(body: &[u8]) -> Self {
520 let aml_code = Aml::parse(body).unwrap();
521 Self { aml: aml_code }
522 }
523}
524
525#[derive(Debug, Clone)]
526#[repr(C, packed)]
527pub struct Bgrt {
528 version: u16,
529 status: u8,
530 image_type: u8,
531 pub image_address: u64,
532 pub image_offset_x: u32,
533 pub image_offset_y: u32,
534}
535
536#[derive(Debug, Clone)]
537#[allow(dead_code)]
538pub struct Waet {
539 emulated_device_flags: u32,
540}
541
542#[derive(Debug, Clone)]
543#[allow(dead_code)]
544pub struct Srat {
545 reserved1: u32,
546 reserved2: u64,
547 static_resource_allocation: Vec<StaticResourceAffinity>,
548}
549
550impl Srat {
551 fn from_body_bytes(body: &[u8]) -> Self {
552 let mut srat = Self {
553 reserved1: LittleEndian::read_u32(body),
554 reserved2: LittleEndian::read_u64(&body[4..]),
555 static_resource_allocation: Vec::new(),
556 };
557
558 let mut remaining_body = &body[12..];
559
560 let mut remaining = body.len() - 12;
561 while remaining > 0 {
562 let struct_type = remaining_body[0];
563 let struct_len = remaining_body[1];
564 let struct_bytes = &remaining_body[2..struct_len as usize];
565 srat.static_resource_allocation
566 .push(StaticResourceAffinity::from_type_and_bytes(
567 struct_type,
568 struct_bytes,
569 ));
570 remaining -= struct_len as usize;
571 remaining_body = &remaining_body[struct_len as usize..];
572 }
573 srat
574 }
575}
576
577#[repr(u8)]
578#[derive(Debug, Clone)]
579#[allow(dead_code)]
580pub enum StaticResourceAffinity {
581 ProcessorLocalAcpi(ProcessorLocalAcpiAffinity) = 0,
582 MemoryAffinity(MemoryAffinity) = 1,
583 ProcessorLocalX2Apic(ProcessorLocalX2ApicAffinity) = 2,
584 GiccAffinity(GiccAffinity) = 3,
585 GicInterruptTranslationService(GicInterruptTranslationServiceAffinity) = 4,
586 GenericInitiatorAffinity(GenericInitiatorAffinity) = 5,
587 Unknown {
588 struct_type: u8,
589 bytes: HexArray<Vec<u8>>,
590 } = 255,
591}
592
593impl StaticResourceAffinity {
594 fn from_type_and_bytes(struct_type: u8, bytes: &[u8]) -> Self {
595 match struct_type {
596 0 => Self::ProcessorLocalAcpi(get_struct_from_bytes(bytes)),
597 1 => Self::MemoryAffinity(get_struct_from_bytes(bytes)),
598 2 => Self::ProcessorLocalX2Apic(get_struct_from_bytes(bytes)),
599 3 => Self::GiccAffinity(get_struct_from_bytes(bytes)),
600 4 => Self::GicInterruptTranslationService(get_struct_from_bytes(bytes)),
601 5 => Self::GenericInitiatorAffinity(get_struct_from_bytes(bytes)),
602 _ => Self::Unknown {
603 struct_type,
604 bytes: HexArray(bytes.to_vec()),
605 },
606 }
607 }
608}
609
610#[derive(Debug, Clone)]
611#[repr(C, packed)]
612pub struct ProcessorLocalAcpiAffinity {
613 proximity_domain_low: u8,
614 apic_id: u8,
615 flags: u32,
616 local_sapic_eid: u8,
617 proximity_domain_high: [u8; 3],
618 clock_domain: u32,
619}
620
621#[derive(Debug, Clone)]
622#[repr(C, packed)]
623pub struct MemoryAffinity {
624 proximity_domain: u32,
625 reserved1: u16,
626 base_address_low: u32,
627 base_address_high: u32,
628 length_low: u32,
629 length_high: u32,
630 reserved2: u32,
631 flags: u32,
632 reserved3: u64,
633}
634
635#[derive(Debug, Clone)]
636#[repr(C, packed)]
637pub struct ProcessorLocalX2ApicAffinity {
638 reserved1: u16,
639 proximity_domain: u32,
640 x2apic_id: u32,
641 flags: u32,
642 clock_domain: u32,
643 reserved2: u32,
644}
645
646#[derive(Debug, Clone)]
647#[repr(C, packed)]
648pub struct GiccAffinity {
649 proximity_domain: u32,
650 acpi_processor_uid: u32,
651 flags: u32,
652 clock_domain: u32,
653}
654
655#[derive(Debug, Clone)]
656#[repr(C, packed)]
657pub struct GicInterruptTranslationServiceAffinity {
658 proximity_domain: u32,
659 reserved1: u16,
660 its_id: u32,
661}
662
663#[derive(Debug, Clone)]
664#[repr(C, packed)]
665pub struct GenericInitiatorAffinity {
666 reserved1: u8,
667 device_handle_type: u8,
668 proximity_domain: u32,
669 device_handle: [u8; 16],
670 flags: u32,
671 reserved2: u32,
672}
673
674#[derive(Debug, Clone)]
675pub struct BiosTables {
676 pub rsdp: Rsdp,
677 pub rsdt: Rsdt,
678}
679
680impl BiosTables {
681 pub unsafe fn new(rsdp: Rsdp) -> Self {
685 Self {
686 rsdt: rsdp.rdst(),
687 rsdp,
688 }
689 }
690}
691
692impl fmt::Display for BiosTables {
693 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
694 writeln!(f, "RSDP: {:X?}", self.rsdp)?;
695 writeln!(f, "RSDT: {:X?}", self.rsdt.header)?;
696 for entry in &self.rsdt.entries {
697 match &entry.body {
698 DescriptorTableBody::Dsdt(data) | DescriptorTableBody::Ssdt(data) => {
699 writeln!(f, "{:X?}", entry.header)?;
700
701 match cmdline::cmdline().log_aml {
702 LogAml::Normal => {
703 writeln!(f, "AML: \n{:#}", data.aml.code())?;
704 }
705 LogAml::Structured => {
706 writeln!(f, "AML: \n{:#}", data.aml.structured())?;
707 }
708 LogAml::Off => {}
709 }
710 }
711 DescriptorTableBody::Unknown(_) => {
712 writeln!(f, " {:X?}", entry.header)?;
713 writeln!(f, " {:X?}", entry.body)?;
714 }
715 _ => {
716 writeln!(f, "{:X?}", entry.body)?;
717 }
718 }
719 }
720 Ok(())
721 }
722}