From 6e7a42c2cb9d743f6f59cc1adfd9b8f82f1a979d Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 27 Jan 2025 18:10:56 +0200 Subject: [PATCH] acpi: move ACPI to its own driver --- Cargo.lock | 19 +- Cargo.toml | 1 + kernel/Cargo.toml | 5 +- .../arch/x86 => arch/x86/src}/intrinsics.rs | 0 kernel/arch/x86/src/lib.rs | 6 + kernel/driver/acpi/Cargo.toml | 18 + kernel/driver/acpi/src/aml_handler.rs | 131 ++++++ kernel/driver/acpi/src/handler.rs | 171 ++++++++ kernel/driver/acpi/src/lib.rs | 74 ++++ kernel/driver/acpi/src/mem.rs | 64 +++ kernel/src/arch/x86/mod.rs | 22 +- kernel/src/arch/x86/pci.rs | 5 +- kernel/src/arch/x86/peripherals/i8253.rs | 7 +- kernel/src/arch/x86/peripherals/i8259.rs | 3 +- kernel/src/arch/x86/peripherals/ps2/mod.rs | 10 +- kernel/src/arch/x86/peripherals/rtc.rs | 7 +- kernel/src/arch/x86/peripherals/serial.rs | 3 +- kernel/src/arch/x86_64/acpi.rs | 390 ------------------ kernel/src/arch/x86_64/apic/ioapic.rs | 6 +- kernel/src/arch/x86_64/mod.rs | 30 +- kernel/src/arch/x86_64/smp.rs | 3 +- 21 files changed, 527 insertions(+), 448 deletions(-) rename kernel/{src/arch/x86 => arch/x86/src}/intrinsics.rs (100%) create mode 100644 kernel/driver/acpi/Cargo.toml create mode 100644 kernel/driver/acpi/src/aml_handler.rs create mode 100644 kernel/driver/acpi/src/handler.rs create mode 100644 kernel/driver/acpi/src/lib.rs create mode 100644 kernel/driver/acpi/src/mem.rs delete mode 100644 kernel/src/arch/x86_64/acpi.rs diff --git a/Cargo.lock b/Cargo.lock index e81d7701..71d3afbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2460,6 +2460,22 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "ygg_driver_acpi" +version = "0.1.0" +dependencies = [ + "acpi", + "acpi-system", + "aml", + "device-api", + "kernel-arch-x86", + "libk", + "libk-mm", + "libk-util", + "log", + "rsdp", +] + [[package]] name = "ygg_driver_ahci" version = "0.1.0" @@ -2658,8 +2674,6 @@ dependencies = [ "abi-lib", "abi-serde", "acpi", - "acpi-system", - "aml", "async-trait", "bitflags 2.6.0", "bytemuck", @@ -2690,6 +2704,7 @@ dependencies = [ "tock-registers 0.9.0", "vmalloc", "yboot-proto", + "ygg_driver_acpi", "ygg_driver_ahci", "ygg_driver_input", "ygg_driver_net_core", diff --git a/Cargo.toml b/Cargo.toml index e21f198c..32e43b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ ahash = { version = "0.8.11", default-features = false, features = ["no-rng"] } # acpi acpi = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branch = "acpi-system" } +rsdp = { git = "https://github.com/alnyan/acpi.git", package = "rsdp", branch = "acpi-system" } aml = { git = "https://github.com/alnyan/acpi.git", branch = "acpi-system" } acpi-system = { git = "https://github.com/alnyan/acpi-system.git" } diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index ce2cbc59..06e36fc8 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -61,12 +61,11 @@ kernel-arch-riscv64.workspace = true yboot-proto.workspace = true kernel-arch-x86_64.workspace = true kernel-arch-x86.workspace = true +ygg_driver_acpi.path = "driver/acpi" ygg_driver_nvme = { path = "driver/block/nvme" } acpi.workspace = true -aml.workspace = true -acpi-system.workspace = true [target.'cfg(target_arch = "x86")'.dependencies] kernel-arch-i686.workspace = true @@ -87,6 +86,8 @@ kernel-arch-x86.workspace = true kernel-arch-aarch64.workspace = true kernel-arch-riscv64.workspace = true +ygg_driver_acpi.path = "driver/acpi" + [features] default = ["fb_console"] fb_console = [] diff --git a/kernel/src/arch/x86/intrinsics.rs b/kernel/arch/x86/src/intrinsics.rs similarity index 100% rename from kernel/src/arch/x86/intrinsics.rs rename to kernel/arch/x86/src/intrinsics.rs diff --git a/kernel/arch/x86/src/lib.rs b/kernel/arch/x86/src/lib.rs index 2f7bae5e..8afeeba9 100644 --- a/kernel/arch/x86/src/lib.rs +++ b/kernel/arch/x86/src/lib.rs @@ -6,4 +6,10 @@ extern crate alloc; pub mod cpuid; pub mod gdt; +pub mod intrinsics; pub mod registers; + +#[cfg(any(target_arch = "x86_64", rust_analyzer))] +pub const ISA_IRQ_OFFSET: u32 = 1024; +#[cfg(any(target_arch = "x86", rust_analyzer))] +pub const ISA_IRQ_OFFSET: u32 = 0; diff --git a/kernel/driver/acpi/Cargo.toml b/kernel/driver/acpi/Cargo.toml new file mode 100644 index 00000000..3666050f --- /dev/null +++ b/kernel/driver/acpi/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "ygg_driver_acpi" +version = "0.1.0" +edition = "2024" + +[dependencies] +libk-util.workspace = true +libk-mm.workspace = true +libk.workspace = true +device-api.workspace = true +kernel-arch-x86.path = "../../arch/x86" + +acpi.workspace = true +rsdp.workspace = true +aml.workspace = true +acpi-system.workspace = true + +log.workspace = true diff --git a/kernel/driver/acpi/src/aml_handler.rs b/kernel/driver/acpi/src/aml_handler.rs new file mode 100644 index 00000000..e903c223 --- /dev/null +++ b/kernel/driver/acpi/src/aml_handler.rs @@ -0,0 +1,131 @@ +use core::time::Duration; + +use crate::AcpiHandlerImpl; + +impl aml::Handler for AcpiHandlerImpl { + fn read_io_u8(&self, port: u16) -> u8 { + ::io_read_u8(port) + } + + fn read_io_u16(&self, port: u16) -> u16 { + ::io_read_u16(port) + } + + fn read_io_u32(&self, port: u16) -> u32 { + ::io_read_u32(port) + } + + fn write_io_u8(&self, port: u16, value: u8) { + ::io_write_u8(port, value) + } + + fn write_io_u16(&self, port: u16, value: u16) { + ::io_write_u16(port, value) + } + + fn write_io_u32(&self, port: u16, value: u32) { + ::io_write_u32(port, value) + } + + fn read_u8(&self, address: usize) -> u8 { + ::mem_read_u8(address as u64) + } + + fn read_u16(&self, address: usize) -> u16 { + ::mem_read_u16(address as u64) + } + + fn read_u32(&self, address: usize) -> u32 { + ::mem_read_u32(address as u64) + } + + fn read_u64(&self, address: usize) -> u64 { + ::mem_read_u64(address as u64) + } + + fn write_u8(&self, address: usize, value: u8) { + ::mem_write_u8(address as u64, value) + } + + fn write_u16(&self, address: usize, value: u16) { + ::mem_write_u16(address as u64, value) + } + + fn write_u32(&self, address: usize, value: u32) { + ::mem_write_u32(address as u64, value) + } + + fn write_u64(&self, address: usize, value: u64) { + ::mem_write_u64(address as u64, value) + } + + fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { + 0xFF + } + + fn read_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u16 { + 0xFFFF + } + + fn read_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u32 { + 0xFFFFFFFF + } + + fn write_pci_u8( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u8, + ) { + } + + fn write_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u16, + ) { + } + + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { + } + + fn read_ec_u8(&self, _address: u64) -> u8 { + 0x00 + } + + fn write_ec_u8(&self, _address: u64, _value: u8) {} + + fn sleep(&self, _duration: Duration) { + todo!() + // util::polling_sleep(duration).unwrap(); + } +} diff --git a/kernel/driver/acpi/src/handler.rs b/kernel/driver/acpi/src/handler.rs new file mode 100644 index 00000000..ca241b9c --- /dev/null +++ b/kernel/driver/acpi/src/handler.rs @@ -0,0 +1,171 @@ +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( + &self, + physical_address: usize, + size: usize, + ) -> PhysicalMapping { + unsafe { + PhysicalMapping::new( + physical_address, + NonNull::new_unchecked( + PhysicalAddress::from_usize(physical_address).virtualize() as *mut T + ), + size, + size, + *self, + ) + } + } + + fn unmap_physical_region(_region: &acpi::PhysicalMapping) {} +} + +impl InterruptHandler for SciHandler { + fn handle_irq(self: Arc, _vector: Option) -> 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" + } +} diff --git a/kernel/driver/acpi/src/lib.rs b/kernel/driver/acpi/src/lib.rs new file mode 100644 index 00000000..bef3728d --- /dev/null +++ b/kernel/driver/acpi/src/lib.rs @@ -0,0 +1,74 @@ +#![feature(allocator_api)] +#![no_std] + +use acpi::AcpiTables; +use acpi_system::{AcpiInterruptMethod, AcpiSystem}; +use alloc::boxed::Box; +use libk::error::Error; +use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; + +extern crate alloc; + +pub mod mem; +pub use mem::AcpiAllocator; +pub mod handler; +pub use handler::AcpiHandlerImpl; +pub mod aml_handler; + +pub use acpi_system::{EventAction, FixedEvent}; + +static ACPI_SYSTEM: OneTimeInit>> = OneTimeInit::new(); + +pub fn add_event_handler) -> EventAction + 'static>( + event: &FixedEvent, + handler: F, +) -> Result<(), Error> { + ACPI_SYSTEM + .get() + .lock() + .enable_fixed_event(event, Box::new(handler)) + .map_err(|_| Error::InvalidArgument) +} + +/// Initializes ACPI management +pub fn switch_to_acpi(tables: &'static AcpiTables) -> Result<(), Error> { + // NOTE mostly broken for real HW + let mut system = AcpiSystem::new(tables, Box::new(AcpiHandlerImpl)).unwrap(); + + system.initialize(AcpiInterruptMethod::Apic).unwrap(); + + // system + // .enable_fixed_event( + // &FixedEvent::POWER_BUTTON, + // Box::new(|_| { + // log::info!("Power button was pressed"); + + // // TODO the correct way would be to + // // 1. Nicely ask all the processes to quit + // // 2. Wait for some time + // // 3. Kill the remaining ones + // // 4. Halt other cores + // // 5. Sync filesystem + // // 6. Do something with the devices + // // 7. Actually enter the S5 state + + // unsafe { + // PLATFORM + // .send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown) + // .unwrap(); + // } + + // SHUTDOWN_FENCE.signal(); + // SHUTDOWN_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire)); + + // log::info!("CPUs are parked, can shutdown now"); + + // EventAction::EnterSleepState(AcpiSleepState::S5) + // }), + // ) + // .unwrap(); + + ACPI_SYSTEM.init(IrqSafeSpinlock::new(system)); + + Ok(()) +} diff --git a/kernel/driver/acpi/src/mem.rs b/kernel/driver/acpi/src/mem.rs new file mode 100644 index 00000000..b3f7019b --- /dev/null +++ b/kernel/driver/acpi/src/mem.rs @@ -0,0 +1,64 @@ +//! ACPI memory IO and management functions + +use core::{ + alloc::{AllocError, Allocator, GlobalAlloc, Layout}, + ptr::NonNull, +}; + +use libk_mm::{address::PhysicalAddress, device::DeviceMemoryMapping, heap::GLOBAL_HEAP}; + +#[derive(Clone, Copy)] +#[doc(hidden)] +pub struct AcpiAllocator; + +unsafe impl Allocator for AcpiAllocator { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + let ptr = unsafe { GLOBAL_HEAP.alloc(layout) }; + log::trace!("ACPI alloc: {:?} -> {:p}", layout, ptr); + + if ptr.is_null() { + Err(AllocError) + } else { + unsafe { + Ok(NonNull::slice_from_raw_parts( + NonNull::new_unchecked(ptr), + layout.size(), + )) + } + } + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + log::trace!("ACPI dealloc: {:?}, {:?}", ptr, layout); + unsafe { GLOBAL_HEAP.dealloc(ptr.as_ptr(), layout) }; + } +} + +// TODO don't map memory as device if not necessary +pub unsafe fn read_memory(address: PhysicalAddress) -> T { + let io = + unsafe { DeviceMemoryMapping::map(address, size_of::(), Default::default()).unwrap() }; + let address = io.address(); + + unsafe { + if address % align_of::() == 0 { + (address as *const T).read_volatile() + } else { + (address as *const T).read_unaligned() + } + } +} + +pub unsafe fn write_memory(address: PhysicalAddress, value: T) { + let io = + unsafe { DeviceMemoryMapping::map(address, size_of::(), Default::default()).unwrap() }; + let address = io.address(); + + unsafe { + if address % align_of::() == 0 { + (address as *mut T).write_volatile(value) + } else { + (address as *mut T).write_unaligned(value) + } + } +} diff --git a/kernel/src/arch/x86/mod.rs b/kernel/src/arch/x86/mod.rs index 4a7797db..132ac6cd 100644 --- a/kernel/src/arch/x86/mod.rs +++ b/kernel/src/arch/x86/mod.rs @@ -5,6 +5,7 @@ use abi::error::Error; use alloc::{sync::Arc, vec::Vec}; use device_api::{device::Device, interrupt::Irq}; +use kernel_arch_x86::ISA_IRQ_OFFSET; use libk::{ config, debug, fs::{devfs, sysfs}, @@ -22,13 +23,6 @@ use crate::fs::{Initrd, INITRD_DATA}; use super::L3; -#[cfg(any(target_arch = "x86_64", rust_analyzer))] -pub const ISA_IRQ_OFFSET: u32 = crate::arch::x86_64::ISA_IRQ_OFFSET; - -#[cfg(any(target_arch = "x86", rust_analyzer))] -pub const ISA_IRQ_OFFSET: u32 = 0; - -pub mod intrinsics; mod pci; pub mod peripherals; @@ -76,13 +70,13 @@ pub fn register_pci_drivers() { Some(0x01), ygg_driver_ahci::probe, ); - ygg_driver_pci::register_class_driver( - "USB xHCI", - 0x0C, - Some(0x03), - Some(0x30), - ygg_driver_usb_xhci::probe, - ); + // ygg_driver_pci::register_class_driver( + // "USB xHCI", + // 0x0C, + // Some(0x03), + // Some(0x30), + // ygg_driver_usb_xhci::probe, + // ); ygg_driver_pci::register_vendor_driver( "Virtio PCI GPU Device", 0x1AF4, diff --git a/kernel/src/arch/x86/pci.rs b/kernel/src/arch/x86/pci.rs index 39d5d23f..0e3777c1 100644 --- a/kernel/src/arch/x86/pci.rs +++ b/kernel/src/arch/x86/pci.rs @@ -1,10 +1,7 @@ +use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess}; use libk_util::sync::IrqSafeSpinlock; use ygg_driver_pci::LegacyPciAccess; -use crate::arch::x86::intrinsics::IoPortAccess; - -use super::intrinsics::IoPort; - struct LegacyPciInner { address: IoPort, data: IoPort, diff --git a/kernel/src/arch/x86/peripherals/i8253.rs b/kernel/src/arch/x86/peripherals/i8253.rs index 7fb47f7f..ada39e24 100644 --- a/kernel/src/arch/x86/peripherals/i8253.rs +++ b/kernel/src/arch/x86/peripherals/i8253.rs @@ -4,13 +4,12 @@ use device_api::{ device::Device, interrupt::{InterruptHandler, Irq}, }; -use libk::{device::external_interrupt_controller, task::runtime, time}; -use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; - -use crate::arch::x86::{ +use kernel_arch_x86::{ intrinsics::{IoPort, IoPortAccess}, ISA_IRQ_OFFSET, }; +use libk::{device::external_interrupt_controller, task::runtime, time}; +use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; const FREQUENCY: u32 = 1193180; diff --git a/kernel/src/arch/x86/peripherals/i8259.rs b/kernel/src/arch/x86/peripherals/i8259.rs index 30dcdb5e..3e8b9f8a 100644 --- a/kernel/src/arch/x86/peripherals/i8259.rs +++ b/kernel/src/arch/x86/peripherals/i8259.rs @@ -9,10 +9,9 @@ use device_api::{ IrqOptions, }, }; +use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; -use crate::arch::x86::intrinsics::{IoPort, IoPortAccess}; - #[cfg(any(target_arch = "x86", rust_analyzer))] use crate::arch::i686::exception; #[cfg(any(target_arch = "x86", rust_analyzer))] diff --git a/kernel/src/arch/x86/peripherals/ps2/mod.rs b/kernel/src/arch/x86/peripherals/ps2/mod.rs index ad2540be..b11a6696 100644 --- a/kernel/src/arch/x86/peripherals/ps2/mod.rs +++ b/kernel/src/arch/x86/peripherals/ps2/mod.rs @@ -8,14 +8,14 @@ use device_api::{ device::Device, interrupt::{InterruptHandler, Irq}, }; +use kernel_arch_x86::{ + intrinsics::{IoPort, IoPortAccess}, + ISA_IRQ_OFFSET, +}; use libk::device::external_interrupt_controller; use libk_util::sync::IrqSafeSpinlock; -use crate::arch::x86::{ - intrinsics::{IoPort, IoPortAccess}, - peripherals::ps2::codeset::{CODE_SET_1_00, CODE_SET_1_E0}, - ISA_IRQ_OFFSET, -}; +use codeset::{CODE_SET_1_00, CODE_SET_1_E0}; mod codeset; diff --git a/kernel/src/arch/x86/peripherals/rtc.rs b/kernel/src/arch/x86/peripherals/rtc.rs index 22f4b02f..9f6e4a10 100644 --- a/kernel/src/arch/x86/peripherals/rtc.rs +++ b/kernel/src/arch/x86/peripherals/rtc.rs @@ -5,13 +5,12 @@ use device_api::{ interrupt::{InterruptHandler, Irq}, }; use kernel_arch::{Architecture, ArchitectureImpl}; -use libk::{device::external_interrupt_controller, time}; -use libk_util::sync::IrqSafeSpinlock; - -use crate::arch::x86::{ +use kernel_arch_x86::{ intrinsics::{io_wait, IoPort, IoPortAccess}, ISA_IRQ_OFFSET, }; +use libk::{device::external_interrupt_controller, time}; +use libk_util::sync::IrqSafeSpinlock; const NMI_DISABLE: u8 = 1 << 7; const CMOS_REG_SEC: u8 = 0x00; diff --git a/kernel/src/arch/x86/peripherals/serial.rs b/kernel/src/arch/x86/peripherals/serial.rs index 378e240a..ba95bbbb 100644 --- a/kernel/src/arch/x86/peripherals/serial.rs +++ b/kernel/src/arch/x86/peripherals/serial.rs @@ -5,6 +5,7 @@ use device_api::{ device::Device, interrupt::{InterruptHandler, Irq}, }; +use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess}; use libk::{ debug::DebugSink, device::{external_interrupt_controller, manager::DEVICE_REGISTRY}, @@ -12,8 +13,6 @@ use libk::{ }; use libk_util::sync::IrqSafeSpinlock; -use crate::arch::x86::intrinsics::{IoPort, IoPortAccess}; - // Single port struct Regs { dr: IoPort, diff --git a/kernel/src/arch/x86_64/acpi.rs b/kernel/src/arch/x86_64/acpi.rs deleted file mode 100644 index d93d7612..00000000 --- a/kernel/src/arch/x86_64/acpi.rs +++ /dev/null @@ -1,390 +0,0 @@ -//! x86-64 implementation of ACPI management interfaces -use core::{ - alloc::{AllocError, Allocator, GlobalAlloc, Layout}, - ptr::NonNull, - sync::atomic::Ordering, - time::Duration, -}; - -use ::acpi::{AcpiHandler, AcpiTables, PhysicalMapping}; -use acpi_system::{ - AcpiInterruptMethod, AcpiSleepState, AcpiSystem, AcpiSystemError, EventAction, FixedEvent, -}; -use alloc::{boxed::Box, sync::Arc}; -use device_api::{ - device::Device, - interrupt::{InterruptHandler, IpiDeliveryTarget, IpiMessage, Irq}, -}; -use kernel_arch_x86_64::CPU_COUNT; -use libk::device::external_interrupt_controller; -use libk_mm::{ - address::{PhysicalAddress, Virtualize}, - heap::GLOBAL_HEAP, - pointer::PhysicalRef, -}; -use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; -use yggdrasil_abi::error::Error; - -use crate::{ - arch::{ - x86_64::{apic::ioapic::ISA_IRQ_OFFSET, SHUTDOWN_FENCE}, - Platform, PLATFORM, - }, - mem::{read_memory, write_memory}, -}; - -use super::intrinsics; - -#[derive(Clone, Copy)] -#[doc(hidden)] -pub struct AcpiAllocator; -#[derive(Clone, Copy)] -#[doc(hidden)] -pub struct AcpiHandlerImpl; -struct SciHandler; - -static ACPI_SYSTEM: OneTimeInit>> = OneTimeInit::new(); - -// impl Device for SciHandler { -// fn display_name(&self) -> &'static str { -// "ACPI interrupt handler" -// } -// } - -impl Device for SciHandler { - fn display_name(&self) -> &str { - "ACPI SCI Handler" - } -} - -impl InterruptHandler for SciHandler { - fn handle_irq(self: Arc, _vector: Option) -> bool { - log::trace!("ACPI SCI received"); - ACPI_SYSTEM.get().lock().handle_sci(); - true - } -} - -unsafe impl Allocator for AcpiAllocator { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - let ptr = unsafe { GLOBAL_HEAP.alloc(layout) }; - log::trace!("ACPI alloc: {:?} -> {:p}", layout, ptr); - - if ptr.is_null() { - Err(AllocError) - } else { - unsafe { - Ok(NonNull::slice_from_raw_parts( - NonNull::new_unchecked(ptr), - layout.size(), - )) - } - } - } - - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - log::trace!("ACPI dealloc: {:?}, {:?}", ptr, layout); - GLOBAL_HEAP.dealloc(ptr.as_ptr(), layout); - } -} - -impl acpi_system::Handler for AcpiHandlerImpl { - type MappedSlice = PhysicalRef<'static, [u8]>; - - unsafe fn map_slice(address: u64, length: u64) -> Self::MappedSlice { - 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 aml::Handler for AcpiHandlerImpl { - fn read_io_u8(&self, port: u16) -> u8 { - ::io_read_u8(port) - } - - fn read_io_u16(&self, port: u16) -> u16 { - ::io_read_u16(port) - } - - fn read_io_u32(&self, port: u16) -> u32 { - ::io_read_u32(port) - } - - fn write_io_u8(&self, port: u16, value: u8) { - ::io_write_u8(port, value) - } - - fn write_io_u16(&self, port: u16, value: u16) { - ::io_write_u16(port, value) - } - - fn write_io_u32(&self, port: u16, value: u32) { - ::io_write_u32(port, value) - } - - fn read_u8(&self, address: usize) -> u8 { - ::mem_read_u8(address as u64) - } - - fn read_u16(&self, address: usize) -> u16 { - ::mem_read_u16(address as u64) - } - - fn read_u32(&self, address: usize) -> u32 { - ::mem_read_u32(address as u64) - } - - fn read_u64(&self, address: usize) -> u64 { - ::mem_read_u64(address as u64) - } - - fn write_u8(&self, address: usize, value: u8) { - ::mem_write_u8(address as u64, value) - } - - fn write_u16(&self, address: usize, value: u16) { - ::mem_write_u16(address as u64, value) - } - - fn write_u32(&self, address: usize, value: u32) { - ::mem_write_u32(address as u64, value) - } - - fn write_u64(&self, address: usize, value: u64) { - ::mem_write_u64(address as u64, value) - } - - fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - 0xFF - } - - fn read_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u16 { - 0xFFFF - } - - fn read_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u32 { - 0xFFFFFFFF - } - - fn write_pci_u8( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u8, - ) { - } - - fn write_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u16, - ) { - } - - fn write_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u32, - ) { - } - - fn read_ec_u8(&self, _address: u64) -> u8 { - 0x00 - } - - fn write_ec_u8(&self, _address: u64, _value: u8) {} - - fn sleep(&self, _duration: Duration) { - todo!() - // util::polling_sleep(duration).unwrap(); - } -} - -impl AcpiHandler for AcpiHandlerImpl { - // No actual address space modification is performed - unsafe fn map_physical_region( - &self, - physical_address: usize, - size: usize, - ) -> PhysicalMapping { - PhysicalMapping::new( - physical_address, - NonNull::new_unchecked( - PhysicalAddress::from_usize(physical_address).virtualize() as *mut T - ), - size, - size, - *self, - ) - } - - // Unmap nothing, these addresses are "virtualized" to high address space - fn unmap_physical_region(_region: &PhysicalMapping) {} -} - -/// Initializes ACPI management -#[allow(unused)] -pub fn init_acpi(tables: &'static AcpiTables) -> Result<(), Error> { - // TODO currently broken for real HW - let mut system = AcpiSystem::new(tables, Box::new(AcpiHandlerImpl)).unwrap(); - - system.initialize(AcpiInterruptMethod::Apic).unwrap(); - - system - .enable_fixed_event( - &FixedEvent::POWER_BUTTON, - Box::new(|_| { - log::info!("Power button was pressed"); - - // TODO the correct way would be to - // 1. Nicely ask all the processes to quit - // 2. Wait for some time - // 3. Kill the remaining ones - // 4. Halt other cores - // 5. Sync filesystem - // 6. Do something with the devices - // 7. Actually enter the S5 state - - unsafe { - PLATFORM - .send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown) - .unwrap(); - } - - SHUTDOWN_FENCE.signal(); - SHUTDOWN_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire)); - - log::info!("CPUs are parked, can shutdown now"); - - EventAction::EnterSleepState(AcpiSleepState::S5) - }), - ) - .unwrap(); - - ACPI_SYSTEM.init(IrqSafeSpinlock::new(system)); - - Ok(()) -} diff --git a/kernel/src/arch/x86_64/apic/ioapic.rs b/kernel/src/arch/x86_64/apic/ioapic.rs index 194e1f6b..bbc6470c 100644 --- a/kernel/src/arch/x86_64/apic/ioapic.rs +++ b/kernel/src/arch/x86_64/apic/ioapic.rs @@ -9,6 +9,7 @@ use device_api::{ IrqLevel, IrqOptions, IrqTrigger, }, }; +use kernel_arch_x86::ISA_IRQ_OFFSET; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; use libk_util::sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}; use tock_registers::{ @@ -16,13 +17,12 @@ use tock_registers::{ register_structs, registers::{ReadWrite, WriteOnly}, }; +use ygg_driver_acpi::AcpiAllocator; -use crate::arch::x86_64::{acpi::AcpiAllocator, apic::local::BSP_APIC_ID}; +use crate::arch::x86_64::apic::local::BSP_APIC_ID; use super::{APIC_EXTERNAL_OFFSET, POPULATED_EXTERNAL_VECTORS}; -pub const ISA_IRQ_OFFSET: u32 = 1024; - // IRQ 0 is timer, IRQ 1 reserved (for now?), +32 offset for exception entries const IO_APIC_VECTOR_OFFSET: u32 = 32 + APIC_EXTERNAL_OFFSET; diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 2a60968b..6575eb21 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -3,13 +3,12 @@ use core::{mem::size_of, ops::DerefMut, ptr::null_mut, sync::atomic::Ordering}; use ::acpi::{mcfg::Mcfg, AcpiTables, HpetInfo, InterruptModel}; use abi::error::Error; -use acpi::{AcpiAllocator, AcpiHandlerImpl}; use alloc::{boxed::Box, sync::Arc}; use apic::{ioapic::IoApic, local::LocalApic}; use device_api::device::Device; use kernel_arch_x86::{ cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures, ExtEdxFeatures}, - gdt, + gdt, intrinsics, }; use kernel_arch_x86_64::{ mem::{ @@ -34,14 +33,14 @@ use libk_mm::{ phys::{self, reserved::reserve_region, PhysicalMemoryRegion}, table::{EntryLevel, EntryLevelExt}, }; -use libk_util::{sync::SpinFence, OneTimeInit}; +use libk_util::OneTimeInit; use yboot_proto::{ v1::{self, AvailableMemoryRegion}, LoadProtocolV1, }; +use ygg_driver_acpi::{AcpiAllocator, AcpiHandlerImpl, EventAction, FixedEvent}; use ygg_driver_pci::PciBusManager; -mod acpi; mod apic; mod boot; mod exception; @@ -55,13 +54,7 @@ use crate::{ use self::boot::BootData; -use super::{ - x86::{intrinsics, InitrdSource}, - Platform, -}; - -/// Offset where legacy ISA IRQs are remapped -pub const ISA_IRQ_OFFSET: u32 = apic::ioapic::ISA_IRQ_OFFSET; +use super::{x86::InitrdSource, Platform}; /// x86-64 architecture implementation pub struct X86_64 { @@ -71,8 +64,6 @@ pub struct X86_64 { fbconsole: OneTimeInit>, } -static SHUTDOWN_FENCE: SpinFence = SpinFence::new(); - /// Global x86-64 architecture value pub static PLATFORM: X86_64 = X86_64 { boot_data: OneTimeInit::new(), @@ -385,7 +376,18 @@ impl X86_64 { let ioapic = IoApic::from_acpi(&apic_info)?; register_external_interrupt_controller(ioapic); - // acpi::init_acpi(acpi).unwrap(); + if let Err(error) = ygg_driver_acpi::switch_to_acpi(acpi) { + log::error!("ACPI initialization error: {error:?}"); + } else { + if let Err(error) = + ygg_driver_acpi::add_event_handler(&FixedEvent::POWER_BUTTON, |_| { + log::info!("Power button pressed!"); + EventAction::Nothing + }) + { + log::error!("Couldn't set ACPI power button handler: {error:?}"); + } + } if let Ok(mcfg) = acpi.find_table::() { for entry in mcfg.entries() { diff --git a/kernel/src/arch/x86_64/smp.rs b/kernel/src/arch/x86_64/smp.rs index 409560cb..cdb9ace1 100644 --- a/kernel/src/arch/x86_64/smp.rs +++ b/kernel/src/arch/x86_64/smp.rs @@ -18,11 +18,10 @@ use libk_mm::{ pointer::PhysicalRefMut, TableAllocatorImpl, }; +use ygg_driver_acpi::AcpiAllocator; use crate::arch::x86_64::boot::__x86_64_ap_entry; -use super::acpi::AcpiAllocator; - static AP_BOOTSTRAP_BIN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/__x86_64_ap_boot.bin")); const AP_STACK_PAGES: usize = 8;