在Sysfs中引入ACPI Firmware (#405)

- bugfix: multiboot2启动的信息因为没及时转存导致后面无法从其中进行查询的bug
- feature: 把acpi表、acpi bus加入sysfs
This commit is contained in:
LoGin
2023-10-22 22:00:16 +08:00
committed by GitHub
parent 01bd5258cf
commit 7eda31b2f0
19 changed files with 1044 additions and 204 deletions

View File

@ -181,7 +181,7 @@ void acpi_init()
// 申请mmio空间
uint64_t size = 0;
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
// 映射rsdt表
paddr = (uint64_t)rsdt_phys_base;
@ -200,7 +200,7 @@ void acpi_init()
printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num);
// 申请mmio空间
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
// 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
@ -220,7 +220,7 @@ void acpi_init()
kdebug("rsdpv1->RsdtAddress=%#018lx", rsdpv1->RsdtAddress);
// 申请mmio空间
uint64_t size = 0;
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
// acpi_rsdt_virt_addr_base = 0xffffb00000000000UL;
kdebug("ACPI: mmio created. acpi_rsdt_virt_addr_base = %#018lx,size= %#010lx", acpi_rsdt_virt_addr_base, size);
@ -243,7 +243,7 @@ void acpi_init()
printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num);
// 申请mmio空间
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
// 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;

View File

@ -1,7 +1,17 @@
use alloc::sync::Arc;
use alloc::{
string::{String, ToString},
sync::{Arc, Weak},
};
use crate::{
driver::base::device::{driver::Driver, Device},
driver::base::{
device::{
bus::{bus_manager, Bus},
driver::Driver,
Device,
},
subsys::SubSysPrivate,
},
syscall::SystemError,
};
@ -20,4 +30,98 @@ impl AcpiManager {
return Ok(false);
}
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1286
pub(super) fn bus_init(&self) -> Result<(), SystemError> {
self.acpi_sysfs_init()?;
let acpi_bus = AcpiBus::new();
bus_manager()
.register(acpi_bus as Arc<dyn Bus>)
.expect("acpi_bus register failed");
return Ok(());
}
}
/// ACPI总线
///
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1072
#[derive(Debug)]
pub(super) struct AcpiBus {
private: SubSysPrivate,
}
impl AcpiBus {
pub fn new() -> Arc<Self> {
let default_weak: Weak<Self> = Weak::new();
let bus = Arc::new(Self {
private: SubSysPrivate::new("acpi".to_string(), default_weak, &[]),
});
bus.subsystem()
.set_bus(Arc::downgrade(&(bus.clone() as Arc<dyn Bus>)));
return bus;
}
}
impl Bus for AcpiBus {
fn name(&self) -> String {
return self.private.subsys().as_kobject().name();
}
fn dev_name(&self) -> String {
self.name()
}
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1056
fn remove(&self, _device: &Arc<dyn Device>) -> Result<(), SystemError> {
todo!("acpi_bus: remove")
}
fn shutdown(&self, _device: &Arc<dyn Device>) {
return;
}
fn resume(&self, _device: &Arc<dyn Device>) -> Result<(), SystemError> {
return Ok(());
}
/// 通过acpi来匹配驱动
///
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1005
fn match_device(
&self,
_device: &Arc<dyn Device>,
_driver: &Arc<dyn Driver>,
) -> Result<bool, SystemError> {
// todo: 通过acpi来匹配驱动
return Ok(false);
}
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1019
fn probe(&self, _device: &Arc<dyn Device>) -> Result<(), SystemError> {
todo!("acpi_bus: probe")
}
fn subsystem(&self) -> &SubSysPrivate {
return &self.private;
}
}
/// Acpi设备应当实现的trait
///
/// 所有的实现了 AcpiDevice trait的结构体都应该在结构体上方标注`#[cast_to([sync] AcpiDevice)]
///
/// todo: 仿照linux的acpi_device去设计这个trait
///
///
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/include/acpi/acpi_bus.h#364
pub trait AcpiDevice: Device {}
/// Acpi驱动应当实现的trait
///
/// 所有的实现了 AcpiDriver trait的结构体都应该在结构体上方标注`#[cast_to([sync] AcpiDriver)]
///
/// todo: 仿照linux的acpi_driver去设计这个trait
///
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/include/acpi/acpi_bus.h#163
pub trait AcpiDriver: Driver {}

