acpi: move ACPI to its own driver

This commit is contained in:
Mark Poliakov 2025-01-27 18:10:56 +02:00
parent 9e48530e62
commit 6e7a42c2cb
21 changed files with 527 additions and 448 deletions

19
Cargo.lock generated
View File

@ -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",

View File

@ -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" }

View File

@ -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 = []

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,131 @@
use core::time::Duration;
use crate::AcpiHandlerImpl;
impl aml::Handler for AcpiHandlerImpl {
fn read_io_u8(&self, port: u16) -> u8 {
<Self as acpi_system::Handler>::io_read_u8(port)
}
fn read_io_u16(&self, port: u16) -> u16 {
<Self as acpi_system::Handler>::io_read_u16(port)
}
fn read_io_u32(&self, port: u16) -> u32 {
<Self as acpi_system::Handler>::io_read_u32(port)
}
fn write_io_u8(&self, port: u16, value: u8) {
<Self as acpi_system::Handler>::io_write_u8(port, value)
}
fn write_io_u16(&self, port: u16, value: u16) {
<Self as acpi_system::Handler>::io_write_u16(port, value)
}
fn write_io_u32(&self, port: u16, value: u32) {
<Self as acpi_system::Handler>::io_write_u32(port, value)
}
fn read_u8(&self, address: usize) -> u8 {
<Self as acpi_system::Handler>::mem_read_u8(address as u64)
}
fn read_u16(&self, address: usize) -> u16 {
<Self as acpi_system::Handler>::mem_read_u16(address as u64)
}
fn read_u32(&self, address: usize) -> u32 {
<Self as acpi_system::Handler>::mem_read_u32(address as u64)
}
fn read_u64(&self, address: usize) -> u64 {
<Self as acpi_system::Handler>::mem_read_u64(address as u64)
}
fn write_u8(&self, address: usize, value: u8) {
<Self as acpi_system::Handler>::mem_write_u8(address as u64, value)
}
fn write_u16(&self, address: usize, value: u16) {
<Self as acpi_system::Handler>::mem_write_u16(address as u64, value)
}
fn write_u32(&self, address: usize, value: u32) {
<Self as acpi_system::Handler>::mem_write_u32(address as u64, value)
}
fn write_u64(&self, address: usize, value: u64) {
<Self as acpi_system::Handler>::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();
}
}

View File

@ -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<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"
}
}

View File

@ -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<IrqSafeSpinlock<AcpiSystem<AcpiHandlerImpl>>> = OneTimeInit::new();
pub fn add_event_handler<F: Fn(&AcpiSystem<AcpiHandlerImpl>) -> 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<AcpiHandlerImpl>) -> 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(())
}

View File

@ -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<NonNull<[u8]>, 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<u8>, 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<T>(address: PhysicalAddress) -> T {
let io =
unsafe { DeviceMemoryMapping::map(address, size_of::<T>(), Default::default()).unwrap() };
let address = io.address();
unsafe {
if address % align_of::<T>() == 0 {
(address as *const T).read_volatile()
} else {
(address as *const T).read_unaligned()
}
}
}
pub unsafe fn write_memory<T>(address: PhysicalAddress, value: T) {
let io =
unsafe { DeviceMemoryMapping::map(address, size_of::<T>(), Default::default()).unwrap() };
let address = io.address();
unsafe {
if address % align_of::<T>() == 0 {
(address as *mut T).write_volatile(value)
} else {
(address as *mut T).write_unaligned(value)
}
}
}

View File

@ -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,

View File

@ -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<u32>,
data: IoPort<u32>,

View File

@ -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;

View File

@ -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))]

View File

@ -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;

View File

@ -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;

View File

@ -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<u8>,

View File

@ -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<IrqSafeSpinlock<AcpiSystem<AcpiHandlerImpl>>> = 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<Self>, _vector: Option<usize>) -> bool {
log::trace!("ACPI SCI received");
ACPI_SYSTEM.get().lock().handle_sci();
true
}
}
unsafe impl Allocator for AcpiAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, 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<u8>, 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 {
<Self as acpi_system::Handler>::io_read_u8(port)
}
fn read_io_u16(&self, port: u16) -> u16 {
<Self as acpi_system::Handler>::io_read_u16(port)
}
fn read_io_u32(&self, port: u16) -> u32 {
<Self as acpi_system::Handler>::io_read_u32(port)
}
fn write_io_u8(&self, port: u16, value: u8) {
<Self as acpi_system::Handler>::io_write_u8(port, value)
}
fn write_io_u16(&self, port: u16, value: u16) {
<Self as acpi_system::Handler>::io_write_u16(port, value)
}
fn write_io_u32(&self, port: u16, value: u32) {
<Self as acpi_system::Handler>::io_write_u32(port, value)
}
fn read_u8(&self, address: usize) -> u8 {
<Self as acpi_system::Handler>::mem_read_u8(address as u64)
}
fn read_u16(&self, address: usize) -> u16 {
<Self as acpi_system::Handler>::mem_read_u16(address as u64)
}
fn read_u32(&self, address: usize) -> u32 {
<Self as acpi_system::Handler>::mem_read_u32(address as u64)
}
fn read_u64(&self, address: usize) -> u64 {
<Self as acpi_system::Handler>::mem_read_u64(address as u64)
}
fn write_u8(&self, address: usize, value: u8) {
<Self as acpi_system::Handler>::mem_write_u8(address as u64, value)
}
fn write_u16(&self, address: usize, value: u16) {
<Self as acpi_system::Handler>::mem_write_u16(address as u64, value)
}
fn write_u32(&self, address: usize, value: u32) {
<Self as acpi_system::Handler>::mem_write_u32(address as u64, value)
}
fn write_u64(&self, address: usize, value: u64) {
<Self as acpi_system::Handler>::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<T>(
&self,
physical_address: usize,
size: usize,
) -> PhysicalMapping<Self, T> {
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<T>(_region: &PhysicalMapping<Self, T>) {}
}
/// Initializes ACPI management
#[allow(unused)]
pub fn init_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> 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(())
}

View File

@ -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;

View File

@ -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<Arc<FramebufferConsole>>,
}
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::<Mcfg>() {
for entry in mcfg.entries() {

View File

@ -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;