ostd/arch/x86/kernel/acpi/
mod.rs1pub(in crate::arch) mod dmar;
4pub(in crate::arch) mod remapping;
5
6use core::{num::NonZeroU8, ptr::NonNull};
7
8use acpi::{
9 AcpiHandler, AcpiTables,
10 address::AddressSpace,
11 fadt::{Fadt, IaPcBootArchFlags},
12 mcfg::Mcfg,
13 rsdp::Rsdp,
14};
15use log::warn;
16use spin::Once;
17
18use crate::{
19 boot::{self, BootloaderAcpiArg},
20 mm::paddr_to_vaddr,
21};
22
23#[derive(Debug, Clone)]
24pub(crate) struct AcpiMemoryHandler {}
25
26impl AcpiHandler for AcpiMemoryHandler {
27 unsafe fn map_physical_region<T>(
28 &self,
29 physical_address: usize,
30 size: usize,
31 ) -> acpi::PhysicalMapping<Self, T> {
32 let virtual_address = NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap();
33
34 unsafe {
40 acpi::PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone())
41 }
42 }
43
44 fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {}
45}
46
47struct SyncAcpiTables(Option<AcpiTables<AcpiMemoryHandler>>);
48
49unsafe impl Sync for SyncAcpiTables {}
54
55static ACPI_TABLES: Once<SyncAcpiTables> = Once::new();
56
57pub(crate) fn get_acpi_tables() -> Option<&'static AcpiTables<AcpiMemoryHandler>> {
58 let acpi_tables = ACPI_TABLES.call_once(|| {
59 let acpi_tables = match boot::EARLY_INFO.get().unwrap().acpi_arg {
60 BootloaderAcpiArg::Rsdp(addr) => unsafe {
61 AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap()
62 },
63 BootloaderAcpiArg::Rsdt(addr) => unsafe {
64 AcpiTables::from_rsdt(AcpiMemoryHandler {}, 0, addr).unwrap()
65 },
66 BootloaderAcpiArg::Xsdt(addr) => unsafe {
67 AcpiTables::from_rsdt(AcpiMemoryHandler {}, 1, addr).unwrap()
68 },
69 BootloaderAcpiArg::NotProvided => {
70 let rsdp = unsafe { Rsdp::search_for_on_bios(AcpiMemoryHandler {}) };
72 match rsdp {
73 Ok(map) => unsafe {
74 AcpiTables::from_rsdp(AcpiMemoryHandler {}, map.physical_start()).unwrap()
75 },
76 Err(_) => {
77 warn!("ACPI info not found!");
78 return SyncAcpiTables(None);
79 }
80 }
81 }
82 };
83
84 SyncAcpiTables(Some(acpi_tables))
85 });
86
87 acpi_tables.0.as_ref()
88}
89
90#[derive(Debug)]
96pub struct AcpiInfo {
97 pub century_register: Option<NonZeroU8>,
99 pub boot_flags: Option<IaPcBootArchFlags>,
101 pub reset_port_and_val: Option<(u16, u8)>,
103 pub pci_ecam_region: Option<PciEcamRegion>,
105}
106
107#[derive(Debug)]
109pub struct PciEcamRegion {
110 pub base_address: u64,
112 pub bus_start: u8,
114 pub bus_end: u8,
116}
117
118pub static ACPI_INFO: Once<AcpiInfo> = Once::new();
120
121pub(in crate::arch) fn init() {
122 let mut acpi_info = AcpiInfo {
123 century_register: None,
124 boot_flags: None,
125 reset_port_and_val: None,
126 pci_ecam_region: None,
127 };
128
129 let Some(acpi_tables) = get_acpi_tables() else {
130 ACPI_INFO.call_once(|| acpi_info);
131 return;
132 };
133
134 if let Ok(fadt) = acpi_tables.find_table::<Fadt>() {
135 acpi_info.century_register = NonZeroU8::new(fadt.century);
137 acpi_info.boot_flags = Some(fadt.iapc_boot_arch);
138 if let Ok(reset_reg) = fadt.reset_register()
139 && reset_reg.address_space == AddressSpace::SystemIo
140 && let Ok(reset_port) = reset_reg.address.try_into()
141 {
142 acpi_info.reset_port_and_val = Some((reset_port, fadt.reset_value));
143 }
144 };
145
146 if let Ok(mcfg) = acpi_tables.find_table::<Mcfg>()
147 && let Some(mcfg_entry) = mcfg.entries().first()
150 {
151 acpi_info.pci_ecam_region = Some(PciEcamRegion {
152 base_address: mcfg_entry.base_address,
153 bus_start: mcfg_entry.bus_number_start,
154 bus_end: mcfg_entry.bus_number_end,
155 });
156 }
157
158 log::info!("[ACPI]: Collected information {:?}", acpi_info);
159
160 ACPI_INFO.call_once(|| acpi_info);
161}