View File

@ -4,7 +4,7 @@ use crate::{
mm::{MemoryManagementArch, VirtAddr},
};
use super::AcpiManager;
use super::acpi_manager;
static mut RSDP_TMP_BOX: Option<AlignedBox<[u8; 4096], 4096>> = None;
@ -20,5 +20,7 @@ unsafe extern "C" fn rs_acpi_init(rsdp_vaddr: u64) {
))
.unwrap();
AcpiManager::init(rsdp_paddr);
acpi_manager()
.init(rsdp_paddr)
.expect("rs_acpi_init(): failed to init acpi");
}

View File

@ -1,56 +1,90 @@
use core::{fmt::Debug, ptr::NonNull};
use acpi::AcpiHandler;
use alloc::{string::ToString, sync::Arc};
use crate::{
driver::base::firmware::sys_firmware_kset,
kinfo,
libs::{
align::{page_align_down, page_align_up},
once::Once,
},
libs::align::{page_align_down, page_align_up},
mm::{
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
PhysAddr, VirtAddr,
},
syscall::SystemError,
};
use super::base::kset::KSet;
extern crate acpi;
pub mod bus;
mod c_adapter;
pub mod glue;
pub mod old;
extern crate acpi;
mod sysfs;
static mut __ACPI_TABLE: Option<acpi::AcpiTables<AcpiHandlerImpl>> = None;
/// `/sys/firmware/acpi`的kset
static mut ACPI_KSET_INSTANCE: Option<Arc<KSet>> = 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 {
pub fn init(rsdp_paddr: PhysAddr) {
static INIT: Once = Once::new();
INIT.call_once(|| {
kinfo!("Initializing Acpi Manager...");
let acpi_table: acpi::AcpiTables<AcpiHandlerImpl> =
unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr.data()) }
.unwrap_or_else(|e| {
panic!("acpi_init(): failed to parse acpi tables, error: {:?}", e)
});
/// 初始化ACPI
///
/// ## 参数
///
/// - `rsdp_paddr`: RSDP的物理地址
///
///
/// ## 参考资料
///
/// https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/bus.c#1390
pub fn init(&self, rsdp_paddr: PhysAddr) -> Result<(), SystemError> {
kinfo!("Initializing Acpi Manager...");
unsafe {
__ACPI_TABLE = Some(acpi_table);
}
kinfo!("Acpi Manager initialized.");
});
// 初始化`/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_paddr)?;
self.bus_init()?;
kinfo!("Acpi Manager initialized.");
return Ok(());
}
fn map_tables(&self, rsdp_paddr: PhysAddr) -> Result<(), SystemError> {
let acpi_table: acpi::AcpiTables<AcpiHandlerImpl> =
unsafe { acpi::AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp_paddr.data()) }.map_err(
|e| {
kerror!("acpi_init(): failed to parse acpi tables, error: {:?}", e);
SystemError::ENOMEM
},
)?;
unsafe {
__ACPI_TABLE = Some(acpi_table);
}
return Ok(());
}
#[allow(dead_code)]
pub fn tables() -> Option<&'static acpi::AcpiTables<AcpiHandlerImpl>> {
pub fn tables(&self) -> Option<&'static acpi::AcpiTables<AcpiHandlerImpl>> {
unsafe { __ACPI_TABLE.as_ref() }
}
}

View File

