172 lines
5.0 KiB
Rust
172 lines
5.0 KiB
Rust
use core::{ptr::NonNull, time::Duration};
|
|
|
|
use acpi::PhysicalMapping;
|
|
use acpi_system::AcpiSystemError;
|
|
use alloc::sync::Arc;
|
|
use device_api::{
|
|
device::Device,
|
|
interrupt::{InterruptHandler, Irq},
|
|
};
|
|
use kernel_arch_x86::{intrinsics, ISA_IRQ_OFFSET};
|
|
use libk::device::external_interrupt_controller;
|
|
use libk_mm::{
|
|
address::{PhysicalAddress, Virtualize},
|
|
pointer::PhysicalRef,
|
|
};
|
|
|
|
use crate::{
|
|
mem::{read_memory, write_memory},
|
|
ACPI_SYSTEM,
|
|
};
|
|
|
|
#[derive(Clone, Copy)]
|
|
#[doc(hidden)]
|
|
pub struct AcpiHandlerImpl;
|
|
|
|
struct SciHandler;
|
|
|
|
impl acpi_system::Handler for AcpiHandlerImpl {
|
|
type MappedSlice = PhysicalRef<'static, [u8]>;
|
|
|
|
unsafe fn map_slice(address: u64, length: u64) -> Self::MappedSlice {
|
|
unsafe {
|
|
PhysicalRef::map_slice(
|
|
PhysicalAddress::from_u64(address),
|
|
length.try_into().unwrap(),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn io_read_u8(port: u16) -> u8 {
|
|
let value = unsafe { intrinsics::inb(port) };
|
|
log::trace!("io_read_u8 {:#x} <- {:#x}", port, value);
|
|
value
|
|
}
|
|
|
|
fn io_read_u16(port: u16) -> u16 {
|
|
let value = unsafe { intrinsics::inw(port) };
|
|
log::trace!("io_read_u16 {:#x} <- {:#x}", port, value);
|
|
value
|
|
}
|
|
|
|
fn io_read_u32(port: u16) -> u32 {
|
|
let value = unsafe { intrinsics::inl(port) };
|
|
log::trace!("io_read_u32 {:#x} <- {:#x}", port, value);
|
|
value
|
|
}
|
|
|
|
fn io_write_u8(port: u16, value: u8) {
|
|
log::trace!("io_write_u8 {:#x}, {:#x}", port, value);
|
|
unsafe { intrinsics::outb(port, value) }
|
|
}
|
|
|
|
fn io_write_u16(port: u16, value: u16) {
|
|
log::trace!("io_write_u16 {:#x}, {:#x}", port, value);
|
|
unsafe { intrinsics::outw(port, value) }
|
|
}
|
|
|
|
fn io_write_u32(port: u16, value: u32) {
|
|
log::trace!("io_write_u32 {:#x}, {:#x}", port, value);
|
|
unsafe { intrinsics::outl(port, value) }
|
|
}
|
|
|
|
fn mem_read_u8(address: u64) -> u8 {
|
|
let value = unsafe { read_memory(PhysicalAddress::from_u64(address)) };
|
|
log::trace!("mem_read_u8 {:#x} -> {:#x}", address, value);
|
|
value
|
|
}
|
|
|
|
fn mem_read_u16(address: u64) -> u16 {
|
|
let value = unsafe { read_memory(PhysicalAddress::from_u64(address)) };
|
|
log::trace!("mem_read_u16 {:#x} -> {:#x}", address, value);
|
|
value
|
|
}
|
|
|
|
fn mem_read_u32(address: u64) -> u32 {
|
|
let value = unsafe { read_memory(PhysicalAddress::from_u64(address)) };
|
|
log::trace!("mem_read_u32 {:#x} -> {:#x}", address, value);
|
|
value
|
|
}
|
|
|
|
fn mem_read_u64(address: u64) -> u64 {
|
|
let value = unsafe { read_memory(PhysicalAddress::from_u64(address)) };
|
|
log::trace!("mem_read_u64 {:#x} -> {:#x}", address, value);
|
|
value
|
|
}
|
|
|
|
fn mem_write_u8(address: u64, value: u8) {
|
|
log::trace!("mem_write_u8 {:#x}, {:#x}", address, value);
|
|
unsafe { write_memory(PhysicalAddress::from_u64(address), value) }
|
|
}
|
|
|
|
fn mem_write_u16(address: u64, value: u16) {
|
|
log::trace!("mem_write_u16 {:#x}, {:#x}", address, value);
|
|
unsafe { write_memory(PhysicalAddress::from_u64(address), value) }
|
|
}
|
|
|
|
fn mem_write_u32(address: u64, value: u32) {
|
|
log::trace!("mem_write_u32 {:#x}, {:#x}", address, value);
|
|
unsafe { write_memory(PhysicalAddress::from_u64(address), value) }
|
|
}
|
|
|
|
fn mem_write_u64(address: u64, value: u64) {
|
|
log::trace!("mem_write_u64 {:#x}, {:#x}", address, value);
|
|
unsafe { write_memory(PhysicalAddress::from_u64(address), value) }
|
|
}
|
|
|
|
fn install_interrupt_handler(irq: u32) -> Result<(), AcpiSystemError> {
|
|
log::info!("Installing ACPI SCI handler at IRQ #{}", irq);
|
|
|
|
let intc = external_interrupt_controller().expect("No external intc");
|
|
let handler = Arc::new(SciHandler);
|
|
let irq = Irq::External(irq + ISA_IRQ_OFFSET);
|
|
|
|
intc.register_irq(irq, Default::default(), handler).unwrap();
|
|
intc.enable_irq(irq).unwrap();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn stall(_duration: Duration) {
|
|
// TODO polling_sleep is not yet implemented properly
|
|
todo!()
|
|
// util::polling_sleep(duration).ok();
|
|
}
|
|
}
|
|
|
|
impl rsdp::handler::AcpiHandler for AcpiHandlerImpl {
|
|
unsafe fn map_physical_region<T>(
|
|
&self,
|
|
physical_address: usize,
|
|
size: usize,
|
|
) -> PhysicalMapping<Self, T> {
|
|
unsafe {
|
|
PhysicalMapping::new(
|
|
physical_address,
|
|
NonNull::new_unchecked(
|
|
PhysicalAddress::from_usize(physical_address).virtualize() as *mut T
|
|
),
|
|
size,
|
|
size,
|
|
*self,
|
|
)
|
|
}
|
|
}
|
|
|
|
fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {}
|
|
}
|
|
|
|
impl InterruptHandler for SciHandler {
|
|
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
|
log::trace!("ACPI SCI received");
|
|
ACPI_SYSTEM.get().lock().handle_sci();
|
|
true
|
|
}
|
|
}
|
|
|
|
impl Device for SciHandler {
|
|
fn display_name(&self) -> &str {
|
|
"ACPI SCI handler"
|
|
}
|
|
}
|