ostd/arch/x86/kernel/acpi/
mod.rs1macro_rules! __log_prefix {
5 () => {
6 "acpi: "
7 };
8}
9
10pub(in crate::arch) mod dmar;
11pub(in crate::arch) mod remapping;
12
13use core::{num::NonZeroU8, ptr::NonNull};
14
15use acpi::{
16 AcpiHandler, AcpiTables,
17 address::AddressSpace,
18 fadt::{Fadt, IaPcBootArchFlags},
19 mcfg::Mcfg,
20 rsdp::Rsdp,
21};
22use spin::Once;
23
24use crate::{
25 boot::{self, BootloaderAcpiArg},
26 info,
27 mm::paddr_to_vaddr,
28 warn,
29};
30
31#[derive(Clone, Debug)]
32pub(crate) struct AcpiMemoryHandler {}
33
34impl AcpiHandler for AcpiMemoryHandler {
35 unsafe fn map_physical_region<T>(
36 &self,
37 physical_address: usize,
38 size: usize,
39 ) -> acpi::PhysicalMapping<Self, T> {
40 let virtual_address = NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap();
41
42 unsafe {
48 acpi::PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone())
49 }
50 }
51
52 fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {}
53}
54
55struct SyncAcpiTables(Option<AcpiTables<AcpiMemoryHandler>>);
56
57unsafe impl Sync for SyncAcpiTables {}
62
63static ACPI_TABLES: Once<SyncAcpiTables> = Once::new();
64
65pub(crate) fn get_acpi_tables() -> Option<&'static AcpiTables<AcpiMemoryHandler>> {
66 let acpi_tables = ACPI_TABLES.call_once(|| {
67 let acpi_tables = match boot::EARLY_INFO.get().unwrap().acpi_arg {
68 BootloaderAcpiArg::Rsdp(addr) => unsafe {
69 AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap()
70 },
71 BootloaderAcpiArg::Rsdt(addr) => unsafe {
72 AcpiTables::from_rsdt(AcpiMemoryHandler {}, 0, addr).unwrap()
73 },
74 BootloaderAcpiArg::Xsdt(addr) => unsafe {
75 AcpiTables::from_rsdt(AcpiMemoryHandler {}, 1, addr).unwrap()
76 },
77 BootloaderAcpiArg::ScanBios => {
78 let rsdp = unsafe { Rsdp::search_for_on_bios(AcpiMemoryHandler {}) };
80 match rsdp {
81 Ok(map) => unsafe {
82 AcpiTables::from_rsdp(AcpiMemoryHandler {}, map.physical_start()).unwrap()
83 },
84 Err(_) => {
85 warn!("ACPI info not found!");
86 return SyncAcpiTables(None);
87 }
88 }
89 }
90 BootloaderAcpiArg::NotProvided => {
91 warn!("ACPI info not found!");
92 return SyncAcpiTables(None);
93 }
94 };
95
96 SyncAcpiTables(Some(acpi_tables))
97 });
98
99 acpi_tables.0.as_ref()
100}
101
102#[derive(Debug)]
108pub struct AcpiInfo {
109 pub century_register: Option<NonZeroU8>,
111 pub boot_flags: Option<IaPcBootArchFlags>,
113 pub reset_port_and_val: Option<(u16, u8)>,
115 pub pci_ecam_region: Option<PciEcamRegion>,
117}
118
119#[derive(Debug)]
121pub struct PciEcamRegion {
122 pub base_address: u64,
124 pub bus_start: u8,
126 pub bus_end: u8,
128}
129
130pub static ACPI_INFO: Once<AcpiInfo> = Once::new();
132
133pub(in crate::arch) fn init() {
134 let mut acpi_info = AcpiInfo {
135 century_register: None,
136 boot_flags: None,
137 reset_port_and_val: None,
138 pci_ecam_region: None,
139 };
140
141 let Some(acpi_tables) = get_acpi_tables() else {
142 ACPI_INFO.call_once(|| acpi_info);
143 return;
144 };
145
146 if let Ok(fadt) = acpi_tables.find_table::<Fadt>() {
147 acpi_info.century_register = NonZeroU8::new(fadt.century);
149 acpi_info.boot_flags = Some(fadt.iapc_boot_arch);
150 if let Ok(reset_reg) = fadt.reset_register()
151 && reset_reg.address_space == AddressSpace::SystemIo
152 && let Ok(reset_port) = reset_reg.address.try_into()
153 {
154 acpi_info.reset_port_and_val = Some((reset_port, fadt.reset_value));
155 }
156 };
157
158 if let Ok(mcfg) = acpi_tables.find_table::<Mcfg>()
159 && let Some(mcfg_entry) = mcfg.entries().first()
162 {
163 acpi_info.pci_ecam_region = Some(PciEcamRegion {
164 base_address: mcfg_entry.base_address,
165 bus_start: mcfg_entry.bus_number_start,
166 bus_end: mcfg_entry.bus_number_end,
167 });
168 }
169
170 info!("Collected information {:?}", acpi_info);
171
172 ACPI_INFO.call_once(|| acpi_info);
173}