pci/dt: rework pci interrupts, add gicv2m and dt msi controllers

This commit is contained in:
Mark Poliakov 2025-02-05 21:45:48 +02:00
parent 01dbac2132
commit 7348232aa9
47 changed files with 783 additions and 342 deletions

View File

@ -30,8 +30,11 @@ ygg_driver_net_core = { path = "driver/net/core" }
ygg_driver_net_loopback = { path = "driver/net/loopback" }
ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] }
ygg_driver_virtio_gpu = { path = "driver/virtio/gpu", features = ["pci"] }
ygg_driver_nvme = { path = "driver/block/nvme" }
ygg_driver_ahci = { path = "driver/block/ahci" }
ygg_driver_input = { path = "driver/input" }
ygg_driver_usb_xhci.path = "driver/usb/xhci"
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
memfs = { path = "driver/fs/memfs" }
ext2 = { path = "driver/fs/ext2" }
@ -63,9 +66,6 @@ kernel-arch-x86_64.workspace = true
kernel-arch-x86.workspace = true
ygg_driver_acpi.path = "driver/acpi"
ygg_driver_usb_xhci.path = "driver/usb/xhci"
ygg_driver_nvme = { path = "driver/block/nvme" }
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
acpi.workspace = true
@ -89,8 +89,6 @@ kernel-arch-aarch64.workspace = true
kernel-arch-riscv64.workspace = true
ygg_driver_acpi.path = "driver/acpi"
ygg_driver_usb_xhci.path = "driver/usb/xhci"
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
[features]
default = ["fb_console"]

View File

@ -8,7 +8,7 @@ use core::sync::atomic::{AtomicUsize, Ordering};
use aarch64_cpu::registers::{DAIF, MPIDR_EL1, TPIDR_EL1};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use device_api::interrupt::LocalInterruptController;
use kernel_arch_interface::{
cpu::{CpuData, CpuImpl, IpiQueue},
guard::IrqGuard,
@ -123,24 +123,10 @@ impl Architecture for ArchitectureImpl {
CPU_COUNT.load(Ordering::Acquire)
}
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
None
}
fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
None
}
// fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
// let local = Self::local_cpu_data()?;
// let intc = *local.gic.try_get()?;
// Some(intc)
// }
// fn message_interrupt_controller() -> &'static dyn MessageInterruptController {
// todo!()
// }
fn cpu_available_features<S: Scheduler>(_cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
None
}

View File

@ -4,7 +4,7 @@
use alloc::vec::Vec;
use cpu::{CpuData, CpuFeatureSet, CpuImpl, IpiQueue};
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use device_api::interrupt::LocalInterruptController;
use task::Scheduler;
extern crate alloc;
@ -72,10 +72,6 @@ pub trait Architecture: Sized + 'static {
None
}
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
None
}
#[allow(unused)]
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
None

View File

@ -6,7 +6,7 @@ extern crate alloc;
use core::sync::atomic::{AtomicUsize, Ordering};
use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec};
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use device_api::interrupt::LocalInterruptController;
use kernel_arch_interface::{
cpu::{CpuData, CpuImpl, IpiQueue},
sync::IrqSafeSpinlock,
@ -160,10 +160,6 @@ impl Architecture for ArchitectureImpl {
todo!()
}
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
todo!()
}
fn idle_task() -> extern "C" fn(usize) -> ! {
idle_task
}

View File

@ -9,7 +9,7 @@ use core::{
sync::atomic::{AtomicUsize, Ordering},
};
use alloc::{boxed::Box, vec::Vec};
use alloc::{sync::Arc, vec::Vec};
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use kernel_arch_interface::{
cpu::{CpuData, CpuImpl, IpiQueue},
@ -52,8 +52,7 @@ pub struct PerCpuData {
// 0x10, used in assembly
pub tmp_address: usize,
pub local_apic: Box<dyn LocalApicInterface>,
// pub local_apic: &'static dyn LocalApicInterface,
pub local_apic: Arc<dyn LocalApicInterface>,
pub available_features: CpuFeatures,
pub enabled_features: CpuFeatures,
}
@ -189,11 +188,6 @@ impl Architecture for ArchitectureImpl {
Some(cpu.local_apic.as_ref())
}
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
let cpu = Self::local_cpu_data()?;
Some(cpu.local_apic.as_ref())
}
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.enabled_features)
}

View File

