xref: /DragonOS/kernel/src/driver/acpi/mod.rs (revision 4fda81ce81939d83b74c8042d6fb4223deff3685)
1 use core::{fmt::Debug, hint::spin_loop, ptr::NonNull};
2 
3 use acpi::{AcpiHandler, AcpiTables, PlatformInfo};
4 use alloc::{string::ToString, sync::Arc};
5 
6 use crate::{
7     arch::MMArch,
8     driver::base::firmware::sys_firmware_kset,
9     kinfo,
10     libs::align::{page_align_down, page_align_up, AlignedBox},
11     mm::{
12         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
13         MemoryManagementArch, PhysAddr, VirtAddr,
14     },
15     syscall::SystemError,
16 };
17 
18 use super::base::kset::KSet;
19 
20 extern crate acpi;
21 
22 pub mod bus;
23 mod c_adapter;
24 pub mod glue;
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 static mut RSDP_TMP_BOX: Option<AlignedBox<[u8; 4096], 4096>> = None;
33 
34 #[inline(always)]
35 pub fn acpi_manager() -> &'static AcpiManager {
36     &AcpiManager
37 }
38 
39 #[inline(always)]
40 pub fn acpi_kset() -> Arc<KSet> {
41     unsafe { ACPI_KSET_INSTANCE.clone().unwrap() }
42 }
43 
44 #[derive(Debug)]
45 pub struct AcpiManager;
46 
47 impl AcpiManager {
48     /// 初始化ACPI
49     ///
50     /// ## 参数
51     ///
52     /// - `rsdp_vaddr1`: RSDP(v1)的虚拟地址
53     /// - `rsdp_vaddr2`: RSDP(v2)的虚拟地址
54     ///
55     ///
56     /// ## 参考资料
57     ///
58     /// https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1390
59     pub fn init(&self, rsdp_vaddr1: u64, rsdp_vaddr2: u64) -> Result<(), SystemError> {
60         kinfo!("Initializing Acpi Manager...");
61 
62         // 初始化`/sys/firmware/acpi`的kset
63         let kset = KSet::new("acpi".to_string());
64         kset.register(Some(sys_firmware_kset()))?;
65         unsafe {
66             ACPI_KSET_INSTANCE = Some(kset.clone());
67         }
68         self.map_tables(rsdp_vaddr1, rsdp_vaddr2)?;
69         self.bus_init()?;
70         kinfo!("Acpi Manager initialized.");
71         return Ok(());
72     }
73 
74     fn map_tables(&self, rsdp_vaddr1: u64, rsdp_vaddr2: u64) -> Result<(), SystemError> {
75         let rsdp_paddr1 = Self::rsdp_paddr(rsdp_vaddr1);
76         let res1 = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr1.data()) };
77         let e1;
78         match res1 {
79             // 如果rsdpv1能够获取到acpi_table,则就用该表,不用rsdpv2了
80             Ok(acpi_table) => {
81                 Self::set_acpi_table(acpi_table);
82                 return Ok(());
83             }
84             Err(e) => {
85                 e1 = e;
86                 Self::drop_rsdp_tmp_box();
87             }
88         }
89 
90         let rsdp_paddr2 = Self::rsdp_paddr(rsdp_vaddr2);
91         let res2 = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr2.data()) };
92         match res2 {
93             Ok(acpi_table) => {
94                 Self::set_acpi_table(acpi_table);
95             }
96             // 如果rsdpv1和rsdpv2都无法获取到acpi_table,说明有问题,打印报错信息后进入死循环
97             Err(e2) => {
98                 kerror!("acpi_init(): failed to parse acpi tables, error: (rsdpv1: {:?}) or (rsdpv2: {:?})", e1, e2);
99                 Self::drop_rsdp_tmp_box();
100                 loop {
101                     spin_loop();
102                 }
103             }
104         }
105 
106         return Ok(());
107     }
108 
109     /// 通过RSDP虚拟地址获取RSDP物理地址
110     ///
111     /// ## 参数
112     ///
113     /// - `rsdp_vaddr`: RSDP的虚拟地址
114     ///
115     /// ## 返回值
116     ///
117     /// RSDP物理地址
118     fn rsdp_paddr(rsdp_vaddr: u64) -> PhysAddr {
119         unsafe {
120             RSDP_TMP_BOX = Some(AlignedBox::new_zeroed().expect("rs_acpi_init(): failed to alloc"))
121         };
122         let size = core::mem::size_of::<acpi::rsdp::Rsdp>();
123         let tmp_data =
124             unsafe { core::slice::from_raw_parts(rsdp_vaddr as usize as *const u8, size) };
125         unsafe { RSDP_TMP_BOX.as_mut().unwrap()[0..size].copy_from_slice(tmp_data) };
126         let rsdp_paddr = unsafe {
127             MMArch::virt_2_phys(VirtAddr::new(
128                 RSDP_TMP_BOX.as_ref().unwrap().as_ptr() as usize
129             ))
130             .unwrap()
131         };
132 
133         return rsdp_paddr;
134     }
135 
136     fn set_acpi_table(acpi_table: AcpiTables<AcpiHandlerImpl>) {
137         unsafe {
138             __ACPI_TABLE = Some(acpi_table);
139         }
140     }
141 
142     fn drop_rsdp_tmp_box() {
143         unsafe {
144             RSDP_TMP_BOX = None;
145         }
146     }
147 
148     #[allow(dead_code)]
149     pub fn tables(&self) -> Option<&'static acpi::AcpiTables<AcpiHandlerImpl>> {
150         unsafe { __ACPI_TABLE.as_ref() }
151     }
152 
153     /// 从acpi获取平台的信息
154     ///
155     /// 包括:
156     ///
157     /// - PowerProfile
158     /// - InterruptModel
159     /// - ProcessorInfo
160     /// - PmTimer
161     pub fn platform_info(&self) -> Option<PlatformInfo<'_, alloc::alloc::Global>> {
162         let r = self.tables()?.platform_info();
163         if let Err(ref e) = r {
164             kerror!(
165                 "AcpiManager::platform_info(): failed to get platform info, error: {:?}",
166                 e
167             );
168             return None;
169         }
170 
171         return Some(r.unwrap());
172     }
173 }
174 
175 #[derive(Debug, Clone, Copy)]
176 pub struct AcpiHandlerImpl;
177 
178 impl AcpiHandler for AcpiHandlerImpl {
179     unsafe fn map_physical_region<T>(
180         &self,
181         physical_address: usize,
182         size: usize,
183     ) -> acpi::PhysicalMapping<Self, T> {
184         let offset = physical_address - page_align_down(physical_address);
185         let size_fix = page_align_up(size + offset);
186 
187         let mmio_guard = mmio_pool()
188             .create_mmio(size_fix)
189             .expect("AcpiHandlerImpl::map_physical_region(): failed to create mmio");
190 
191         mmio_guard
192             .map_phys(PhysAddr::new(page_align_down(physical_address)), size_fix)
193             .expect("AcpiHandlerImpl::map_physical_region(): failed to map phys");
194         let virtual_start = mmio_guard.vaddr().data() + offset;
195 
196         let virtual_start = NonNull::new(virtual_start as *mut T).unwrap();
197 
198         let result: acpi::PhysicalMapping<AcpiHandlerImpl, T> = acpi::PhysicalMapping::new(
199             physical_address,
200             virtual_start,
201             size,
202             mmio_guard.size(),
203             AcpiHandlerImpl,
204         );
205 
206         MMIOSpaceGuard::leak(mmio_guard);
207 
208         return result;
209     }
210 
211     fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {
212         let mmio_guard = unsafe {
213             MMIOSpaceGuard::from_raw(
214                 VirtAddr::new(page_align_down(
215                     region.virtual_start().as_ref() as *const T as usize
216                 )),
217                 region.mapped_length(),
218                 true,
219             )
220         };
221         drop(mmio_guard);
222     }
223 }
224