224 lines
6.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::{fmt::Debug, hint::spin_loop, ptr::NonNull};
use acpi::{AcpiHandler, AcpiTables, PlatformInfo};
use alloc::{string::ToString, sync::Arc};
use log::{error, info};
use crate::{
arch::MMArch,
driver::base::firmware::sys_firmware_kset,
libs::align::{page_align_down, page_align_up, AlignedBox},
mm::{
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
MemoryManagementArch, PhysAddr, VirtAddr,
},
};
use system_error::SystemError;
use super::base::kset::KSet;
extern crate acpi;
pub mod bus;
mod c_adapter;
pub mod glue;
pub mod pmtmr;
mod sysfs;
static mut __ACPI_TABLE: Option<acpi::AcpiTables<AcpiHandlerImpl>> = None;
/// `/sys/firmware/acpi`的kset
static mut ACPI_KSET_INSTANCE: Option<Arc<KSet>> = None;
static mut RSDP_TMP_BOX: Option<AlignedBox<[u8; 4096], 4096>> = None;
#[inline(always)]
pub fn acpi_manager() -> &'static AcpiManager {
&AcpiManager
}
#[inline(always)]
pub fn acpi_kset() -> Arc<KSet> {
unsafe { ACPI_KSET_INSTANCE.clone().unwrap() }
}
#[derive(Debug)]
pub struct AcpiManager;
impl AcpiManager {
/// 初始化ACPI
///
/// ## 参数
///
/// - `rsdp_vaddr1`: RSDP(v1)的虚拟地址
/// - `rsdp_vaddr2`: RSDP(v2)的虚拟地址
///
///
/// ## 参考资料
///
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1390
pub fn init(&self, rsdp_vaddr1: u64, rsdp_vaddr2: u64) -> Result<(), SystemError> {
info!("Initializing Acpi Manager...");
// 初始化`/sys/firmware/acpi`的kset
let kset = KSet::new("acpi".to_string());
kset.register(Some(sys_firmware_kset()))?;
unsafe {
ACPI_KSET_INSTANCE = Some(kset.clone());
}
self.map_tables(rsdp_vaddr1, rsdp_vaddr2)?;
self.bus_init()?;
info!("Acpi Manager initialized.");
return Ok(());
}
fn map_tables(&self, rsdp_vaddr1: u64, rsdp_vaddr2: u64) -> Result<(), SystemError> {
let rsdp_paddr1 = Self::rsdp_paddr(rsdp_vaddr1);
let res1 = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr1.data()) };
let e1;
match res1 {
// 如果rsdpv1能够获取到acpi_table则就用该表不用rsdpv2了
Ok(acpi_table) => {
Self::set_acpi_table(acpi_table);
return Ok(());
}
Err(e) => {
e1 = e;
Self::drop_rsdp_tmp_box();
}
}
let rsdp_paddr2 = Self::rsdp_paddr(rsdp_vaddr2);
let res2 = unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr2.data()) };
match res2 {
Ok(acpi_table) => {
Self::set_acpi_table(acpi_table);
}
// 如果rsdpv1和rsdpv2都无法获取到acpi_table说明有问题打印报错信息后进入死循环
Err(e2) => {
error!("acpi_init(): failed to parse acpi tables, error: (rsdpv1: {:?}) or (rsdpv2: {:?})", e1, e2);
Self::drop_rsdp_tmp_box();
loop {
spin_loop();
}
}
}
return Ok(());
}
/// 通过RSDP虚拟地址获取RSDP物理地址
///
/// ## 参数
///
/// - `rsdp_vaddr`: RSDP的虚拟地址
///
/// ## 返回值
///
/// RSDP物理地址
fn rsdp_paddr(rsdp_vaddr: u64) -> PhysAddr {
unsafe {
RSDP_TMP_BOX = Some(AlignedBox::new_zeroed().expect("rs_acpi_init(): failed to alloc"))
};
let size = core::mem::size_of::<acpi::rsdp::Rsdp>();
let tmp_data =
unsafe { core::slice::from_raw_parts(rsdp_vaddr as usize as *const u8, size) };
unsafe { RSDP_TMP_BOX.as_mut().unwrap()[0..size].copy_from_slice(tmp_data) };
let rsdp_paddr = unsafe {
MMArch::virt_2_phys(VirtAddr::new(
RSDP_TMP_BOX.as_ref().unwrap().as_ptr() as usize
))
.unwrap()
};
return rsdp_paddr;
}
fn set_acpi_table(acpi_table: AcpiTables<AcpiHandlerImpl>) {
unsafe {
__ACPI_TABLE = Some(acpi_table);
}
}
fn drop_rsdp_tmp_box() {
unsafe {
RSDP_TMP_BOX = None;
}
}
#[allow(dead_code)]
pub fn tables(&self) -> Option<&'static acpi::AcpiTables<AcpiHandlerImpl>> {
unsafe { __ACPI_TABLE.as_ref() }
}
/// 从acpi获取平台的信息
///
/// 包括:
///
/// - PowerProfile
/// - InterruptModel
/// - ProcessorInfo
/// - PmTimer
pub fn platform_info(&self) -> Option<PlatformInfo<'_, alloc::alloc::Global>> {
let r = self.tables()?.platform_info();
if let Err(ref e) = r {
error!(
"AcpiManager::platform_info(): failed to get platform info, error: {:?}",
e
);
return None;
}
return Some(r.unwrap());
}
}
#[derive(Debug, Clone, Copy)]
pub struct AcpiHandlerImpl;
impl AcpiHandler for AcpiHandlerImpl {
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> acpi::PhysicalMapping<Self, T> {
let offset = physical_address - page_align_down(physical_address);
let size_fix = page_align_up(size + offset);
let mmio_guard = mmio_pool()
.create_mmio(size_fix)
.expect("AcpiHandlerImpl::map_physical_region(): failed to create mmio");
mmio_guard
.map_phys(PhysAddr::new(page_align_down(physical_address)), size_fix)
.expect("AcpiHandlerImpl::map_physical_region(): failed to map phys");
let virtual_start = mmio_guard.vaddr().data() + offset;
let virtual_start = NonNull::new(virtual_start as *mut T).unwrap();
let result: acpi::PhysicalMapping<AcpiHandlerImpl, T> = acpi::PhysicalMapping::new(
physical_address,
virtual_start,
size,
mmio_guard.size(),
AcpiHandlerImpl,
);
MMIOSpaceGuard::leak(mmio_guard);
return result;
}
fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {
let mmio_guard = unsafe {
MMIOSpaceGuard::from_raw(
VirtAddr::new(page_align_down(
region.virtual_start().as_ref() as *const T as usize
)),
region.mapped_length(),
true,
)
};
drop(mmio_guard);
}
}