@ -5,7 +5,7 @@ use acpi_system::AcpiSystemError;
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::{intrinsics, ISA_IRQ_OFFSET};
use libk::device::external_interrupt_controller;
@ -157,7 +157,7 @@ impl rsdp::handler::AcpiHandler for AcpiHandlerImpl {
}
impl InterruptHandler for SciHandler {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
log::trace!("ACPI SCI received");
ACPI_SYSTEM.get().lock().handle_sci();
true

View File

@ -9,7 +9,7 @@ use bytemuck::Zeroable;
use data::ReceivedFis;
use device_api::{
device::Device,
interrupt::{InterruptAffinity, InterruptHandler},
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
};
use error::AhciError;
use libk::{device::manager::probe_partitions, fs::devfs, task::runtime};
@ -159,7 +159,7 @@ impl AhciController {
}
impl InterruptHandler for AhciController {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let regs = self.regs.lock();
let is = regs.IS.get();

View File

@ -5,6 +5,7 @@ use super::queue::CommandError;
#[derive(Debug)]
pub enum NvmeError {
InitError(Error),
InvalidBuffer(PhysicalAddress, usize),
RequestTooLarge(usize),
MemoryError(Error),
@ -20,6 +21,7 @@ impl From<CommandError> for NvmeError {
impl From<NvmeError> for Error {
fn from(value: NvmeError) -> Self {
match value {
NvmeError::InitError(error) => error,
NvmeError::RequestTooLarge(_) => Error::InvalidArgument,
NvmeError::InvalidBuffer(_, _) => Error::InvalidArgument,
NvmeError::MemoryError(err) => err,

View File

@ -16,7 +16,7 @@ use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
use command::{IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest};
use device_api::{
device::Device,
interrupt::{InterruptAffinity, InterruptHandler},
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
};
use drive::NvmeNamespace;
use libk::{
@ -222,7 +222,7 @@ impl NvmeController {
let range = self
.pci
.map_interrupt_multiple(0..io_queue_count + 1, InterruptAffinity::Any, self.clone())
.unwrap();
.map_err(NvmeError::InitError)?;
// TODO handle different MSI range allocations
for (i, msi) in range.iter().enumerate() {
@ -327,8 +327,10 @@ impl NvmeController {
}
impl InterruptHandler for NvmeController {
fn handle_irq(self: Arc<Self>, vector: Option<usize>) -> bool {
let vector = vector.expect("Only MSI-X interrupts are supported");
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
let IrqVector::Msi(vector) = vector else {
unreachable!("Only MSI-x interrupts are supported for NVMe");
};
if vector == 0 {
self.admin_q.get().process_completions() != 0

View File

@ -489,11 +489,11 @@ impl MsiXVectorTable<'_> {
}
}
pub fn register_range<C: MessageInterruptController + ?Sized>(
pub fn register_range(
&mut self,
start: usize,
end: usize,
ic: &C,
ic: &Arc<dyn MessageInterruptController>,
affinity: InterruptAffinity,
handler: Arc<dyn InterruptHandler>,
) -> Result<Vec<MsiInfo>, Error> {
@ -505,7 +505,7 @@ impl MsiXVectorTable<'_> {
};
end - start
];
ic.register_msi_range(&mut range, handler)?;
ic.clone().register_msi_range(&mut range, handler)?;
for (i, info) in range.iter().enumerate() {
let index = i + start;
@ -519,13 +519,13 @@ impl MsiXVectorTable<'_> {
}
impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiData<'s, S> {
pub fn register<C: MessageInterruptController + ?Sized>(
pub fn register(
&mut self,
ic: &C,
ic: &Arc<dyn MessageInterruptController>,
affinity: InterruptAffinity,
handler: Arc<dyn InterruptHandler>,
) -> Result<MsiInfo, Error> {
let info = ic.register_msi(affinity, handler)?;
let info = ic.clone().register_msi(affinity, handler)?;
let mut w0 = self.space.read_u16(self.offset + 2);
// Enable the vector first

View File

@ -3,9 +3,12 @@ use core::ops::Range;
use alloc::{sync::Arc, vec::Vec};
use device_api::{
device::Device,
interrupt::{InterruptAffinity, InterruptHandler, IrqOptions, MsiInfo},
interrupt::{
ExternalInterruptController, InterruptAffinity, InterruptHandler, Irq, IrqOptions,
MessageInterruptController, MsiInfo,
},
};
use libk::device::{message_interrupt_controller, register_global_interrupt};
use libk::device::external_interrupt_controller;
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use yggdrasil_abi::error::Error;
@ -58,11 +61,14 @@ pub enum PreferredInterruptMode {
}
enum ConfiguredInterruptMode {
MsiX(MsiXVectorTable<'static>),
Msi,
LegacyPin(PciInterruptPin),
MsiX(
Arc<dyn MessageInterruptController>,
MsiXVectorTable<'static>,
),
Msi(Arc<dyn MessageInterruptController>),
LegacyPin(Arc<dyn ExternalInterruptController>, PciInterruptPin),
#[cfg_attr(not(target_arch = "x86"), allow(unused))]
LegacyLine(u8),
LegacyLine(Arc<dyn ExternalInterruptController>, u8),
None,
}
@ -78,6 +84,12 @@ pub struct PciInterruptRoute {
pub options: IrqOptions,
}
#[derive(Clone)]
pub struct PciMsiRoute {
// TODO `msi-base`
pub controller: Arc<dyn MessageInterruptController>,
}
/// Used to store PCI bus devices which were enumerated by the kernel
pub struct PciBusDevice {
pub(crate) info: PciDeviceInfo,
@ -123,10 +135,10 @@ impl PciDeviceInfo {
pub fn init_interrupts(&self, preferred_mode: PreferredInterruptMode) -> Result<(), Error> {
self.interrupt_config
.try_init_with(|| {
let configured_mode = if self.segment.has_msi
&& let PreferredInterruptMode::Msi(want_msix) = preferred_mode
let configured_mode = if let PreferredInterruptMode::Msi(want_msix) = preferred_mode
&& let Some(msi_route) = self.segment.msi_translation_map.map_msi(self.address)
{
// Try MSI-X first
// Try to setup MSI (or MSI-x, if requested)
let mut result = None;
if want_msix
&& let Some(mut msix) = self.config_space.capability::<MsiXCapability>()
@ -137,46 +149,55 @@ impl PciDeviceInfo {
msix.set_function_mask(false);
msix.set_enabled(true);
result = Some(ConfiguredInterruptMode::MsiX(vt));
result = Some(ConfiguredInterruptMode::MsiX(
msi_route.controller.clone(),
vt,
));
}
}
// Then try MSI
// Fall back to MSI if MSI-x is not available or not requested
if result.is_none() && self.config_space.capability::<MsiCapability>().is_some()
{
result = Some(ConfiguredInterruptMode::Msi)
result = Some(ConfiguredInterruptMode::Msi(msi_route.controller));
}
// And then fall back to legacy
// Fall back to legacy IRQ if nothing else works
if let Some(result) = result {
result
} else {
self.legacy_interrupt_mode()
}
} else {
// Ignore preferred_mode, the only supported is Legacy
// MSI not requested or segment does not have MSI functionality
self.legacy_interrupt_mode()
};
IrqSafeRwLock::new(InterruptConfig {
preferred_mode,
configured_mode,
})
})
.expect("Attempted to double-configure interrupts for a PCI device");
.expect("Possible bug: double-initialization of PCI(e) interrupt config");
Ok(())
}
fn legacy_interrupt_mode(&self) -> ConfiguredInterruptMode {
let Ok(intc) = external_interrupt_controller() else {
return ConfiguredInterruptMode::None;
};
// TODO this should be retrieved from interrupt map
#[cfg(any(target_arch = "x86", rust_analyzer))]
{
if let Some(irq) = self.config_space.interrupt_line() {
return ConfiguredInterruptMode::LegacyLine(irq);
return ConfiguredInterruptMode::LegacyLine(intc.clone(), irq);
}
}
match self.config_space.interrupt_pin() {
Some(pin) => ConfiguredInterruptMode::LegacyPin(pin),
Some(pin) => ConfiguredInterruptMode::LegacyPin(intc.clone(), pin),
None => ConfiguredInterruptMode::None,
}
}
@ -189,27 +210,26 @@ impl PciDeviceInfo {
let mut irq = self.interrupt_config.get().write();
match &mut irq.configured_mode {
ConfiguredInterruptMode::MsiX(msix) => {
let info =
msix.register_range(0, 1, message_interrupt_controller()?, affinity, handler)?;
Ok(Some(info[0]))
}
ConfiguredInterruptMode::Msi => {
ConfiguredInterruptMode::Msi(controller) => {
let mut msi = self
.config_space
.capability::<MsiCapability>()
.ok_or(Error::InvalidOperation)?;
let info = msi.register(message_interrupt_controller()?, affinity, handler)?;
let info = msi.register(controller, affinity, handler)?;
Ok(Some(info))
}
ConfiguredInterruptMode::LegacyPin(pin) => {
self.try_map_legacy(*pin, handler)?;
ConfiguredInterruptMode::MsiX(controller, msix) => {
let info = msix.register_range(0, 1, controller, affinity, handler)?;
Ok(Some(info[0]))
}
ConfiguredInterruptMode::LegacyPin(intc, pin) => {
self.try_map_legacy(intc.as_ref(), *pin, handler)?;
Ok(None)
}
ConfiguredInterruptMode::LegacyLine(irq) => {
self.try_map_legacy_line(*irq, handler)?;
ConfiguredInterruptMode::LegacyLine(intc, irq) => {
self.try_map_legacy_line(intc.as_ref(), *irq, handler)?;
Ok(None)
}
ConfiguredInterruptMode::None => Err(Error::InvalidOperation),
@ -227,19 +247,16 @@ impl PciDeviceInfo {
let end = vector_range.end;
match &mut irq.configured_mode {
ConfiguredInterruptMode::MsiX(msix) => msix.register_range(
start,
end,
message_interrupt_controller()?,
affinity,
handler,
),
ConfiguredInterruptMode::MsiX(controller, msix) => {
msix.register_range(start, end, controller, affinity, handler)
}
_ => Err(Error::InvalidOperation),
}
}
fn try_map_legacy(
&self,
intc: &dyn ExternalInterruptController,
pin: PciInterruptPin,
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
@ -260,17 +277,22 @@ impl PciDeviceInfo {
route.number
);
register_global_interrupt(route.number, route.options, handler)
let irq = Irq::External(route.number);
intc.register_irq(irq, route.options, handler)?;
intc.enable_irq(irq)
}
fn try_map_legacy_line(
&self,
intc: &dyn ExternalInterruptController,
line: u8,
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
log::debug!("PCI {} -> IRQ#{}", self.address, line);
register_global_interrupt(line as _, Default::default(), handler)
let irq = Irq::External(line as u32);
intc.register_irq(irq, Default::default(), handler)?;
intc.enable_irq(irq)
}
}

View File

@ -1,7 +1,13 @@
use alloc::collections::btree_map::BTreeMap;
use core::fmt;
use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
use device_api::interrupt::MessageInterruptController;
use libk::error::Error;
use crate::device::{PciInterrupt, PciInterruptRoute};
use crate::{
device::{PciInterrupt, PciInterruptRoute, PciMsiRoute},
PciAddress,
};
#[derive(Debug)]
pub enum PciInterruptMap {
@ -11,6 +17,24 @@ pub enum PciInterruptMap {
Legacy,
}
// TODO device-tree also provides a "msi-base" value, which is ignored and assumed to be zero for
// now
pub struct PciFixedMsiMapping {
pub start_address: PciAddress,
pub end_address: PciAddress,
pub controller: Arc<dyn MessageInterruptController>,
}
pub struct PciFixedMsiMap {
pub entries: Vec<PciFixedMsiMapping>,
}
pub enum PciMsiMap {
Fixed(PciFixedMsiMap),
Identity(Arc<dyn MessageInterruptController>),
Legacy,
}
impl PciInterruptMap {
pub fn map_interrupt(&self, interrupt: &PciInterrupt) -> Result<PciInterruptRoute, Error> {
match self {
@ -61,3 +85,57 @@ impl PciInterruptMap {
}
}
}
impl PciMsiMap {
pub fn map_msi(&self, address: PciAddress) -> Option<PciMsiRoute> {
match self {
Self::Fixed(map) => map.map_msi(address),
Self::Identity(controller) => Some(PciMsiRoute {
controller: controller.clone(),
}),
Self::Legacy => None,
}
}
}
impl fmt::Debug for PciMsiMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Legacy => f.debug_struct("Legacy").finish(),
Self::Fixed(map) => f
.debug_struct("Fixed")
.field("entries", &map.entries)
.finish(),
Self::Identity(_) => f.debug_struct("Identity").finish(),
}
}
}
impl PciFixedMsiMap {
pub fn map_msi(&self, address: PciAddress) -> Option<PciMsiRoute> {
for entry in self.entries.iter() {
if entry.contains(address) {
let route = PciMsiRoute {
controller: entry.controller.clone(),
};
return Some(route);
}
}
None
}
}
impl PciFixedMsiMapping {
pub fn contains(&self, address: PciAddress) -> bool {
self.start_address <= address && self.end_address > address
}
}
impl fmt::Debug for PciFixedMsiMapping {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PciFixedMsiMapping")
.field("start_address", &self.start_address)
.field("end_address", &self.end_address)
.finish()
}
}

View File

@ -13,13 +13,16 @@ use alloc::{format, sync::Arc, vec::Vec};
use bitflags::bitflags;
use device::{PciBusDevice, PciDeviceInfo};
use interrupt::PciInterruptMap;
use interrupt::{PciInterruptMap, PciMsiMap};
use libk::fs::sysfs::{self, object::KObject};
use libk_mm::address::PhysicalAddress;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use space::legacy;
use yggdrasil_abi::{error::Error, primitive_enum};
#[cfg(target_arch = "x86_64")]
use device_api::interrupt::MessageInterruptController;
pub mod capability;
pub mod device;
pub mod driver;
@ -124,6 +127,45 @@ struct BusAddressAllocator {
offset_32: u32,
}
#[derive(Debug)]
pub struct PciSegmentInfo {
pub segment_number: u8,
pub bus_number_start: u8,
pub bus_number_end: u8,
pub ecam_phys_base: Option<PhysicalAddress>,
pub irq_translation_map: PciInterruptMap,
pub msi_translation_map: PciMsiMap,
}
/// Represents a single PCIe bus segment
pub struct PciBusSegment {
allocator: Option<BusAddressAllocator>,
info: Arc<PciSegmentInfo>,
devices: Vec<Arc<KObject<IrqSafeSpinlock<PciBusDevice>>>>,
}
#[derive(Debug)]
pub enum PciRangeType {
Configuration,
Io,
Memory32,
Memory64,
}
pub struct PciAddressRange {
pub ty: PciRangeType,
pub bus_number: u8,
pub pci_base: u64,
pub host_base: PhysicalAddress,
pub size: usize,
}
/// Manager struct to store and control all PCI devices in the system
pub struct PciBusManager {
segments: Vec<PciBusSegment>,
}
#[cfg_attr(
any(target_arch = "x86_64", target_arch = "x86", target_arch = "riscv64"),
allow(dead_code)
@ -195,45 +237,6 @@ impl BusAddressAllocator {
}
}
#[derive(Debug)]
pub struct PciSegmentInfo {
pub segment_number: u8,
pub bus_number_start: u8,
pub bus_number_end: u8,
pub ecam_phys_base: Option<PhysicalAddress>,
pub irq_translation_map: PciInterruptMap,
pub has_msi: bool,
}
/// Represents a single PCIe bus segment
pub struct PciBusSegment {
allocator: Option<BusAddressAllocator>,
info: Arc<PciSegmentInfo>,
devices: Vec<Arc<KObject<IrqSafeSpinlock<PciBusDevice>>>>,
}
#[derive(Debug)]
pub enum PciRangeType {
Configuration,
Io,
Memory32,
Memory64,
}
pub struct PciAddressRange {
pub ty: PciRangeType,
pub bus_number: u8,
pub pci_base: u64,
pub host_base: PhysicalAddress,
pub size: usize,
}
/// Manager struct to store and control all PCI devices in the system
pub struct PciBusManager {
segments: Vec<PciBusSegment>,
}
impl PciBaseAddress {
pub fn as_memory(self) -> Option<PhysicalAddress> {
match self {
@ -416,6 +419,12 @@ impl PciBusSegment {
}
}
impl PciSegmentInfo {
pub fn has_msi(&self) -> bool {
!matches!(self.msi_translation_map, PciMsiMap::Legacy)
}
}
impl PciBusManager {
const fn new() -> Self {
Self {
@ -463,7 +472,7 @@ impl PciBusManager {
bus_number_end: 255,
ecam_phys_base: None,
irq_translation_map: PciInterruptMap::Legacy,
has_msi: false,
msi_translation_map: PciMsiMap::Legacy,
}),
allocator: None,
devices: Vec::new(),
@ -478,7 +487,12 @@ impl PciBusManager {
/// Enumerates a bus segment provided by ACPI MCFG table entry
#[cfg(target_arch = "x86_64")]
pub fn add_segment_from_mcfg(entry: &McfgEntry) -> Result<(), Error> {
pub fn add_segment_from_mcfg(
entry: &McfgEntry,
msi_controller: Arc<dyn MessageInterruptController>,
) -> Result<(), Error> {
let msi_translation_map = PciMsiMap::Identity(msi_controller);
let mut bus_segment = PciBusSegment {
info: Arc::new(PciSegmentInfo {
segment_number: entry.pci_segment_group as u8,
@ -488,7 +502,7 @@ impl PciBusManager {
// TODO get the segment's PCI root bridge AML name
irq_translation_map: PciInterruptMap::Acpi("\\_SB.PCI0._PRT".into()),
has_msi: true,
msi_translation_map,
}),
// Firmware done this for us
allocator: None,
@ -508,7 +522,8 @@ impl PciBusManager {
cfg_base: PhysicalAddress,
bus_range: core::ops::Range<u8>,
ranges: Vec<PciAddressRange>,
interrupt_map: PciInterruptMap,
irq_translation_map: PciInterruptMap,
msi_translation_map: PciMsiMap,
) -> Result<(), Error> {
let mut bus_segment = PciBusSegment {
info: Arc::new(PciSegmentInfo {
@ -517,8 +532,8 @@ impl PciBusManager {
bus_number_end: bus_range.end,
ecam_phys_base: Some(cfg_base),
irq_translation_map: interrupt_map,
has_msi: false,
irq_translation_map,
msi_translation_map,
}),
allocator: Some(BusAddressAllocator::from_ranges(&ranges)),

View File

@ -156,7 +156,7 @@ impl UsbDriver for UsbHidKeyboardDriver {
let events = unsafe { MaybeUninit::slice_assume_init_ref(&events[..event_count]) };
for &event in events {
log::info!("Generic Keyboard: {:?}", event);
log::trace!("Generic Keyboard: {:?}", event);
ygg_driver_input::send_event(event);
}
}

View File

@ -1,7 +1,10 @@
use core::mem::MaybeUninit;
use alloc::sync::Arc;
use device_api::{device::Device, interrupt::InterruptHandler};
use device_api::{
device::Device,
interrupt::{InterruptHandler, IrqVector},
};
use libk::error::Error;
use libk_mm::{
address::{AsPhysicalAddress, PhysicalAddress},
@ -280,7 +283,7 @@ impl Rtl8139 {
}
impl InterruptHandler for Rtl8139 {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let regs = self.regs.lock();
let status = regs.ISR.extract();
// Clear ISR bits

View File

@ -4,7 +4,10 @@ use core::{
};
use alloc::{sync::Arc, vec::Vec};
use device_api::{device::Device, interrupt::InterruptHandler};
use device_api::{
device::Device,
interrupt::{InterruptHandler, IrqVector},
};
use libk::error::Error;
use libk_mm::{
address::{AsPhysicalAddress, PhysicalAddress},
@ -255,7 +258,6 @@ impl RxRing {
},
capacity,
)?;
unsafe { core::arch::asm!("wbinvd") };
Ok(Self {
entries,
buffers,
@ -388,7 +390,6 @@ impl Descriptor {
self.vlan_cmd = 0;
unsafe {
atomic::fence(Ordering::Release);
core::arch::asm!("wbinvd");
core::ptr::write_volatile(&mut self.cmd, cmd | Self::CMD_OWN);
}
}
@ -400,7 +401,6 @@ impl Descriptor {
self.vlan_cmd = 0;
unsafe {
atomic::fence(Ordering::Release);
core::arch::asm!("wbinvd");
core::ptr::write_volatile(&mut self.cmd, cmd);
}
}
@ -545,7 +545,7 @@ impl Rtl8168 {
}
impl InterruptHandler for Rtl8168 {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let regs = self.regs.lock();
let status = regs.ISR.extract();
@ -637,8 +637,6 @@ impl Device for Rtl8168 {
log::info!("rx_ring_base = {rx_ring_base:#x}");
unsafe { core::arch::asm!("wbinvd") };
// Setup Tx
regs.TCR.modify(TCR::MXDMA::Unlimited);
// Setup Rx

View File

@ -2,7 +2,10 @@ use core::sync::atomic::{AtomicU8, Ordering};
use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
use async_trait::async_trait;
use device_api::{device::Device, interrupt::InterruptHandler};
use device_api::{
device::Device,
interrupt::{InterruptHandler, IrqVector},
};
use libk::{error::Error, task::runtime};
use libk_mm::{
address::{AsPhysicalAddress, PhysicalAddress},
@ -480,7 +483,7 @@ impl Device for Xhci {
}
impl InterruptHandler for Xhci {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let status = self.regs.handle_interrupt(0);
if status.matches_all(USBSTS::HSE::SET) {

View File

@ -25,7 +25,6 @@ mod ring;
mod util;
// Only x86-64 supports xHCI currently, because only it has MSI-X implemented
#[cfg(target_arch = "x86_64")]
pci_driver! {
matches: [class (0x0C:0x03:0x30)],
driver: {

View File

@ -9,7 +9,7 @@ use alloc::{collections::BTreeMap, sync::Arc};
use bytemuck::{Pod, Zeroable};
use device_api::{
device::Device,
interrupt::{InterruptAffinity, InterruptHandler},
interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
};
use libk_mm::PageBox;
use libk_util::{
@ -34,9 +34,6 @@ use yggdrasil_abi::{error::Error, net::MacAddress};
struct Queues {
receive: IrqSafeSpinlock<VirtQueue>,
transmit: IrqSafeSpinlock<VirtQueue>,
// #[allow(unused)]
// configuration_vector: usize,
receive_vector: Option<u16>,
}
pub struct VirtioNet<T: Transport> {
@ -202,7 +199,6 @@ impl<T: Transport + 'static> VirtioNet<T> {
self.queues.init(Queues {
receive: IrqSafeSpinlock::new(rx),
transmit: IrqSafeSpinlock::new(tx),
receive_vector,
});
Ok(())
@ -232,39 +228,26 @@ impl<T: Transport + 'static> NetworkDevice for VirtioNet<T> {
}
impl<T: Transport + 'static> InterruptHandler for VirtioNet<T> {
fn handle_irq(self: Arc<Self>, vector: Option<usize>) -> bool {
#[allow(clippy::redundant_pattern_matching)]
if let Some(_) = vector {
// MSI/MSI-X
let Some(queues) = self.queues.try_get() else {
return false;
};
if vector == queues.receive_vector.map(Into::into) {
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
match vector {
IrqVector::Msi(_) => {
// MSI/MSI-X
self.handle_receive_interrupt(0)
} else {
false
}
} else {
// Legacy IRQ
let (queue_irq, config_irq) = self.transport.lock().read_interrupt_status();
IrqVector::Irq(_) => {
// Legacy IRQ
let (queue_irq, config_irq) = self.transport.lock().read_interrupt_status();
if queue_irq {
self.handle_receive_interrupt(0);
if queue_irq {
self.handle_receive_interrupt(0);
}
queue_irq || config_irq
}
queue_irq || config_irq
}
}
}
// impl<T: Transport + 'static> MsiHandler for VirtioNet<T> {
// fn handle_msi(&self, vector: usize) -> bool {
//
// todo!()
// }
// }
impl<T: Transport + 'static> Device for VirtioNet<T> {
fn display_name(&self) -> &str {
"VirtIO Network Device"

View File

@ -61,6 +61,12 @@ pub enum InterruptAffinity {
Specific(usize),
}
#[derive(Clone, Copy, Debug)]
pub enum IrqVector {
Msi(usize),
Irq(Irq),
}
/// Describes messages sent from some CPU to others
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u64)]
@ -73,7 +79,7 @@ pub enum IpiMessage {
}
pub trait InterruptHandler: Device {
fn handle_irq(self: Arc<Self>, vector: Option<usize>) -> bool;
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool;
}
pub trait InterruptTable: Sync {
@ -107,9 +113,9 @@ pub trait ExternalInterruptController: Device {
}
}
pub trait MessageInterruptController {
pub trait MessageInterruptController: Device {
fn register_msi(
&self,
self: Arc<Self>,
affinity: InterruptAffinity,
handler: Arc<dyn InterruptHandler>,
) -> Result<MsiInfo, Error> {
@ -123,7 +129,7 @@ pub trait MessageInterruptController {
#[allow(unused)]
fn register_msi_range(
&self,
self: Arc<Self>,
range: &mut [MsiInfo],
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {

View File

@ -7,16 +7,6 @@ use crate::TProp;
use super::{lookup_phandle, Node};
/// Looks up an `interrupt-controller` node by its phandle with lazy probe.
pub fn interrupt_controller(phandle: Phandle) -> Option<Arc<Node>> {
lookup_phandle(phandle, true)
}
/// Looks up a clock controller by its phandle with lazy probe.
pub fn clock_controller(phandle: Phandle) -> Option<Arc<Node>> {
lookup_phandle(phandle, true)
}
// Interrupt controller handling
/// Reads interrupt information, as interpreted by `interrupt_controller`, from `property` at a
@ -33,7 +23,7 @@ pub fn map_interrupt_at(
/// Same as [map_interrupt_at], but uses a phandle to address the `interrupt-controller` node
/// and a scaled `index`.
pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option<FullIrq> {
let interrupt_controller = interrupt_controller(phandle)?;
let interrupt_controller = lookup_phandle(phandle, true)?;
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
map_interrupt_at(&interrupt_controller, property, index * interrupt_cells)
}

View File

@ -11,7 +11,7 @@ mod tree;
pub mod util;
pub use controller::{interrupt_controller, map_interrupt, map_interrupt_at};
pub use controller::{map_interrupt, map_interrupt_at};
pub use macros::device_tree_driver;
pub use registry::{lookup_phandle, register_driver};
pub use traits::{DeviceTreeInterruptController, Driver, ProbeContext};

View File

@ -2,7 +2,11 @@
use core::ops::Range;
use alloc::sync::{Arc, Weak};
use device_api::{bus::Bus, device::Device, interrupt::FullIrq};
use device_api::{
bus::Bus,
device::Device,
interrupt::{ExternalInterruptController, FullIrq},
};
use crate::TProp;
@ -19,6 +23,9 @@ pub trait DeviceTreeInterruptController {
/// Reads interrupt information from `property` at given `offset` and maps it to
/// the interrupt used by the controller
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq>;
/// Returns the [ExternalInterruptController] implementor of this node
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController>;
}
/// Context passed to the driver's `probe` function

View File

@ -5,7 +5,12 @@ use alloc::{
sync::{Arc, Weak},
vec::Vec,
};
use device_api::{bus::Bus, clock::ClockController, device::Device, interrupt::FullIrq};
use device_api::{
bus::Bus,
clock::ClockController,
device::Device,
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
};
use fdt_rs::spec::Phandle;
use libk_mm::address::PhysicalAddress;
use libk_util::OneTimeInit;
@ -42,6 +47,7 @@ pub struct Node {
device: OneTimeInit<NodeDevice>,
init_token: OneTimeInit<()>,
pub(crate) interrupt_controller: OneTimeInit<Arc<dyn DeviceTreeInterruptController>>,
pub(crate) msi_controller: OneTimeInit<Arc<dyn MessageInterruptController>>,
}
enum NodeDevice {
@ -157,6 +163,12 @@ impl Node {
self.interrupt_controller.init(intc);
}
/// When called from an msi-controller driver, informs the node of its capability as an MSI
/// controller.
pub fn make_msi_controller(&self, intc: Arc<dyn MessageInterruptController>) {
self.msi_controller.init(intc);
}
/// Returns the device driver associated with this node, if any was probed.
pub fn driver(&self) -> Option<&'static dyn Driver> {
self.device.try_get()?.driver()
@ -290,6 +302,13 @@ impl Node {
device.as_device()?.as_clock_controller()
}
/// Attempts to get an interrupt controller represented by this node, if any
pub fn as_interrupt_controller(&self) -> Option<Arc<dyn ExternalInterruptController>> {
self.interrupt_controller
.try_get()
.map(|e| e.clone().as_interrupt_controller())
}
/// Returns the `#address-cells` value of the node's parent bus
pub fn bus_address_cells(&self) -> usize {
self.bus_address_cells
@ -368,6 +387,7 @@ fn unflatten_node(
device: OneTimeInit::new(),
init_token: OneTimeInit::new(),
interrupt_controller: OneTimeInit::new(),
msi_controller: OneTimeInit::new(),
});
if let Some(phandle) = phandle {

View File

@ -1,7 +1,7 @@
//! General helpers and utilities for device tree drivers
use alloc::sync::Arc;
use device_api::interrupt::FullIrq;
use device_api::interrupt::{FullIrq, MessageInterruptController};
use crate::{
driver::{lookup_phandle, map_interrupt_at},
@ -27,6 +27,22 @@ pub struct PcieInterruptEntry {
pub irq: FullIrq,
}
/// Represents a single PCI address (Requester ID for a MSI(-x))
#[derive(Debug)]
pub struct PcieMsiRequesterId(u32);
/// Represents an entry in a PCIe-controller's `msi-map` field
pub struct PcieMsiEntry {
/// Base requester ID
pub base_rid: PcieMsiRequesterId,
/// Number of consecutive Requester IDs this entry describes
pub length: u32,
/// MSI controller this entry maps to
pub msi_controller: Arc<dyn MessageInterruptController>,
/// Base vector this entry translates to in the MSI controller
pub msi_base: u32,
}
/// An iterator over a generic PCIe interrupt map
pub struct PcieInterruptMapIter<'a> {
interrupt_map: TProp<'a>,
@ -34,6 +50,12 @@ pub struct PcieInterruptMapIter<'a> {
child_address_cells: usize,
}
/// An iterator over a generic PCIe MSI map
pub struct PcieMsiMapIter<'a> {
msi_map: TProp<'a>,
offset: usize,
}
impl Iterator for PcieInterruptMapIter<'_> {
type Item = PcieInterruptEntry;
@ -88,6 +110,56 @@ impl Iterator for PcieInterruptMapIter<'_> {
}
}
impl Iterator for PcieMsiMapIter<'_> {
type Item = PcieMsiEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.msi_map.len() {
return None;
}
// Each entry is 4 cells:
//
// * Requester ID (PCI address) base
// * msi-controller node phandle
// * msi-base
// * Number of consecutive Requester ID for this entry
let (base_rid, phandle, msi_base, length) =
self.msi_map.read_cells_at(self.offset, (1, 1, 1, 1))?;
let base_rid = PcieMsiRequesterId(base_rid as u32);
let msi_controller = lookup_phandle(phandle as u32, true)?;
let msi_controller = msi_controller.msi_controller.try_get()?.clone();
let msi_base = msi_base as u32;
let length = length as u32;
self.offset += 4;
Some(PcieMsiEntry {
base_rid,
msi_base,
msi_controller,
length,
})
}
}
impl PcieMsiRequesterId {
/// Splits the struct into bus:device:function parts
pub fn as_parts(&self) -> (u8, u8, u8) {
let bus = (self.0 >> 8) as u8;
let device = ((self.0 >> 3) & 0x1F) as u8;
let function = (self.0 & 0xF) as u8;
(bus, device, function)
}
/// Applies an offset to this requester ID, returning the result
pub fn offset(&self, offset: u32) -> Self {
Self(self.0 + offset - 1)
}
}
/// Returns an iterator over the PCIe-controller's `interrupt-map`
pub fn pcie_interrupt_map(node: &Arc<Node>) -> Option<PcieInterruptMapIter<'static>> {
let interrupt_map = node.property("interrupt-map")?;
@ -99,3 +171,9 @@ pub fn pcie_interrupt_map(node: &Arc<Node>) -> Option<PcieInterruptMapIter<'stat
offset: 0,
})
}
/// Returns an iterator over the PCIe-controller's `msi-map`
pub fn pcie_msi_map(node: &Arc<Node>) -> Option<PcieMsiMapIter<'static>> {
let msi_map = node.property("msi-map")?;
Some(PcieMsiMapIter { msi_map, offset: 0 })
}

View File

@ -1,13 +1,6 @@
// pub mod display;
// pub use libk_device::*;
use alloc::sync::Arc;
use device_api::interrupt::{
ExternalInterruptController, InterruptHandler, Irq, IrqOptions, MessageInterruptController,
};
use kernel_arch::{Architecture, ArchitectureImpl};
use device_api::interrupt::ExternalInterruptController;
use libk_util::OneTimeInit;
use yggdrasil_abi::error::Error;
@ -16,6 +9,7 @@ pub mod char;
pub mod display;
pub mod manager;
// TODO get rid of this, this does not work when there are multiple interrupt controllers
// Interrupt controllers don't disappear (or at least in my OS), so it's okay to keep a reference
// inside a static OneTimeInit.
static EXTERNAL_INTC: OneTimeInit<Arc<dyn ExternalInterruptController>> = OneTimeInit::new();
@ -28,23 +22,3 @@ pub fn external_interrupt_controller(
) -> Result<&'static Arc<dyn ExternalInterruptController>, Error> {
EXTERNAL_INTC.try_get().ok_or(Error::DoesNotExist)
}
pub fn message_interrupt_controller() -> Result<&'static dyn MessageInterruptController, Error> {
ArchitectureImpl::message_interrupt_controller().ok_or(Error::DoesNotExist)
}
#[inline]
pub fn register_global_interrupt(
irq: u32,
options: IrqOptions,
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
let irq = Irq::External(irq);
intc.register_irq(irq, options, handler)?;
intc.enable_irq(irq)?;
Ok(())
}

View File

@ -9,7 +9,8 @@ use tock_registers::{
register_bitfields! {
u32,
CTLR [
Enable OFFSET(0) NUMBITS(1) []
EnableGrp0 OFFSET(0) NUMBITS(1) [],
EnableGrp1 OFFSET(1) NUMBITS(1) [],
],
PMR [
Priority OFFSET(0) NUMBITS(8) []
@ -45,7 +46,9 @@ impl Gicc {
pub unsafe fn init(&self) {
log::debug!("Enabling GICv2 GICC");
self.regs.CTLR.write(CTLR::Enable::SET);
self.regs
.CTLR
.write(CTLR::EnableGrp0::SET + CTLR::EnableGrp1::SET);
self.regs.PMR.write(PMR::Priority.val(0xFF));
}

View File

@ -1,5 +1,5 @@
//! ARM GICv2 Distributor registers
use device_api::interrupt::{IpiDeliveryTarget, IrqLevel, IrqOptions, IrqTrigger};
use device_api::interrupt::{IpiDeliveryTarget, IrqOptions, IrqTrigger};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::Spinlock;
use tock_registers::{
@ -11,7 +11,9 @@ use tock_registers::{
register_bitfields! {
u32,
CTLR [
Enable OFFSET(0) NUMBITS(1) []
EnableGrp0 OFFSET(0) NUMBITS(1) [],
EnableGrp1NS OFFSET(1) NUMBITS(1) [],
ARE_NS OFFSET(5) NUMBITS(1) [],
],
TYPER [
ITLinesNumber OFFSET(0) NUMBITS(5) []
@ -39,8 +41,14 @@ register_structs! {
(0x000 => CTLR: ReadWrite<u32, CTLR::Register>),
(0x004 => TYPER: ReadWrite<u32, TYPER::Register>),
(0x008 => _0),
(0x040 => SETSPI_NSR: WriteOnly<u32>),
(0x044 => _7),
(0x084 => IGROUPRn: [ReadWrite<u32>; 31]),
(0x100 => _5),
(0x104 => ISENABLER: [ReadWrite<u32>; 31]),
(0x180 => _1),
(0x420 => IPRIORITYRn: [ReadWrite<u32>; 248]),
(0x800 => _6),
(0x820 => ITARGETSR: [ReadWrite<u32, ITARGETSR::Register>; 248]),
(0xC00 => _2),
(0xC08 => ICFGR: [ReadWrite<u32>; 62]),
@ -76,12 +84,7 @@ impl GicdSharedRegs {
#[inline(always)]
fn itargets_slice(&self) -> &[ReadWrite<u32, ITARGETSR::Register>] {
if self.num_irqs() >= 36 {
let itargetsr_max_index = ((self.num_irqs() - 32) >> 2) - 1;
&self.ITARGETSR[0..itargetsr_max_index]
} else {
&[]
}
&self.ITARGETSR[..]
}
}
@ -120,11 +123,9 @@ impl Gicd {
// 2 bits per IRQ, 16 entries per register
let reg = irq / 16;
let shift = (irq % 16) * 2;
let cfgr_value = match (options.trigger, options.level) {
(IrqTrigger::Level, IrqLevel::ActiveLow) => 0,
(IrqTrigger::Level, _) => 0,
(_, IrqLevel::ActiveLow) => 1,
(_, _) => 1,
let cfgr_value = match options.trigger {
IrqTrigger::Edge | IrqTrigger::Default => 0b10,
IrqTrigger::Level => 0b00,
};
match reg {
@ -170,7 +171,7 @@ impl Gicd {
log::debug!("Enabling GICv2 GICD, max IRQ number: {}", regs.num_irqs());
regs.CTLR.modify(CTLR::Enable::SET);
regs.CTLR.modify(CTLR::EnableGrp0::SET);
for reg in regs.itargets_slice().iter() {
// Redirect all IRQs to cpu0 (this CPU)

View File

@ -0,0 +1,259 @@
//! ARM GICv2m extension support for MSI/MSI-x
use core::{mem::offset_of, ops::Range};
use abi::error::Error;
use alloc::{sync::Arc, vec::Vec};
use device_api::{
device::Device,
interrupt::{
ExternalInterruptController, InterruptAffinity, InterruptHandler, Irq, IrqLevel,
IrqOptions, IrqTrigger, IrqVector, MessageInterruptController, MsiInfo,
},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
OneTimeInit,
};
use tock_registers::{
interfaces::Readable,
register_bitfields, register_structs,
registers::{ReadOnly, WriteOnly},
};
use crate::arch::aarch64::gic::GIC_SPI_START;
register_bitfields! {
u32,
GICM_TYPER [
VALID OFFSET(31) NUMBITS(1) [],
CLR OFFSET(30) NUMBITS(1) [],
SR OFFSET(29) NUMBITS(1) [],
INTID OFFSET(16) NUMBITS(13) [],
NUMSPIS OFFSET(0) NUMBITS(11) [],
],
GICM_IIDR [
VARIANT OFFSET(16) NUMBITS(4) [],
REVISION OFFSET(12) NUMBITS(4) [],
IMPLEMENTER OFFSET(0) NUMBITS(12) [],
],
}
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x0000 => _0),
(0x0008 => GICM_TYPER: ReadOnly<u32, GICM_TYPER::Register>),
(0x000C => _1),
(0x0040 => GICM_SETSPI_NSR: WriteOnly<u32>),
(0x0044 => _2),
(0x0048 => GICM_CLRSPI_NSR: WriteOnly<u32>),
(0x004C => _3),
(0x0050 => GICM_SETSPI_SR: WriteOnly<u32>),
(0x0054 => _4),
(0x0058 => GICM_CLRSPI_SR: WriteOnly<u32>),
(0x005C => _5),
(0x0FCC => GICM_IIDR: ReadOnly<u32, GICM_IIDR::Register>),
(0x0FD0 => _6),
(0x1000 => @END),
}
}
struct MsiEntry {
handler: Arc<dyn InterruptHandler>,
vector: usize,
}
struct Inner {
irq_range: Range<u32>,
msi_map: IrqSafeRwLock<Vec<Option<MsiEntry>>>,
}
/// GICv2m Register Frame, allows handling MSI(-x)-based interrupts via its parent GIC
pub struct Gicv2m {
base: PhysicalAddress,
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
parent: Arc<dyn ExternalInterruptController>,
msi_base_override: Option<u32>,
msi_count_override: Option<usize>,
inner: OneTimeInit<Inner>,
}
impl Device for Gicv2m {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
let regs = self.regs.lock();
log::info!("gicv2m: init @ {:#x}", self.base);
// NOTE qemu's gicv2m TYPER.VALID = 0 for some reason, even though it contains proper
// values
let quirk_qemu = (regs.GICM_IIDR.get() >> 20) == b'Q' as u32;
// If GICM_TYPER.VALID == 0, use the base provided via device tree (or fail if neither is
// available)
let valid = quirk_qemu || regs.GICM_TYPER.matches_all(GICM_TYPER::VALID::SET);
let irq_base = if valid {
regs.GICM_TYPER.read(GICM_TYPER::INTID)
} else {
self.msi_base_override
.ok_or(Error::InvalidArgument)
.inspect_err(|_| {
log::error!("gicv2m: typer is not valid and no base provided in the FDT")
})?
};
let irq_count = if valid {
regs.GICM_TYPER.read(GICM_TYPER::NUMSPIS)
} else {
self.msi_count_override
.ok_or(Error::InvalidArgument)
.inspect_err(|_| {
log::error!("gicv2m: typer is not valid and no irq count provided in the FDT")
})? as u32
};
log::info!("gicv2m: irq base {irq_base}, irq count {irq_count}");
let irq_range = irq_base..irq_base + irq_count;
self.inner.init(Inner {
irq_range: irq_range.clone(),
msi_map: IrqSafeRwLock::new((0..irq_count as usize).map(|_| None).collect()),
});
for irq in irq_range {
// Map SPI in parent
let irq = Irq::External(irq - 32);
self.parent.register_irq(
irq,
IrqOptions {
trigger: IrqTrigger::Edge,
level: IrqLevel::ActiveHigh,
},
self.clone(),
)?;
}
Ok(())
}
fn display_name(&self) -> &str {
"GICv2m Frame"
}
}
impl InterruptHandler for Gicv2m {
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
let IrqVector::Irq(Irq::External(spi)) = vector else {
return false;
};
let Some(inner) = self.inner.try_get() else {
return false;
};
let msi_map = inner.msi_map.read();
let index = (spi + GIC_SPI_START - inner.irq_range.start) as usize;
if index >= inner.irq_range.len() {
return false;
}
if let Some(entry) = &msi_map[index] {
entry
.handler
.clone()
.handle_irq(IrqVector::Msi(entry.vector))
} else {
false
}
}
}
impl MessageInterruptController for Gicv2m {
fn handle_msi(&self, _vector: usize) {
loop {}
}
fn register_msi_range(
self: Arc<Self>,
range: &mut [MsiInfo],
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
let inner = self.inner.get();
let mut msi_map = inner.msi_map.write();
// let map = self.irq_map.write();
// let irq_range = self.irq_range.try_get().ok_or(Error::DoesNotExist)?.clone();
let irq_base = inner.irq_range.start;
let mut allocated_range = None;
for irq in inner.irq_range.clone() {
let mut taken = false;
for i in 0..range.len() {
let index = (irq - irq_base) as usize + i;
if msi_map[index].is_some() {
taken = true;
break;
}
}
if taken {
continue;
}
allocated_range = Some(irq..irq + range.len() as u32);
break;
}
let map_range = allocated_range
.ok_or(Error::InvalidArgument)
.inspect_err(|_| log::warn!("gicv2m: no free irq slots"))?;
for (i, (info, irq)) in core::iter::zip(range, map_range).enumerate() {
log::info!("gicv2m: map msi irq {irq} -> {}", handler.display_name());
let index = (irq - irq_base) as usize;
msi_map[index] = Some(MsiEntry {
vector: i,
handler: handler.clone(),
});
*info = MsiInfo {
address: self
.base
.add(offset_of!(Regs, GICM_SETSPI_NSR))
.into_usize(),
value: irq,
vector: i,
affinity: InterruptAffinity::Any,
};
self.parent.enable_irq(Irq::External(irq - 32))?;
}
Ok(())
}
}
device_tree_driver! {
compatible: ["arm,gic-v2m-frame"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let parent = node.parent()?.as_interrupt_controller()?;
let msi_base_override = node.prop_usize("arm,msi-base-spi").map(|x| x as u32);
let msi_count_override = node.prop_usize("arm,msi-num-spis");
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.inspect_err(|e| {
log::error!("gicv2m: could not map memory at {base:#x}: {e:?}");
}).ok()?;
let intc = Arc::new(Gicv2m {
base,
parent,
msi_base_override,
msi_count_override,
regs: IrqSafeSpinlock::new(regs),
inner: OneTimeInit::new()
});
node.make_msi_controller(intc.clone());
Some(intc)
}
}
}

View File

@ -10,7 +10,7 @@ use device_api::{
interrupt::{
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger,
LocalInterruptController, MessageInterruptController, MsiInfo,
IrqVector, LocalInterruptController,
},
};
use device_tree::{
@ -32,8 +32,12 @@ use super::AArch64;
const MAX_IRQ: usize = 300;
const IPI_VECTOR: u64 = 1;
const GIC_PPI_START: u32 = 16;
const GIC_SPI_START: u32 = 32;
pub mod gicc;
pub mod gicd;
pub mod gicv2m;
/// ARM Generic Interrupt Controller v2
pub struct Gic {
@ -96,8 +100,8 @@ impl ExternalInterruptController for Gic {
let gicd = self.gicd.get();
let index = match irq {
Irq::External(i) => i + 32,
Irq::Private(i) => i + 16,
Irq::External(i) => i + GIC_SPI_START,
Irq::Private(i) => i + GIC_PPI_START,
} as usize;
log::debug!(
@ -107,7 +111,7 @@ impl ExternalInterruptController for Gic {
options.trigger,
options.level
);
if index >= 32 {
if index >= GIC_SPI_START as usize {
gicd.configure_irq(index, options);
}
table.insert(index, handler)?;
@ -118,28 +122,38 @@ impl ExternalInterruptController for Gic {
fn enable_irq(&self, irq: Irq) -> Result<(), Error> {
let gicd = self.gicd.get();
let index = match irq {
Irq::External(i) => i + 32,
Irq::Private(i) => i + 16,
Irq::External(i) => i + GIC_SPI_START,
Irq::Private(i) => i + GIC_PPI_START,
} as usize;
log::info!("Enable irq{index} ({irq:?})");
log::debug!("Enable irq{index} ({irq:?})");
gicd.enable_irq(index);
Ok(())
}
fn handle_pending_irqs(&self) {
let gicc = self.gicc.get();
let irq_number = gicc.pending_irq_number();
if irq_number >= MAX_IRQ {
return;
}
gicc.clear_irq(irq_number);
if irq_number == IPI_VECTOR as usize {
gicc.clear_irq(irq_number);
// TODO pop entry
crate::panic::panic_secondary();
}
gicc.clear_irq(irq_number);
if irq_number < GIC_PPI_START as usize {
return;
}
let irq = if irq_number < GIC_SPI_START as usize {
Irq::Private(irq_number as u32 - GIC_PPI_START)
} else {
Irq::External(irq_number as u32 - GIC_SPI_START)
};
{
let table = self.table.read();
@ -151,25 +165,11 @@ impl ExternalInterruptController for Gic {
}
};
entry.handle_irq(None);
entry.handle_irq(IrqVector::Irq(irq));
}
}
}
impl MessageInterruptController for Gic {
fn handle_msi(&self, _vector: usize) {
unimplemented!()
}
fn register_msi_range(
&self,
_range: &mut [MsiInfo],
_handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
unimplemented!()
}
}
impl LocalInterruptController for Gic {
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error> {
let local = cpu_index();
@ -211,8 +211,6 @@ impl DeviceTreeInterruptController for Gic {
// IRQ_TYPE_LEVEL_HIGH - 4
// IRQ_TYPE_LEVEL_LOW - 8
log::info!("MAP INTERRUPT offset={offset}");
let sizes = (1, 1, 1);
let (kind, number, options) = property.read_cells_at(offset, sizes)?;
let number = number as u32;
@ -236,6 +234,10 @@ impl DeviceTreeInterruptController for Gic {
options: IrqOptions { trigger, level },
})
}
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController> {
self
}
}
impl Gic {

View File

@ -7,7 +7,7 @@ use abi::{error::Error, time::NANOSECONDS_IN_SECOND};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{FullIrq, InterruptHandler},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use kernel_arch::task::Scheduler;
@ -25,7 +25,7 @@ pub const TICK_INTERVAL: u64 = 250000;
static LAST_TICKS: AtomicU64 = AtomicU64::new(0);
impl InterruptHandler for ArmTimer {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let count = CNTPCT_EL0.get();
CNTP_TVAL_EL0.set(TICK_INTERVAL);

View File

@ -5,7 +5,7 @@ use acpi::HpetInfo;
use alloc::{collections::btree_map::BTreeMap, format, string::String, sync::Arc};
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq, IrqOptions, IrqTrigger},
interrupt::{InterruptHandler, Irq, IrqOptions, IrqTrigger, IrqVector},
};
use libk::{device::external_interrupt_controller, task::runtime, time};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
@ -102,7 +102,7 @@ const FS_IN_S: u64 = 10u64.pow(15);
const FS_IN_NS: u64 = 10u64.pow(6);
impl InterruptHandler for HpetTimer {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let now = self.parent.read_counter();
let last = self.last_ticks.swap(now, Ordering::Relaxed);
let delta = now.wrapping_sub(last);

View File

@ -2,7 +2,7 @@ use abi::error::Error;
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::{
intrinsics::{IoPort, IoPortAccess},
@ -31,7 +31,7 @@ pub struct I8253 {
}
impl InterruptHandler for I8253 {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
self.irq_handler_fastpath();
true
}

View File

@ -6,7 +6,7 @@ use device_api::{
device::Device,
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
IrqOptions,
IrqOptions, IrqVector,
},
};
use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess};
@ -94,9 +94,10 @@ impl ExternalInterruptController for I8259 {
self.eoi(index);
let table = self.table.lock();
let vector = IrqVector::Irq(Irq::External(index as u32));
if let Some(handler) = table.handler(index - 1) {
handler.clone().handle_irq(None);
handler.clone().handle_irq(vector);
}
}
}

View File

@ -6,7 +6,7 @@ use abi::{
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::{
intrinsics::{IoPort, IoPortAccess},
@ -76,7 +76,7 @@ impl Inner {
}
impl InterruptHandler for PS2Controller {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let mut count = 0;
let mut inner = self.inner.lock();

View File

@ -2,7 +2,7 @@ use abi::error::Error;
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch::{Architecture, ArchitectureImpl};
use kernel_arch_x86::{
@ -124,7 +124,7 @@ impl Inner {
}
impl InterruptHandler for Rtc {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let mut inner = self.inner.lock();
if inner.counter == 0 {
let time = inner.read_date_time();

View File

@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess};
use libk::{
@ -97,7 +97,7 @@ impl DebugSink for Port {
}
impl InterruptHandler for Port {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.terminal.output();
if let Some(byte) = inner.handle_irq() {
self.terminal.write_to_input(byte);

View File

@ -6,7 +6,7 @@ use device_api::{
device::Device,
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
IrqLevel, IrqOptions, IrqTrigger,
IrqLevel, IrqOptions, IrqTrigger, IrqVector,
},
};
use kernel_arch_x86::ISA_IRQ_OFFSET;
@ -217,30 +217,15 @@ impl ExternalInterruptController for IoApic {
fn handle_specific_irq(&self, gsi: usize) {
let table = self.table.read();
let vector = IrqVector::Irq(Irq::External(gsi as u32));
if let Some(handler) = table.handler(gsi) {
handler.clone().handle_irq(None);
handler.clone().handle_irq(vector);
} else {
log::warn!("No handler set for GSI #{}", gsi);
}
}
}
// fn register_irq(
// &self,
// irq: Irq,
// options: IrqOptions,
// handler: &'static dyn InterruptHandler,
// ) -> Result<(), Error> {
// }
//
// fn enable_irq(&self, irq: Irq) -> Result<(), Error> {
// }
//
// fn handle_specific_irq(&self, gsi: usize) {
// let table = self.table.lock();
//
// }
// }
impl IoApic {
/// Creates an I/O APIC instance from its ACPI definition

View File

@ -6,17 +6,10 @@ use alloc::{sync::Arc, vec, vec::Vec};
use device_api::{
device::Device,
interrupt::{
InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage,
InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage, IrqVector,
LocalInterruptController, MessageInterruptController, MsiInfo,
},
};
// use device_api::{
// interrupt::{
// InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage,
// LocalInterruptController, MessageInterruptController, MsiInfo,
// },
// Device,
// };
use kernel_arch_x86::registers::MSR_IA32_APIC_BASE;
use kernel_arch_x86_64::{mem::table::L3, LocalApicInterface, CPU_COUNT};
use libk::arch::Cpu;
@ -228,14 +221,14 @@ impl MessageInterruptController for LocalApic {
};
drop(table);
handler.handle_irq(Some(vector));
handler.handle_irq(IrqVector::Msi(vector));
i += 1;
}
}
fn register_msi_range(
&self,
self: Arc<Self>,
range: &mut [MsiInfo],
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {

View File

@ -3,7 +3,7 @@ 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 alloc::{boxed::Box, sync::Arc};
use alloc::sync::Arc;
use apic::{ioapic::IoApic, local::LocalApic};
use device_api::device::Device;
use kernel_arch_x86::{
@ -251,7 +251,7 @@ impl X86_64 {
.expect("Could not initialize memory management");
}
self.init_local_cpu(cpu_id, available_features, enabled_features);
let local_apic = self.init_local_cpu(cpu_id, available_features, enabled_features);
if cpu_id == 0 {
self.setup_from_boot_data()?;
@ -267,7 +267,7 @@ impl X86_64 {
}
if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi)?;
self.init_platform_from_acpi(acpi, local_apic)?;
}
if !config::get().x86_64.disable_hpet {
@ -322,8 +322,8 @@ impl X86_64 {
cpu_id: usize,
available_features: CpuFeatures,
enabled_features: CpuFeatures,
) {
let local_apic = Box::new(LocalApic::new());
) -> Arc<LocalApic> {
let local_apic = Arc::new(LocalApic::new());
let tss_address = gdt::init();
exception::init_exceptions(cpu_id);
@ -331,7 +331,7 @@ impl X86_64 {
this: null_mut(),
tss_address,
tmp_address: 0,
local_apic,
local_apic: local_apic.clone(),
available_features,
enabled_features,
};
@ -339,6 +339,8 @@ impl X86_64 {
Cpu::init_local(Some(cpu_id as _), cpu_data);
syscall::init_syscall();
local_apic
}
unsafe fn setup_from_boot_data(&self) -> Result<(), Error> {
@ -364,6 +366,7 @@ impl X86_64 {
unsafe fn init_platform_from_acpi(
&self,
acpi: &'static AcpiTables<AcpiHandlerImpl>,
local_apic: Arc<LocalApic>,
) -> Result<(), Error> {
let platform_info = acpi.platform_info_in(AcpiAllocator).map_err(|err| {
log::error!("Could not get ACPI platform info: {:?}", err);
@ -392,7 +395,8 @@ impl X86_64 {
if let Ok(mcfg) = acpi.find_table::<Mcfg>() {
for entry in mcfg.entries() {
if let Err(error) = PciBusManager::add_segment_from_mcfg(entry) {
if let Err(error) = PciBusManager::add_segment_from_mcfg(entry, local_apic.clone())
{
log::error!("Could not add PCI bus segment: {error:?}");
}
}

View File

@ -3,13 +3,17 @@
use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
use device_api::{device::Device, interrupt::Irq};
use device_tree::{
driver::{device_tree_driver, util::pcie_interrupt_map, Node, ProbeContext},
driver::{
device_tree_driver,
util::{pcie_interrupt_map, pcie_msi_map},
Node, ProbeContext,
},
DeviceTreePropertyRead,
};
use libk_mm::address::PhysicalAddress;
use ygg_driver_pci::{
device::{PciInterrupt, PciInterruptPin, PciInterruptRoute},
interrupt::PciInterruptMap,
interrupt::{PciFixedMsiMap, PciFixedMsiMapping, PciInterruptMap, PciMsiMap},
PciAddress, PciAddressRange, PciBusManager, PciRangeType,
};
@ -78,6 +82,42 @@ fn make_interrupt_map(node: &Arc<Node>) -> Option<PciInterruptMap> {
Some(PciInterruptMap::Fixed(imap))
}
fn make_msi_map(node: &Arc<Node>) -> Option<PciMsiMap> {
let msi_map = pcie_msi_map(node)?;
let mut entries = Vec::new();
for entry in msi_map {
let (bus, device, function) = entry.base_rid.as_parts();
let start_address = PciAddress {
// TODO
segment: 0,
bus,
device,
function,
};
let (bus, device, function) = entry.base_rid.offset(entry.length).as_parts();
let end_address = PciAddress {
// TODO
segment: 0,
bus,
device,
function,
};
entries.push(PciFixedMsiMapping {
start_address,
end_address,
controller: entry.msi_controller,
});
}
if entries.is_empty() {
None
} else {
Some(PciMsiMap::Fixed(PciFixedMsiMap { entries }))
}
}
device_tree_driver! {
compatible: ["pci-host-ecam-generic"],
driver: {
@ -111,12 +151,18 @@ device_tree_driver! {
}
}
let msi_map = match make_msi_map(node) {
Some(map) => map,
None => PciMsiMap::Legacy
};
PciBusManager::add_segment_from_device_tree(
ecam_base,
// TODO bus-range
0..255,
bus_ranges,
interrupt_map
interrupt_map,
msi_map,
).ok();
None

View File

@ -7,7 +7,7 @@ use device_api::{
device::Device,
interrupt::{
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, Irq, IrqOptions,
InterruptTable, Irq, IrqOptions, IrqVector,
},
};
use device_tree::{
@ -175,7 +175,6 @@ impl ExternalInterruptController for Plic {
table.insert(irq as usize, handler)?;
// TODO
Ok(())
}
@ -195,9 +194,10 @@ impl ExternalInterruptController for Plic {
if irq == 0 {
break;
}
let vector = IrqVector::Irq(Irq::External(irq));
if let Some(handler) = table.handler(irq as usize) {
handler.clone().handle_irq(None);
handler.clone().handle_irq(vector);
} else {
log::warn!("plic: no handler for IRQ #{irq}");
}
@ -272,6 +272,10 @@ impl DeviceTreeInterruptController for Plic {
options: IrqOptions::default(),
})
}
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController> {
self
}
}
fn map_context_to_hart(target: u32) -> Option<u32> {

View File

@ -9,7 +9,7 @@ use abi::{
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{FullIrq, InterruptHandler},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::{
driver::{device_tree_driver, lookup_phandle, Node, ProbeContext},
@ -122,7 +122,7 @@ impl DebugSink for Bcm2835AuxUart {
}
impl InterruptHandler for Bcm2835AuxUart {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.inner.get();
let (status, byte) = {

View File

@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{FullIrq, InterruptHandler},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
@ -149,7 +149,7 @@ impl Device for Ns16550a {
}
impl InterruptHandler for Ns16550a {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.inner.get();
let output = inner.output();
let byte = output.io.lock().handle_irq();

View File

@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{FullIrq, InterruptHandler},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
@ -124,7 +124,7 @@ impl DebugSink for Pl011 {
}
impl InterruptHandler for Pl011 {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.inner.get();
let byte = inner.output().handle_irq();

View File

@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{FullIrq, InterruptHandler},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
@ -133,7 +133,7 @@ impl Io {
}
impl InterruptHandler for DwUart {
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.inner.get();
let output = inner.output();
let byte = output.io.lock().handle_irq();

View File

@ -39,7 +39,6 @@
use abi::{error::Error, io::FileMode};
use alloc::string::String;
use arch::Platform;
use cfg_if::cfg_if;
use git_version::git_version;
use kernel_arch::{Architecture, ArchitectureImpl};
use libk::{
@ -62,16 +61,10 @@ extern crate alloc;
#[cfg(not(rust_analyzer))]
extern crate compiler_builtins;
cfg_if! {
if #[cfg(any(target_arch = "x86_64", rust_analyzer))] {
extern crate ygg_driver_net_rtl81xx;
extern crate ygg_driver_usb_xhci;
extern crate ygg_driver_nvme;
}
}
extern crate ygg_driver_ahci;
extern crate ygg_driver_net_rtl81xx;
extern crate ygg_driver_nvme;
extern crate ygg_driver_usb_xhci;
extern crate ygg_driver_virtio_gpu;
extern crate ygg_driver_virtio_net;