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