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 }; 16 use system_error::SystemError; 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