good-os-framework 0.5.3

A simple operating system framework for framekernel written in Rust
Documentation
use acpi::mcfg::{Mcfg, McfgEntry};
use acpi::platform::interrupt::Apic;
use acpi::InterruptModel;
use acpi::{AcpiHandler, AcpiTables, HpetInfo, PhysicalMapping};
use alloc::alloc::Global;
use alloc::boxed::Box;
use alloc::vec::Vec;
use conquer_once::spin::OnceCell;
use core::ptr::NonNull;
use limine::request::RsdpRequest;
use x86_64::{PhysAddr, VirtAddr};

use crate::memory::{convert_physical_to_virtual, convert_virtual_to_physical};

pub static ACPI: OnceCell<Acpi> = OnceCell::uninit();

#[used]
#[link_section = ".requests"]
static RSDP_REQUEST: RsdpRequest = RsdpRequest::new();

#[derive(Clone)]
struct AcpiMemHandler;

impl AcpiHandler for AcpiMemHandler {
    unsafe fn map_physical_region<T>(
        &self,
        physical_address: usize,
        size: usize,
    ) -> PhysicalMapping<Self, T> {
        let virtual_address = {
            let physical_address = PhysAddr::new(physical_address as u64);
            let virtual_address = convert_physical_to_virtual(physical_address);
            NonNull::new_unchecked(virtual_address.as_u64() as *mut T)
        };
        PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone())
    }

    fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
}

#[derive(Debug)]
pub struct Acpi<'a> {
    pub apic_info: Apic<'a, Global>,
    pub hpet_info: HpetInfo,
    pub mcfg_info: Vec<McfgEntry>,
}

pub fn init() {
    let rsdp_response = RSDP_REQUEST.get_response().unwrap();

    let acpi_tables = unsafe {
        let rsdp_addr = VirtAddr::new(rsdp_response.address() as u64);
        let tables = AcpiTables::from_rsdp(
            AcpiMemHandler,
            convert_virtual_to_physical(rsdp_addr).as_u64() as usize,
        );
        Box::leak(Box::new(tables.unwrap()))
    };

    log::info!("Find ACPI tables successfully!");

    let platform_info = acpi_tables
        .platform_info()
        .expect("Failed to get platform info!");

    let apic_info = match platform_info.interrupt_model {
        InterruptModel::Unknown => panic!("No APIC support, cannot continue!"),
        InterruptModel::Apic(apic) => apic,
        _ => panic!("ACPI does not have interrupt model info!"),
    };

    let hpet_info = HpetInfo::new(acpi_tables).expect("Failed to get HPET info!");

    let mut mcfg_info = Vec::new();
    let mcfg = acpi_tables.find_table::<Mcfg>().expect("Cannot get MCFG");
    for entry in mcfg.entries() {
        mcfg_info.push(*entry);
    }

    ACPI.init_once(|| Acpi {
        apic_info,
        hpet_info,
        mcfg_info,
    });
}