@ -0,0 +1,510 @@
use acpi::sdt::SdtHeader;
use alloc::{
string::{String, ToString},
sync::Arc,
vec::Vec,
};
use crate::{
driver::{
acpi::acpi_manager,
base::{kobject::KObject, kset::KSet},
},
filesystem::{
sysfs::{file::sysfs_emit_str, sysfs_instance, Attribute, BinAttribute, SysFSOpsSupport},
vfs::syscall::ModeType,
},
libs::rwlock::RwLock,
syscall::SystemError,
};
use super::{acpi_kset, AcpiManager};
static mut __HOTPLUG_KSET_INSTANCE: Option<Arc<KSet>> = None;
static mut __ACPI_TABLES_KSET_INSTANCE: Option<Arc<KSet>> = None;
static mut __ACPI_TABLES_DATA_KSET_INSTANCE: Option<Arc<KSet>> = None;
static mut __ACPI_TABLES_DYNAMIC_KSET_INSTANCE: Option<Arc<KSet>> = None;
static mut __ACPI_TABLE_ATTR_LIST: Option<RwLock<Vec<Arc<AttrAcpiTable>>>> = None;
const ACPI_MAX_TABLE_INSTANCES: usize = 999;
#[inline(always)]
#[allow(dead_code)]
pub fn hotplug_kset() -> Arc<KSet> {
unsafe { __HOTPLUG_KSET_INSTANCE.clone().unwrap() }
}
#[inline(always)]
pub fn acpi_tables_kset() -> Arc<KSet> {
unsafe { __ACPI_TABLES_KSET_INSTANCE.clone().unwrap() }
}
#[inline(always)]
#[allow(dead_code)]
pub fn acpi_tables_data_kset() -> Arc<KSet> {
unsafe { __ACPI_TABLES_DATA_KSET_INSTANCE.clone().unwrap() }
}
#[inline(always)]
#[allow(dead_code)]
pub fn acpi_tables_dynamic_kset() -> Arc<KSet> {
unsafe { __ACPI_TABLES_DYNAMIC_KSET_INSTANCE.clone().unwrap() }
}
#[inline(always)]
fn acpi_table_attr_list() -> &'static RwLock<Vec<Arc<AttrAcpiTable>>> {
unsafe {
return __ACPI_TABLE_ATTR_LIST.as_ref().unwrap();
}
}
impl AcpiManager {
pub(super) fn acpi_sysfs_init(&self) -> Result<(), SystemError> {
unsafe {
__ACPI_TABLE_ATTR_LIST = Some(RwLock::new(Vec::new()));
}
self.acpi_tables_sysfs_init()?;
let hotplug_kset = KSet::new("hotplug".to_string());
hotplug_kset.register(Some(acpi_kset()))?;
unsafe {
__HOTPLUG_KSET_INSTANCE = Some(hotplug_kset.clone());
}
let hotplug_kobj = hotplug_kset as Arc<dyn KObject>;
sysfs_instance().create_file(&hotplug_kobj, &AttrForceRemove)?;
return Ok(());
}
/// 在 sysfs 中创建 ACPI 表目录
///
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/sysfs.c?fi=acpi_sysfs_init#488
fn acpi_tables_sysfs_init(&self) -> Result<(), SystemError> {
// 创建 `/sys/firmware/acpi/tables` 目录
let acpi_tables_kset = KSet::new("tables".to_string());
acpi_tables_kset.register(Some(acpi_kset()))?;
unsafe {
__ACPI_TABLES_KSET_INSTANCE = Some(acpi_tables_kset.clone());
}
// 创建 `/sys/firmware/acpi/tables/data` 目录
let acpi_tables_data_kset = KSet::new("data".to_string());
acpi_tables_data_kset.register(Some(acpi_tables_kset.clone()))?;
unsafe {
__ACPI_TABLES_DATA_KSET_INSTANCE = Some(acpi_tables_data_kset);
}
// 创建 `/sys/firmware/acpi/tables/dynamic` 目录
let acpi_tables_dynamic_kset = KSet::new("dynamic".to_string());
acpi_tables_dynamic_kset.register(Some(acpi_tables_kset.clone()))?;
unsafe {
__ACPI_TABLES_DYNAMIC_KSET_INSTANCE = Some(acpi_tables_dynamic_kset);
}
// todo: get acpi tables.
let tables = self.tables().unwrap();
let headers = tables.headers();
for header in headers {
kdebug!("ACPI header: {:?}", header);
let attr = AttrAcpiTable::new(&header)?;
acpi_table_attr_list().write().push(attr);
self.acpi_table_data_init(&header)?;
}
return Ok(());
}
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/sysfs.c?fi=acpi_sysfs_init#469
fn acpi_table_data_init(&self, _header: &SdtHeader) -> Result<(), SystemError> {
// todo!("AcpiManager::acpi_table_data_init()")
return Ok(());
}
}
#[derive(Debug)]
struct AttrForceRemove;
impl Attribute for AttrForceRemove {
fn name(&self) -> &str {
"force_remove"
}
fn mode(&self) -> ModeType {
return ModeType::from_bits_truncate(0o444);
}
fn support(&self) -> SysFSOpsSupport {
return SysFSOpsSupport::SHOW;
}
fn show(&self, _kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
return sysfs_emit_str(buf, "0\n");
}
}
/// ACPI 表在 sysfs 中的属性
#[derive(Debug)]
struct AttrAcpiTable {
name: String,
filename: String,
instance: isize,
size: usize,
}
impl AttrAcpiTable {
pub fn new(header: &SdtHeader) -> Result<Arc<Self>, SystemError> {
let mut r = Self {
name: header.signature.to_string(),
filename: "".to_string(),
instance: 0,
size: header.length as usize,
};
for attr in acpi_table_attr_list().read().iter() {
if attr.name == r.name {
r.instance = attr.instance;
}
}
// 将当前实例的序号加1
r.instance += 1;
if r.instance > ACPI_MAX_TABLE_INSTANCES as isize {
kwarn!("too many table instances. name: {}", r.name);
return Err(SystemError::ERANGE);
}
let mut has_multiple_instances: bool = false;
let mut tmpcnt = 0;
for h in acpi_manager().tables().unwrap().headers() {
if h.signature == header.signature {
tmpcnt += 1;
if tmpcnt > 1 {
has_multiple_instances = true;
break;
}
}
}
if r.instance > 1 || (r.instance == 1 && has_multiple_instances) {
r.filename = format!("{}{}", r.name, r.instance);
} else {
r.filename = r.name.clone();
}
let result = Arc::new(r);
sysfs_instance().create_bin_file(
&(acpi_tables_kset() as Arc<dyn KObject>),
&(result.clone() as Arc<dyn BinAttribute>),
)?;
return Ok(result);
}
}
impl Attribute for AttrAcpiTable {
fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
fn name(&self) -> &str {
return &self.filename;
}
fn mode(&self) -> ModeType {
return ModeType::from_bits_truncate(0o400);
}
fn support(&self) -> SysFSOpsSupport {
return SysFSOpsSupport::empty();
}
}
impl BinAttribute for AttrAcpiTable {
fn support_battr(&self) -> SysFSOpsSupport {
return SysFSOpsSupport::READ;
}
fn write(
&self,
_kobj: Arc<dyn KObject>,
_buf: &[u8],
_offset: usize,
) -> Result<usize, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
/// 展示 ACPI 表的内容
///
/// 参考 https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/acpi/sysfs.c?fi=acpi_sysfs_init#320
fn read(
&self,
_kobj: Arc<dyn KObject>,
buf: &mut [u8],
offset: usize,
) -> Result<usize, SystemError> {
macro_rules! copy_data {
($table:expr) => {
let from = unsafe {
core::slice::from_raw_parts(
$table.virtual_start().as_ptr() as *const u8,
$table.region_length(),
)
};
if offset >= from.len() {
return Ok(0);
}
let mut count = buf.len();
if count > from.len() - offset {
count = from.len() - offset;
}
buf[0..count].copy_from_slice(&from[offset..offset + count]);
return Ok(count);
};
}
macro_rules! define_struct {
($name:ident) => {
#[repr(transparent)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
struct $name {
header: SdtHeader,
}
unsafe impl acpi::AcpiTable for $name {
const SIGNATURE: acpi::sdt::Signature = acpi::sdt::Signature::$name;
fn header(&self) -> &acpi::sdt::SdtHeader {
return &self.header;
}
}
};
}
macro_rules! handle {
($name: ident, $tables: expr) => {
define_struct!($name);
let table = $tables.find_entire_table::<$name>().map_err(|e| {
kwarn!(
"AttrAcpiTable::read(): failed to find table. name: {}, error: {:?}",
self.name,
e
);
SystemError::ENODEV
})?;
copy_data!(table);
};
}
let tables = acpi_manager().tables().unwrap();
match self.name.as_str() {
"RSDT" => {
handle!(RSDT, tables);
}
"XSDT" => {
handle!(XSDT, tables);
}
"FACP" => {
handle!(FADT, tables);
}
"HPET" => {
handle!(HPET, tables);
}
"APIC" => {
handle!(MADT, tables);
}
"MCFG" => {
handle!(MCFG, tables);
}
"SSDT" => {
handle!(SSDT, tables);
}
"BERT" => {
handle!(BERT, tables);
}
"BGRT" => {
handle!(BGRT, tables);
}
"CPEP" => {
handle!(CPEP, tables);
}
"DSDT" => {
handle!(DSDT, tables);
}
"ECDT" => {
handle!(ECDT, tables);
}
"EINJ" => {
handle!(EINJ, tables);
}
"ERST" => {
handle!(ERST, tables);
}
"FACS" => {
handle!(FACS, tables);
}
"FPDT" => {
handle!(FPDT, tables);
}
"GTDT" => {
handle!(GTDT, tables);
}
"HEST" => {
handle!(HEST, tables);
}
"MSCT" => {
handle!(MSCT, tables);
}
"MPST" => {
handle!(MPST, tables);
}
"NFIT" => {
handle!(NFIT, tables);
}
"PCCT" => {
handle!(PCCT, tables);
}
"PHAT" => {
handle!(PHAT, tables);
}
"PMTT" => {
handle!(PMTT, tables);
}
"PSDT" => {
handle!(PSDT, tables);
}
"RASF" => {
handle!(RASF, tables);
}
"SBST" => {
handle!(SBST, tables);
}
"SDEV" => {
handle!(SDEV, tables);
}
"SLIT" => {
handle!(SLIT, tables);
}
"SRAT" => {
handle!(SRAT, tables);
}
"AEST" => {
handle!(AEST, tables);
}
"BDAT" => {
handle!(BDAT, tables);
}
"CDIT" => {
handle!(CDIT, tables);
}
"CEDT" => {
handle!(CEDT, tables);
}
"CRAT" => {
handle!(CRAT, tables);
}
"CSRT" => {
handle!(CSRT, tables);
}
"DBGP" => {
handle!(DBGP, tables);
}
"DBG2" => {
handle!(DBG2, tables);
}
"DMAR" => {
handle!(DMAR, tables);
}
"DRTM" => {
handle!(DRTM, tables);
}
"ETDT" => {
handle!(ETDT, tables);
}
"IBFT" => {
handle!(IBFT, tables);
}
"IORT" => {
handle!(IORT, tables);
}
"IVRS" => {
handle!(IVRS, tables);
}
"LPIT" => {
handle!(LPIT, tables);
}
"MCHI" => {
handle!(MCHI, tables);
}
"MPAM" => {
handle!(MPAM, tables);
}
"MSDM" => {
handle!(MSDM, tables);
}
"PRMT" => {
handle!(PRMT, tables);
}
"RGRT" => {
handle!(RGRT, tables);
}
"SDEI" => {
handle!(SDEI, tables);
}
"SLIC" => {
handle!(SLIC, tables);
}
"SPCR" => {
handle!(SPCR, tables);
}
"SPMI" => {
handle!(SPMI, tables);
}
"STAO" => {
handle!(STAO, tables);
}
"SVKL" => {
handle!(SVKL, tables);
}
"TCPA" => {
handle!(TCPA, tables);
}
"TPM2" => {
handle!(TPM2, tables);
}
"UEFI" => {
handle!(UEFI, tables);
}
"WAET" => {
handle!(WAET, tables);
}
"WDAT" => {
handle!(WDAT, tables);
}
"WDRT" => {
handle!(WDRT, tables);
}
"WPBT" => {
handle!(WPBT, tables);
}
"WSMT" => {
handle!(WSMT, tables);
}
"XENV" => {
handle!(XENV, tables);
}
_ => {
kerror!("AttrAcpiTable::read(): unknown table. name: {}", self.name);
return Err(SystemError::ENODEV);
}
};
}
fn size(&self) -> usize {
return self.size;
}
}