Compare commits
3 Commits
abdf53368b
...
baed9c4868
Author | SHA1 | Date | |
---|---|---|---|
baed9c4868 | |||
62e42b8455 | |||
07726b4a26 |
738
Cargo.lock
generated
738
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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" }
|
||||
|
||||
|
@ -61,12 +61,12 @@ 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" }
|
||||
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
|
||||
|
||||
acpi.workspace = true
|
||||
aml.workspace = true
|
||||
acpi-system.workspace = true
|
||||
|
||||
[target.'cfg(target_arch = "x86")'.dependencies]
|
||||
kernel-arch-i686.workspace = true
|
||||
@ -87,6 +87,9 @@ kernel-arch-x86.workspace = true
|
||||
kernel-arch-aarch64.workspace = true
|
||||
kernel-arch-riscv64.workspace = true
|
||||
|
||||
ygg_driver_acpi.path = "driver/acpi"
|
||||
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
|
||||
|
||||
[features]
|
||||
default = ["fb_console"]
|
||||
fb_console = []
|
||||
|
@ -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;
|
||||
|
18
kernel/driver/acpi/Cargo.toml
Normal file
18
kernel/driver/acpi/Cargo.toml
Normal 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
|
131
kernel/driver/acpi/src/aml_handler.rs
Normal file
131
kernel/driver/acpi/src/aml_handler.rs
Normal 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();
|
||||
}
|
||||
}
|
171
kernel/driver/acpi/src/handler.rs
Normal file
171
kernel/driver/acpi/src/handler.rs
Normal 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"
|
||||
}
|
||||
}
|
89
kernel/driver/acpi/src/lib.rs
Normal file
89
kernel/driver/acpi/src/lib.rs
Normal file
@ -0,0 +1,89 @@
|
||||
#![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, InterruptPolarity, InterruptTrigger, IrqDescriptor, PciPin,
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn get_pci_route(
|
||||
aml_path: &str,
|
||||
device: u16,
|
||||
function: u16,
|
||||
pin: PciPin,
|
||||
) -> Option<IrqDescriptor> {
|
||||
ACPI_SYSTEM
|
||||
.get()
|
||||
.lock()
|
||||
.pci_route(aml_path, device, function, pin)
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// 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(())
|
||||
}
|
64
kernel/driver/acpi/src/mem.rs
Normal file
64
kernel/driver/acpi/src/mem.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ bitflags.workspace = true
|
||||
tock-registers.workspace = true
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||
ygg_driver_acpi.path = "../../acpi"
|
||||
acpi.workspace = true
|
||||
|
||||
[lints]
|
||||
|
@ -110,7 +110,6 @@ impl PciDeviceInfo {
|
||||
// Ignore preferred_mode, the only supported is Legacy
|
||||
self.legacy_interrupt_mode()
|
||||
};
|
||||
|
||||
IrqSafeRwLock::new(InterruptConfig {
|
||||
preferred_mode,
|
||||
configured_mode,
|
||||
@ -201,11 +200,7 @@ impl PciDeviceInfo {
|
||||
address: self.address,
|
||||
pin,
|
||||
};
|
||||
let route = self
|
||||
.segment
|
||||
.irq_translation_map
|
||||
.get(&src)
|
||||
.ok_or(Error::InvalidOperation)?;
|
||||
let route = self.segment.irq_translation_map.map_interrupt(&src)?;
|
||||
|
||||
log::debug!(
|
||||
"PCI {} pin {:?} -> system IRQ #{}",
|
||||
|
55
kernel/driver/bus/pci/src/interrupt.rs
Normal file
55
kernel/driver/bus/pci/src/interrupt.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use alloc::collections::btree_map::BTreeMap;
|
||||
use libk::error::Error;
|
||||
|
||||
use crate::device::{PciInterrupt, PciInterruptRoute};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PciInterruptMap {
|
||||
Fixed(BTreeMap<PciInterrupt, PciInterruptRoute>),
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
Acpi(alloc::string::String),
|
||||
Legacy,
|
||||
}
|
||||
|
||||
impl PciInterruptMap {
|
||||
pub fn map_interrupt(&self, interrupt: &PciInterrupt) -> Result<PciInterruptRoute, Error> {
|
||||
match self {
|
||||
Self::Fixed(map) => map.get(interrupt).cloned().ok_or(Error::DoesNotExist),
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
Self::Acpi(aml_object_name) => {
|
||||
use device_api::interrupt::{IrqLevel, IrqOptions, IrqTrigger};
|
||||
|
||||
use crate::device::PciInterruptPin;
|
||||
|
||||
let aml_pin = match interrupt.pin {
|
||||
PciInterruptPin::A => ygg_driver_acpi::PciPin::IntA,
|
||||
PciInterruptPin::B => ygg_driver_acpi::PciPin::IntB,
|
||||
PciInterruptPin::C => ygg_driver_acpi::PciPin::IntC,
|
||||
PciInterruptPin::D => ygg_driver_acpi::PciPin::IntD,
|
||||
};
|
||||
let aml_route = ygg_driver_acpi::get_pci_route(
|
||||
aml_object_name.as_str(),
|
||||
interrupt.address.device as u16,
|
||||
interrupt.address.function as u16,
|
||||
aml_pin,
|
||||
)
|
||||
.ok_or(Error::DoesNotExist)?;
|
||||
|
||||
let trigger = match aml_route.trigger {
|
||||
ygg_driver_acpi::InterruptTrigger::Edge => IrqTrigger::Edge,
|
||||
ygg_driver_acpi::InterruptTrigger::Level => IrqTrigger::Level,
|
||||
};
|
||||
let level = match aml_route.polarity {
|
||||
ygg_driver_acpi::InterruptPolarity::ActiveLow => IrqLevel::ActiveLow,
|
||||
ygg_driver_acpi::InterruptPolarity::ActiveHigh => IrqLevel::ActiveHigh,
|
||||
};
|
||||
|
||||
Ok(PciInterruptRoute {
|
||||
options: IrqOptions { trigger, level },
|
||||
number: aml_route.irq,
|
||||
})
|
||||
}
|
||||
Self::Legacy => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -6,12 +6,14 @@ extern crate alloc;
|
||||
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
use acpi::mcfg::McfgEntry;
|
||||
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use bitflags::bitflags;
|
||||
use device::{PciBusDevice, PciDeviceInfo, PciDriver, PciInterrupt, PciInterruptRoute, PciMatch};
|
||||
use device::{PciBusDevice, PciDeviceInfo, PciDriver, PciMatch};
|
||||
use device_api::device::Device;
|
||||
use interrupt::PciInterruptMap;
|
||||
use libk_mm::address::PhysicalAddress;
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use space::legacy;
|
||||
@ -19,6 +21,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
pub mod capability;
|
||||
pub mod device;
|
||||
pub mod interrupt;
|
||||
mod space;
|
||||
|
||||
pub use space::{
|
||||
@ -200,7 +203,7 @@ pub struct PciSegmentInfo {
|
||||
pub bus_number_end: u8,
|
||||
pub ecam_phys_base: Option<PhysicalAddress>,
|
||||
|
||||
pub irq_translation_map: BTreeMap<PciInterrupt, PciInterruptRoute>,
|
||||
pub irq_translation_map: PciInterruptMap,
|
||||
pub has_msi: bool,
|
||||
}
|
||||
|
||||
@ -425,7 +428,7 @@ impl PciBusManager {
|
||||
bus_number_start: 0,
|
||||
bus_number_end: 255,
|
||||
ecam_phys_base: None,
|
||||
irq_translation_map: BTreeMap::new(),
|
||||
irq_translation_map: PciInterruptMap::Legacy,
|
||||
has_msi: false,
|
||||
}),
|
||||
allocator: None,
|
||||
@ -449,8 +452,8 @@ impl PciBusManager {
|
||||
bus_number_end: entry.bus_number_end,
|
||||
ecam_phys_base: Some(PhysicalAddress::from_u64(entry.base_address)),
|
||||
|
||||
// TODO obtain this from ACPI SSDT
|
||||
irq_translation_map: BTreeMap::new(),
|
||||
// TODO get the segment's PCI root bridge AML name
|
||||
irq_translation_map: PciInterruptMap::Acpi("\\_SB.PCI0._PRT".into()),
|
||||
has_msi: true,
|
||||
}),
|
||||
// Firmware done this for us
|
||||
|
17
kernel/driver/net/rtl81xx/Cargo.toml
Normal file
17
kernel/driver/net/rtl81xx/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "ygg_driver_net_rtl81xx"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
device-api.workspace = true
|
||||
yggdrasil-abi.workspace = true
|
||||
libk-mm.workspace = true
|
||||
libk-util.workspace = true
|
||||
libk.workspace = true
|
||||
|
||||
ygg_driver_pci.path = "../../bus/pci"
|
||||
ygg_driver_net_core.path = "../core"
|
||||
|
||||
tock-registers.workspace = true
|
||||
log.workspace = true
|
37
kernel/driver/net/rtl81xx/src/lib.rs
Normal file
37
kernel/driver/net/rtl81xx/src/lib.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#![no_std]
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::Device;
|
||||
use libk::error::Error;
|
||||
use rtl8139::Rtl8139;
|
||||
use ygg_driver_pci::{
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
PciBaseAddress, PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod rtl8139;
|
||||
|
||||
pub fn probe_8169(_info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn probe_8139(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
|
||||
info.init_interrupts(PreferredInterruptMode::Msi)?;
|
||||
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
let mut command = info.config_space.command();
|
||||
command |= (PciCommandRegister::BUS_MASTER | PciCommandRegister::ENABLE_MEMORY).bits();
|
||||
command &= !(PciCommandRegister::ENABLE_IO | PciCommandRegister::DISABLE_INTERRUPTS).bits();
|
||||
info.config_space.set_command(command);
|
||||
|
||||
let base = info
|
||||
.config_space
|
||||
.bar(1)
|
||||
.and_then(PciBaseAddress::as_memory)
|
||||
.ok_or(Error::InvalidArgument)?;
|
||||
|
||||
let device = Rtl8139::new(base, info.clone())?;
|
||||
Ok(Arc::new(device))
|
||||
}
|
422
kernel/driver/net/rtl81xx/src/rtl8139.rs
Normal file
422
kernel/driver/net/rtl81xx/src/rtl8139.rs
Normal file
@ -0,0 +1,422 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{device::Device, interrupt::InterruptHandler};
|
||||
use libk::error::Error;
|
||||
use libk_mm::{
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
device::DeviceMemoryIo,
|
||||
PageBox,
|
||||
};
|
||||
use libk_util::{queue::BoundedQueue, sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite},
|
||||
};
|
||||
use ygg_driver_net_core::{
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
Packet,
|
||||
};
|
||||
use ygg_driver_pci::device::PciDeviceInfo;
|
||||
use yggdrasil_abi::net::MacAddress;
|
||||
|
||||
register_bitfields! {
|
||||
u8,
|
||||
|
||||
pub CR [
|
||||
/// Reset. Setting this bit forces the RTL8139D(L) to perform a software reset. This bit is
|
||||
/// cleared by the RTL8139D(L) after the reset completes.
|
||||
RST OFFSET(4) NUMBITS(1) [],
|
||||
/// Receiver enable
|
||||
RE OFFSET(3) NUMBITS(1) [],
|
||||
/// Transmitter enable
|
||||
TE OFFSET(2) NUMBITS(1) [],
|
||||
/// Rx buffer empty
|
||||
BUFE OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
|
||||
pub CONFIG1 [
|
||||
/// LED pin control
|
||||
LEDS1 OFFSET(7) NUMBITS(1) [],
|
||||
/// LED pin control
|
||||
LEDS0 OFFSET(6) NUMBITS(1) [],
|
||||
/// Driver load. Software may use this bit to make sure that the driver has been loaded.
|
||||
DVRLOAD OFFSET(5) NUMBITS(1) [],
|
||||
/// LWAKE active mode. The LWACT bit and LWPTN bit in CONFIG4 are used to program the LWAKE
|
||||
/// pin's output signal.
|
||||
LWACT OFFSET(4) NUMBITS(1) [],
|
||||
/// The operational registers are mapped into PCI memory space
|
||||
MEMMAP OFFSET(3) NUMBITS(1) [],
|
||||
/// The operational registers are mapped into PCI I/O space
|
||||
IOMAP OFFSET(2) NUMBITS(1) [],
|
||||
/// Set to enable Vital Product Data
|
||||
VPD OFFSET(1) NUMBITS(1) [],
|
||||
/// Power management enable
|
||||
PMEn OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
}
|
||||
|
||||
register_bitfields! {
|
||||
u16,
|
||||
|
||||
pub IMR_ISR [
|
||||
/// System error interrupt
|
||||
SERR OFFSET(15) NUMBITS(1) [],
|
||||
/// Time out interrupt
|
||||
TIMEOUT OFFSET(14) NUMBITS(1) [],
|
||||
/// Cable length change interrupt
|
||||
LENCHG OFFSET(13) NUMBITS(1) [],
|
||||
/// Rx FIFO overflow interrupt
|
||||
FOVW OFFSET(6) NUMBITS(1) [],
|
||||
/// Packet underrun/Link change interrupt
|
||||
PUN_LINKCHG OFFSET(5) NUMBITS(1) [],
|
||||
/// Rx buffer overflow
|
||||
RXOVW OFFSET(4) NUMBITS(1) [],
|
||||
/// Tx error interrupt
|
||||
TER OFFSET(3) NUMBITS(1) [],
|
||||
/// Tx OK interrupt
|
||||
TOK OFFSET(2) NUMBITS(1) [],
|
||||
/// Rx error interrupt
|
||||
RER OFFSET(1) NUMBITS(1) [],
|
||||
/// Rx OK interrupt
|
||||
ROK OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
}
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
|
||||
pub TSDn [
|
||||
/// Carrier sense lost
|
||||
CRS OFFSET(31) NUMBITS(1) [],
|
||||
/// Tx aborted
|
||||
TABT OFFSET(30) NUMBITS(1) [],
|
||||
/// Out of window collision
|
||||
OWC OFFSET(29) NUMBITS(1) [],
|
||||
/// CD heart beat
|
||||
CDH OFFSET(28) NUMBITS(1) [],
|
||||
/// Number of collision count
|
||||
NCC OFFSET(24) NUMBITS(4) [],
|
||||
/// Early Tx threshold
|
||||
ERTXTH OFFSET(16) NUMBITS(6) [],
|
||||
/// Tx OK
|
||||
TOK OFFSET(15) NUMBITS(1) [],
|
||||
/// Tx FIFO underrun
|
||||
TUN OFFSET(14) NUMBITS(1) [],
|
||||
/// Tx descriptor is owned by the DMA. Set to 0 by the driver to initiate a send
|
||||
OWN OFFSET(13) NUMBITS(1) [],
|
||||
/// Tx size
|
||||
SIZE OFFSET(0) NUMBITS(13) [],
|
||||
],
|
||||
|
||||
pub RCR [
|
||||
/// Early Rx threshold bits
|
||||
ERTH OFFSET(24) NUMBITS(4) [],
|
||||
/// Multiple early interrupt select
|
||||
MULERINT OFFSET(17) NUMBITS(1) [],
|
||||
/// TBD, didn't really understand the docs, lmao
|
||||
RER8 OFFSET(16) NUMBITS(1) [],
|
||||
/// Rx FIFO threshold
|
||||
RXFTH OFFSET(13) NUMBITS(3) [],
|
||||
/// Rx buffer length (+16 bytes)
|
||||
RBLEN OFFSET(11) NUMBITS(2) [
|
||||
Len8K = 0,
|
||||
Len16K = 1,
|
||||
Len32K = 2,
|
||||
Len64K = 3,
|
||||
],
|
||||
/// Max DMA burst size per Rx DMA burst
|
||||
MXDMA OFFSET(8) NUMBITS(3) [],
|
||||
/// When 0: the packet will get split if crossing the Rx buffer end
|
||||
/// When 1: the packet will get placed contiguously
|
||||
WRAP OFFSET(7) NUMBITS(1) [],
|
||||
/// Accept error packet
|
||||
AER OFFSET(5) NUMBITS(1) [],
|
||||
/// Accept runt (packets smaller than 64 bytes)
|
||||
AR OFFSET(4) NUMBITS(1) [],
|
||||
/// Accept broadcast packets
|
||||
AB OFFSET(3) NUMBITS(1) [],
|
||||
/// Accept multicast packets
|
||||
AM OFFSET(2) NUMBITS(1) [],
|
||||
/// Accept physical match
|
||||
APM OFFSET(1) NUMBITS(1) [],
|
||||
/// Accept all packets
|
||||
AAP OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
pub Regs {
|
||||
(0x0000 => pub IDRn: [ReadWrite<u32>; 2]),
|
||||
(0x0008 => pub MARn: [ReadWrite<u8>; 8]),
|
||||
(0x0010 => pub TSDn: [ReadWrite<u32, TSDn::Register>; 4]),
|
||||
(0x0020 => pub TSADn: [ReadWrite<u32>; 4]),
|
||||
(0x0030 => pub RBSTART: ReadWrite<u32>),
|
||||
(0x0034 => pub ERBCR: ReadOnly<u16>),
|
||||
(0x0036 => pub ERSR: ReadOnly<u8>),
|
||||
(0x0037 => pub CR: ReadWrite<u8, CR::Register>),
|
||||
(0x0038 => pub CAPR: ReadWrite<u16>),
|
||||
(0x003A => pub CBR: ReadOnly<u16>),
|
||||
(0x003C => pub IMR: ReadWrite<u16, IMR_ISR::Register>),
|
||||
(0x003E => pub ISR: ReadWrite<u16, IMR_ISR::Register>),
|
||||
(0x0040 => pub TCR: ReadWrite<u32>),
|
||||
(0x0044 => pub RCR: ReadWrite<u32, RCR::Register>),
|
||||
(0x0048 => pub TCTR: ReadWrite<u32>),
|
||||
(0x004C => pub MPC: ReadWrite<u32>),
|
||||
(0x0050 => pub r9346CR: ReadWrite<u8>),
|
||||
(0x0051 => pub CONFIG0: ReadOnly<u8>),
|
||||
(0x0052 => pub CONFIG1: ReadWrite<u8, CONFIG1::Register>),
|
||||
(0x0053 => _1),
|
||||
(0x0054 => pub TIMERINT: ReadWrite<u32>),
|
||||
(0x0058 => pub MSR: ReadWrite<u8>),
|
||||
(0x0059 => pub CONFIG3: ReadWrite<u8>),
|
||||
(0x005A => pub CONFIG4: ReadWrite<u8>),
|
||||
(0x005B => _2),
|
||||
(0x005C => pub MULINT: ReadWrite<u16>),
|
||||
(0x005E => pub RERID: ReadOnly<u8>),
|
||||
(0x005F => _3),
|
||||
(0x0060 => pub TSAD: ReadOnly<u16>),
|
||||
(0x0062 => pub BMCR: ReadWrite<u16>),
|
||||
(0x0064 => pub BMSR: ReadOnly<u16>),
|
||||
(0x0066 => pub ANAR: ReadWrite<u16>),
|
||||
(0x0068 => pub ANLPAR: ReadOnly<u16>),
|
||||
(0x006A => pub ANER: ReadOnly<u16>),
|
||||
(0x006C => pub DIS: ReadOnly<u16>),
|
||||
(0x006E => pub FCSC: ReadOnly<u16>),
|
||||
(0x0070 => pub NWAYTR: ReadWrite<u16>),
|
||||
(0x0072 => pub REC: ReadOnly<u16>),
|
||||
(0x0074 => pub CSCR: ReadWrite<u16>),
|
||||
(0x0076 => _4),
|
||||
(0x0078 => pub PHY1_PARM: ReadWrite<u32>),
|
||||
(0x007C => pub TW_PARM: ReadWrite<u32>),
|
||||
(0x0080 => pub PHY2_PARM: ReadWrite<u8>),
|
||||
(0x0081 => _5),
|
||||
(0x0084 => pub CRCn: [ReadWrite<u8>; 8]),
|
||||
(0x008C => pub WAKEUPn: [ReadWrite<u32>; 16]),
|
||||
(0x00CC => pub LSBCRCn: [ReadWrite<u8>; 8]),
|
||||
(0x00D4 => _6),
|
||||
(0x00D8 => pub CONFIG5: ReadWrite<u8>),
|
||||
(0x00D9 => _7),
|
||||
(0x0100 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct Rx {
|
||||
buffer: PageBox<[MaybeUninit<u8>]>,
|
||||
rd: usize,
|
||||
}
|
||||
|
||||
// TODO place a secondary Tx queue here, to send the queued packets when more slots become
|
||||
// available
|
||||
struct Tx {
|
||||
buffers: [Option<PageBox<[u8]>>; 4],
|
||||
wr: usize,
|
||||
rd: usize,
|
||||
queue: BoundedQueue<PageBox<[u8]>>,
|
||||
}
|
||||
|
||||
pub struct Rtl8139 {
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
mac: MacAddress,
|
||||
pci: PciDeviceInfo,
|
||||
|
||||
nic: OneTimeInit<u32>,
|
||||
rx: OneTimeInit<IrqSafeSpinlock<Rx>>,
|
||||
tx: IrqSafeSpinlock<Tx>,
|
||||
}
|
||||
|
||||
impl Tx {
|
||||
pub fn tx_now(&mut self, regs: &Regs, packet: PageBox<[u8]>) -> Result<(), Error> {
|
||||
let packet_address = unsafe { packet.as_physical_address() }
|
||||
.try_into_u32()
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
let packet_len = packet.len();
|
||||
if packet_len > 1500 {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
|
||||
self.buffers[self.wr] = Some(packet);
|
||||
regs.TSADn[self.wr].set(packet_address);
|
||||
regs.TSDn[self.wr].write(TSDn::SIZE.val(packet_len as u32));
|
||||
|
||||
self.wr = (self.wr + 1) % 4;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
(self.wr + 1) % 4 == self.rd
|
||||
}
|
||||
}
|
||||
|
||||
impl Rtl8139 {
|
||||
// 8K + overflow space
|
||||
const RX_BUFFER_LEN: usize = 8192;
|
||||
const RX_BUFFER_OVERFLOW: usize = 4096;
|
||||
|
||||
pub fn new(base: PhysicalAddress, info: PciDeviceInfo) -> Result<Self, Error> {
|
||||
let regs = unsafe { DeviceMemoryIo::<Regs>::map(base, Default::default()) }?;
|
||||
let mac0 = regs.IDRn[0].get().to_le_bytes();
|
||||
let mac1 = regs.IDRn[1].get().to_le_bytes();
|
||||
let mac = MacAddress::from([mac0[0], mac0[1], mac0[2], mac0[3], mac1[0], mac1[1]]);
|
||||
|
||||
Ok(Self {
|
||||
mac,
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
pci: info,
|
||||
|
||||
nic: OneTimeInit::new(),
|
||||
rx: OneTimeInit::new(),
|
||||
tx: IrqSafeSpinlock::new(Tx {
|
||||
buffers: [const { None }; 4],
|
||||
wr: 0,
|
||||
rd: 0,
|
||||
queue: BoundedQueue::new(64),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Rtl8139 {
|
||||
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||
let regs = self.regs.lock();
|
||||
let status = regs.ISR.extract();
|
||||
// Clear ISR bits
|
||||
regs.ISR.write(IMR_ISR::TOK::SET + IMR_ISR::ROK::SET);
|
||||
|
||||
let mut any = false;
|
||||
if status.matches_all(IMR_ISR::TOK::SET) {
|
||||
let mut tx = self.tx.lock();
|
||||
|
||||
tx.rd = (tx.rd + 1) % 4;
|
||||
if let Some(packet) = tx.queue.pop() {
|
||||
// Should not fail, we just freed a single descriptor
|
||||
tx.tx_now(®s, packet).unwrap();
|
||||
}
|
||||
|
||||
any = true;
|
||||
}
|
||||
if status.matches_all(IMR_ISR::ROK::SET) {
|
||||
let nic = *self.nic.get();
|
||||
let mut rx = self.rx.get().lock();
|
||||
let cbr = regs.CBR.get();
|
||||
|
||||
loop {
|
||||
let rx_pos = rx.rd % Self::RX_BUFFER_LEN;
|
||||
if rx_pos == cbr as usize {
|
||||
break;
|
||||
}
|
||||
|
||||
// 4-byte preamble
|
||||
let rx_len_0 = unsafe { rx.buffer[rx_pos + 2].assume_init() };
|
||||
let rx_len_1 = unsafe { rx.buffer[rx_pos + 3].assume_init() };
|
||||
let rx_len = u16::from_le_bytes([rx_len_0, rx_len_1]) as usize;
|
||||
|
||||
if rx_len >= 16 {
|
||||
if let Ok(mut packet_buf) = PageBox::new_uninit_slice(rx_len) {
|
||||
packet_buf.copy_from_slice(&rx.buffer[rx_pos + 4..rx_pos + rx_len + 4]);
|
||||
let packet_buf = unsafe { packet_buf.assume_init_slice() };
|
||||
let packet = Packet::new(packet_buf, 0, nic);
|
||||
ygg_driver_net_core::receive_packet(packet).ok();
|
||||
}
|
||||
}
|
||||
|
||||
// rx_len + 4, aligned to 4 bytes
|
||||
let total_len = (rx_len + 7) & !3;
|
||||
rx.rd = rx.rd.wrapping_add(total_len);
|
||||
}
|
||||
|
||||
regs.CAPR.set((rx.rd as u16).max(cbr).wrapping_sub(0x10));
|
||||
rx.rd %= Self::RX_BUFFER_LEN;
|
||||
|
||||
any = true;
|
||||
}
|
||||
|
||||
any
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Rtl8139 {
|
||||
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
|
||||
log::info!("Initialize rtl8139 driver");
|
||||
log::info!("MAC: {}", self.mac);
|
||||
|
||||
// Setup the initial Rx buffer
|
||||
let rx_buffer = PageBox::new_uninit_slice(Self::RX_BUFFER_LEN + Self::RX_BUFFER_OVERFLOW)?;
|
||||
let rx_buffer_address = unsafe { rx_buffer.as_physical_address() }
|
||||
.try_into_u32()
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
|
||||
self.pci.map_interrupt(Default::default(), self.clone())?;
|
||||
|
||||
let regs = self.regs.lock();
|
||||
|
||||
// Power up the device
|
||||
regs.CONFIG1.set(0);
|
||||
|
||||
// Reset the device
|
||||
let mut timeout = 1000000;
|
||||
regs.CR.write(CR::RST::SET);
|
||||
while timeout > 0 && regs.CR.matches_all(CR::RST::SET) {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
if timeout == 0 {
|
||||
log::error!("rtl8139: reset timed out");
|
||||
return Err(Error::TimedOut);
|
||||
}
|
||||
|
||||
// Configure Rx
|
||||
regs.RBSTART.set(rx_buffer_address);
|
||||
regs.RCR
|
||||
.write(RCR::WRAP::SET + RCR::AB::SET + RCR::APM::SET + RCR::AR::SET + RCR::AM::SET);
|
||||
|
||||
// Enable Rx/Tx interrupts
|
||||
regs.IMR.write(IMR_ISR::ROK::SET + IMR_ISR::TOK::SET);
|
||||
|
||||
// Start Rx/Tx
|
||||
regs.CR.modify(CR::TE::SET + CR::RE::SET);
|
||||
|
||||
self.rx.init(IrqSafeSpinlock::new(Rx {
|
||||
buffer: rx_buffer,
|
||||
rd: 0,
|
||||
}));
|
||||
let nic =
|
||||
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
|
||||
self.nic.init(nic.id());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"Realtek RTL8139 10/100Mbps Ethernet Controller"
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkDevice for Rtl8139 {
|
||||
fn transmit(&self, packet: PageBox<[u8]>) -> Result<(), Error> {
|
||||
let mut tx = self.tx.lock();
|
||||
|
||||
// Buffer still in Tx, cannot send
|
||||
if tx.is_full() {
|
||||
if tx.queue.push(packet).is_err() {
|
||||
log::warn!("rtl8139: out of tx buffers + queue full");
|
||||
return Err(Error::WouldBlock);
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let regs = self.regs.lock();
|
||||
tx.tx_now(®s, packet)
|
||||
}
|
||||
|
||||
fn packet_prefix_size(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn read_hardware_address(&self) -> MacAddress {
|
||||
self.mac
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ use libk_mm::{
|
||||
};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
|
||||
use crate::arch::x86::intrinsics::{io_wait, IoPort, IoPortAccess};
|
||||
use kernel_arch_x86::intrinsics::{io_wait, IoPort, IoPortAccess};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
|
@ -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,
|
||||
@ -95,6 +89,18 @@ pub fn register_pci_drivers() {
|
||||
0x1000,
|
||||
ygg_driver_virtio_net::probe,
|
||||
);
|
||||
ygg_driver_pci::register_vendor_driver(
|
||||
"Realtek RTL8139 10/100Mbps Ethernet",
|
||||
0x10EC,
|
||||
0x8139,
|
||||
ygg_driver_net_rtl81xx::probe_8139,
|
||||
);
|
||||
ygg_driver_pci::register_vendor_driver(
|
||||
"Realtek RTL8169/8110 Gigabit Ethernet",
|
||||
0x10EC,
|
||||
0x8169,
|
||||
ygg_driver_net_rtl81xx::probe_8169,
|
||||
);
|
||||
}
|
||||
|
||||
// Initialize the bare minimum required to:
|
||||
|
@ -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>,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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))]
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>,
|
||||
|
@ -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(())
|
||||
}
|
@ -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;
|
||||
|
||||
@ -83,7 +83,7 @@ impl Regs {
|
||||
|
||||
impl Inner {
|
||||
fn map_gsi(&mut self, gsi: u32, vector: u32, apic_id: u32) -> Result<(), Error> {
|
||||
assert!(gsi < self.max_gsi);
|
||||
assert!(gsi <= self.max_gsi);
|
||||
assert!(vector < 0x100);
|
||||
|
||||
log::info!("map_irq gsi{}, vec{}, apic{}", gsi, vector, apic_id);
|
||||
@ -110,7 +110,7 @@ impl Inner {
|
||||
}
|
||||
|
||||
fn configure_gsi(&mut self, gsi: u32, level: IrqLevel, trigger: IrqTrigger) {
|
||||
assert!(gsi < self.max_gsi);
|
||||
assert!(gsi <= self.max_gsi);
|
||||
|
||||
let mut low = self.regs.read(REG_REDIRECTION_BASE + gsi * 2);
|
||||
|
||||
@ -138,7 +138,7 @@ impl Inner {
|
||||
}
|
||||
|
||||
fn set_gsi_enabled(&mut self, gsi: u32, enabled: bool) {
|
||||
assert!(gsi < self.max_gsi);
|
||||
assert!(gsi <= self.max_gsi);
|
||||
|
||||
let low = self.regs.read(REG_REDIRECTION_BASE + gsi * 2);
|
||||
if enabled {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -5,6 +5,7 @@ use crate::IntoArgs;
|
||||
#[derive(Debug)]
|
||||
pub enum QemuNic {
|
||||
VirtioPci { mac: Option<String> },
|
||||
Rtl8139 { mac: Option<String> },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@ -46,6 +47,15 @@ impl IntoArgs for QemuNic {
|
||||
}
|
||||
command.arg(val);
|
||||
}
|
||||
Self::Rtl8139 { mac } => {
|
||||
command.arg("-device");
|
||||
let mut val = "rtl8139,netdev=net0".to_owned();
|
||||
if let Some(mac) = mac {
|
||||
val.push_str(",mac=");
|
||||
val.push_str(mac);
|
||||
}
|
||||
command.arg(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,21 @@ use crate::{
|
||||
util::run_external_command,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
enum QemuNetworkInterface {
|
||||
#[default]
|
||||
VirtioNet,
|
||||
Rtl8139,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "kebab-case", default)]
|
||||
struct QemuNetworkConfig {
|
||||
enable: bool,
|
||||
interface_name: String,
|
||||
mac: String,
|
||||
interface: QemuNetworkInterface,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, serde::Deserialize, serde::Serialize)]
|
||||
@ -119,6 +128,7 @@ impl Default for QemuNetworkConfig {
|
||||
enable: true,
|
||||
interface_name: "qemu-tap0".into(),
|
||||
mac: "12:34:56:65:43:21".into(),
|
||||
interface: QemuNetworkInterface::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -307,10 +317,13 @@ fn add_devices_from_config(
|
||||
config: &QemuConfig,
|
||||
) -> Result<(), Error> {
|
||||
if config.network.enable {
|
||||
let mac = Some(config.network.mac.clone());
|
||||
let nic = match config.network.interface {
|
||||
QemuNetworkInterface::VirtioNet => QemuNic::VirtioPci { mac },
|
||||
QemuNetworkInterface::Rtl8139 => QemuNic::Rtl8139 { mac },
|
||||
};
|
||||
devices.push(QemuDevice::NetworkTap {
|
||||
nic: QemuNic::VirtioPci {
|
||||
mac: Some(config.network.mac.clone()),
|
||||
},
|
||||
nic,
|
||||
script: Some("xtask/scripts/qemu-ifup".into()),
|
||||
ifname: Some(config.network.interface_name.clone()),
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user