xref: /DragonOS/kernel/src/driver/acpi/mod.rs (revision 77799ccaaca276fe127448d169f0e035837cce44)
1 use core::{fmt::Debug, ptr::NonNull};
2 
3 use acpi::{AcpiHandler, PlatformInfo};
4 use alloc::{string::ToString, sync::Arc};
5 
6 use crate::{
7     driver::base::firmware::sys_firmware_kset,
8     kinfo,
9     libs::align::{page_align_down, page_align_up},
10     mm::{
11         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
12         PhysAddr, VirtAddr,
13     },
14     syscall::SystemError,
15 };
16 
17 use super::base::kset::KSet;
18 
19 extern crate acpi;
20 
21 pub mod bus;
22 mod c_adapter;
23 pub mod glue;
24 pub mod old;
25 pub mod pmtmr;
26 mod sysfs;
27 
28 static mut __ACPI_TABLE: Option<acpi::AcpiTables<AcpiHandlerImpl>> = None;
29 /// `/sys/firmware/acpi`的kset
30 static mut ACPI_KSET_INSTANCE: Option<Arc<KSet>> = None;
31 
32 #[inline(always)]
33 pub fn acpi_manager() -> &'static AcpiManager {
34     &AcpiManager
35 }
36 
37 #[inline(always)]
38 pub fn acpi_kset() -> Arc<KSet> {
39     unsafe { ACPI_KSET_INSTANCE.clone().unwrap() }
40 }
41 
42 #[derive(Debug)]
43 pub struct AcpiManager;
44 
45 impl AcpiManager {
46     /// 初始化ACPI
47     ///
48     /// ## 参数
49     ///
50     /// - `rsdp_paddr`: RSDP的物理地址
51     ///
52     ///
53     /// ## 参考资料
54     ///
55     /// https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1390
56     pub fn init(&self, rsdp_paddr: PhysAddr) -> Result<(), SystemError> {
57         kinfo!("Initializing Acpi Manager...");
58 
59         // 初始化`/sys/firmware/acpi`的kset
60         let kset = KSet::new("acpi".to_string());
61         kset.register(Some(sys_firmware_kset()))?;
62         unsafe {
63             ACPI_KSET_INSTANCE = Some(kset.clone());
64         }
65         self.map_tables(rsdp_paddr)?;
66         self.bus_init()?;
67         kinfo!("Acpi Manager initialized.");
68         return Ok(());
69     }
70 
71     fn map_tables(&self, rsdp_paddr: PhysAddr) -> Result<(), SystemError> {
72         let acpi_table: acpi::AcpiTables<AcpiHandlerImpl> =
73             unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr.data()) }.map_err(
74                 |e| {
75                     kerror!("acpi_init(): failed to parse acpi tables, error: {:?}", e);
76                     SystemError::ENOMEM
77                 },
78             )?;
79 
80         unsafe {
81             __ACPI_TABLE = Some(acpi_table);
82         }
83 
84         return Ok(());
85     }
86 
87     #[allow(dead_code)]
88     pub fn tables(&self) -> Option<&'static acpi::AcpiTables<AcpiHandlerImpl>> {
89         unsafe { __ACPI_TABLE.as_ref() }
90     }
91 
92     /// 从acpi获取平台的信息
93     ///
94     /// 包括:
95     ///
96     /// - PowerProfile
97     /// - InterruptModel
98     /// - ProcessorInfo
99     /// - PmTimer
100     pub fn platform_info(&self) -> Option<PlatformInfo<'_, alloc::alloc::Global>> {
101         let r = self.tables()?.platform_info();
102         if let Err(ref e) = r {
103             kerror!(
104                 "AcpiManager::platform_info(): failed to get platform info, error: {:?}",
105                 e
106             );
107             return None;
108         }
109 
110         return Some(r.unwrap());
111     }
112 }
113 
114 #[derive(Debug, Clone, Copy)]
115 pub struct AcpiHandlerImpl;
116 
117 impl AcpiHandler for AcpiHandlerImpl {
118     unsafe fn map_physical_region<T>(
119         &self,
120         physical_address: usize,
121         size: usize,
122     ) -> acpi::PhysicalMapping<Self, T> {
123         let offset = physical_address - page_align_down(physical_address);
124         let size_fix = page_align_up(size + offset);
125 
126         let mmio_guard = mmio_pool()
127             .create_mmio(size_fix)
128             .expect("AcpiHandlerImpl::map_physical_region(): failed to create mmio");
129 
130         mmio_guard
131             .map_phys(PhysAddr::new(page_align_down(physical_address)), size_fix)
132             .expect("AcpiHandlerImpl::map_physical_region(): failed to map phys");
133         let virtual_start = mmio_guard.vaddr().data() + offset;
134 
135         let virtual_start = NonNull::new(virtual_start as *mut T).unwrap();
136 
137         let result: acpi::PhysicalMapping<AcpiHandlerImpl, T> = acpi::PhysicalMapping::new(
138             physical_address,
139             virtual_start,
140             size,
141             mmio_guard.size(),
142             AcpiHandlerImpl,
143         );
144 
145         MMIOSpaceGuard::leak(mmio_guard);
146 
147         return result;
148     }
149 
150     fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {
151         let mmio_guard = unsafe {
152             MMIOSpaceGuard::from_raw(
153                 VirtAddr::new(page_align_down(
154                     region.virtual_start().as_ref() as *const T as usize
155                 )),
156                 region.mapped_length(),
157                 true,
158             )
159         };
160         drop(mmio_guard);
161     }
162 }
163