diff --git a/etc/dtb/aarch64/bcm2711-rpi-4-b.dts b/etc/dtb/aarch64/bcm2711-rpi-4-b.dts index fe7430bd..fedfbf43 100644 --- a/etc/dtb/aarch64/bcm2711-rpi-4-b.dts +++ b/etc/dtb/aarch64/bcm2711-rpi-4-b.dts @@ -150,6 +150,11 @@ brcm,function = <2>; bootph-all; }; + uart2_gpio: uart2_pins { + brcm,pins = <0>, <1>; + brcm,function = <3>; + brcm,pull = <0>, <2>; + }; // I²C i2c0if_gpio0: i2c0if-gpio0 { @@ -230,7 +235,7 @@ clocks = <&cprman 0x14>; #address-cells = <0x01>; #size-cells = <0x00>; - status = "okay"; + status = "disabled"; clock-frequency = <0x186a0>; }; @@ -239,7 +244,7 @@ #address-cells = <0x01>; #size-cells = <0x00>; i2c-parent = <&i2c0if>; - status = "okay"; + status = "disabled"; pinctrl-names = "i2c0", "i2c_csi_dsi"; pinctrl-0 = <&i2c0if_gpio0>; pinctrl-1 = <&i2c0if_gpio44>; @@ -391,6 +396,8 @@ clock-names = "uartclk", "apb_pclk"; arm,primecell-periphid = <0x241011>; + pinctrl-0 = <&uart2_gpio>; + pinctrl-names = "default"; status = "disabled"; }; diff --git a/kernel/driver/bsp/riscv/src/plic.rs b/kernel/driver/bsp/riscv/src/plic.rs index a46f9a58..48ddaa2a 100644 --- a/kernel/driver/bsp/riscv/src/plic.rs +++ b/kernel/driver/bsp/riscv/src/plic.rs @@ -2,8 +2,7 @@ use alloc::{sync::Arc, vec::Vec}; use device_api::{ device::{Device, DeviceInitContext}, interrupt::{ - ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq, - IrqHandle, IrqOptions, IrqVector, + ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqVector, }, }; use device_tree::{ @@ -13,7 +12,10 @@ use device_tree::{ }, }; use kernel_arch_riscv64::boot_hart_id; -use libk::{arch::Cpu, device::register_external_interrupt_controller}; +use libk::{ + arch::Cpu, + device::{interrupt::FixedInterruptTable, register_external_interrupt_controller}, +}; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; use libk_util::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock}; use tock_registers::{ @@ -77,8 +79,7 @@ register_structs! { struct Context { enable: IrqSafeRwLock>, control: IrqSafeRwLock>, - // TODO scale the table depending on effective MAX_IRQS value - table: IrqSafeRwLock>, + table: FixedInterruptTable, } struct Inner { @@ -163,13 +164,13 @@ impl ExternalInterruptController for Plic { .inspect_err(|_| log::error!("plic: no context for hart {bsp_hart_id}"))? .context .get(); - let mut table = context.table.write(); + // let mut table = context.table.write(); + log::info!( "Bind irq #{irq} -> hart {bsp_hart_id}, {:?}", handler.display_name() ); - - table.insert(irq as usize, handler)?; + context.table.insert(irq as usize, handler); Ok(()) } @@ -183,7 +184,7 @@ impl ExternalInterruptController for Plic { let context = context.context.get(); let control = context.control.write(); - let table = context.table.read(); + // let table = context.table.read(); loop { let irq = control.CLAIM.get(); @@ -192,9 +193,7 @@ impl ExternalInterruptController for Plic { } let vector = IrqVector::Irq(Irq::External(irq)); - if let Some(handler) = table.handler(irq as usize) { - handler.clone().handle_irq(vector); - } else { + if !context.table.handle_irq_line(irq as usize, vector) { log::warn!("plic: no handler for IRQ #{irq}"); } @@ -242,7 +241,7 @@ impl Device for Plic { context.context.init(Context { enable: IrqSafeRwLock::new(enable), control: IrqSafeRwLock::new(control), - table: IrqSafeRwLock::new(FixedInterruptTable::new()), + table: FixedInterruptTable::new(MAX_IRQS), // table: IrqSafeRwLock::new(FixedInterruptTable::new()), }); } diff --git a/kernel/driver/serial/uart8250/src/lib.rs b/kernel/driver/serial/uart8250/src/lib.rs index b0579675..afe65dcf 100644 --- a/kernel/driver/serial/uart8250/src/lib.rs +++ b/kernel/driver/serial/uart8250/src/lib.rs @@ -37,6 +37,9 @@ pub trait PortConfig: Sync + Send { pub trait Access: Sized + Send + 'static { type Config: Config; + /// # Safety + /// + /// Unsafe: allows physical memory access. unsafe fn map(config: &::Port) -> Result; fn read(&self, reg: u8) -> u8; @@ -76,6 +79,10 @@ impl Uart8250 { } } + /// # Safety + /// + /// Unsafe: the function is meant only to be called once, directly + /// interacts with the device state. pub unsafe fn init_inner(self: &Arc) -> Result<(), Error> { let ports = self.ports.iter(); let port_configs = self.config.ports().iter(); diff --git a/kernel/driver/serial/uart8250/src/port.rs b/kernel/driver/serial/uart8250/src/port.rs index 4526befa..96dea8b6 100644 --- a/kernel/driver/serial/uart8250/src/port.rs +++ b/kernel/driver/serial/uart8250/src/port.rs @@ -109,7 +109,7 @@ impl Port8250 { let regs = inner.output().regs.lock(); let iir = regs.read(REG_IIR) & IIR_MASK; if iir == IIR_RXDA { - Some(regs.read(REG_RBR) as u8) + Some(regs.read(REG_RBR)) } else { None } diff --git a/kernel/lib/device-api/src/interrupt.rs b/kernel/lib/device-api/src/interrupt.rs index ed130a70..24698e65 100644 --- a/kernel/lib/device-api/src/interrupt.rs +++ b/kernel/lib/device-api/src/interrupt.rs @@ -83,10 +83,6 @@ pub trait InterruptHandler: Device { fn handle_irq(self: Arc, vector: IrqVector) -> bool; } -pub trait InterruptTable: Sync { - fn handler(&self, index: usize) -> Option<&Arc>; -} - pub trait ExternalInterruptController: Device { /// Performs IRQ delivery method configuration and registers a handler to execute when it is /// fired @@ -151,10 +147,6 @@ pub trait LocalInterruptController: Device { fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error>; } -pub struct FixedInterruptTable { - rows: [Option>; N], -} - impl IrqHandle { pub fn register(&self, handler: Arc) -> Result<(), Error> { self.intc.register_irq(self.irq, self.options, handler) @@ -165,43 +157,6 @@ impl IrqHandle { } } -impl FixedInterruptTable { - pub const fn new() -> Self { - Self { - rows: [const { None }; N], - } - } - - pub fn insert(&mut self, index: usize, entry: Arc) -> Result<(), Error> { - let row = self.rows.get_mut(index).ok_or(Error::InvalidArgument)?; - if row.is_some() { - return Err(Error::AlreadyExists); - } - *row = Some(entry); - Ok(()) - } - - pub fn insert_least_loaded( - &mut self, - handler: Arc, - ) -> Result { - let index = self - .rows - .iter() - .position(|p| p.is_none()) - .ok_or(Error::InvalidArgument)?; - self.rows[index].replace(handler); - Ok(index) - } -} - -impl InterruptTable for FixedInterruptTable { - #[inline] - fn handler(&self, index: usize) -> Option<&Arc> { - self.rows.get(index).and_then(|p| p.as_ref()) - } -} - impl IrqLevel { pub fn override_default(self, value: IrqLevel) -> Self { match self { diff --git a/kernel/lib/device-tree/src/driver/macros.rs b/kernel/lib/device-tree/src/driver/macros.rs index df7cd59d..5c116bee 100644 --- a/kernel/lib/device-tree/src/driver/macros.rs +++ b/kernel/lib/device-tree/src/driver/macros.rs @@ -25,6 +25,7 @@ pub macro device_tree_driver( static __REGISTER_FN: extern "C" fn() = __register_fn; extern "C" fn __register_fn() { + #[allow(clippy::needless_update)] let config = $crate::driver::DriverConfig { $( $($config_field: $config_value,)+ diff --git a/kernel/lib/device-tree/src/driver/tree.rs b/kernel/lib/device-tree/src/driver/tree.rs index 132bd903..66f596b5 100644 --- a/kernel/lib/device-tree/src/driver/tree.rs +++ b/kernel/lib/device-tree/src/driver/tree.rs @@ -107,14 +107,17 @@ impl Node { .as_str_list() .find_map(|c| drivers.iter().find(|d| d.matches(c))); - if libk::config::get().device_tree.log_missing && driver.is_none() { - // FIXME don't spam virtio missing stuff - if !name.is_some_and(|n| n.starts_with("virtio_mmio")) { - for (i, compatible) in compatible.as_str_list().enumerate() { - if i == 0 { - log::warn!("No driver for {name:?} ({compatible:?})"); - } else { - log::warn!(" also {compatible:?}"); + #[cfg(any(not(target_arch = "x86_64"), rust_analyzer))] + { + if libk::config::get().device_tree.log_missing && driver.is_none() { + // FIXME don't spam virtio missing stuff + if !name.is_some_and(|n| n.starts_with("virtio_mmio")) { + for (i, compatible) in compatible.as_str_list().enumerate() { + if i == 0 { + log::warn!("No driver for {name:?} ({compatible:?})"); + } else { + log::warn!(" also {compatible:?}"); + } } } } diff --git a/kernel/libk/src/device/interrupt.rs b/kernel/libk/src/device/interrupt.rs new file mode 100644 index 00000000..fc3f56bf --- /dev/null +++ b/kernel/libk/src/device/interrupt.rs @@ -0,0 +1,44 @@ +use alloc::{sync::Arc, vec::Vec}; +use device_api::interrupt::{InterruptHandler, IrqVector}; +use libk_util::sync::spin_rwlock::IrqSafeRwLock; + +pub struct FixedInterruptTable { + rows: Vec>>>, +} + +impl FixedInterruptTable { + pub fn new(irq_lines: usize) -> Self { + Self { + rows: (0..irq_lines) + .map(|_| IrqSafeRwLock::new(Vec::new())) + .collect(), + } + } + + pub fn insert(&self, line: usize, handler: Arc) { + let mut row = self.rows[line].write(); + row.push(handler); + } + + pub fn insert_least_loaded(&self, handler: Arc) -> usize { + let min_line = self + .rows + .iter() + .enumerate() + .min_by_key(|(_, row)| row.read().len()) + .unwrap() + .0; + self.insert(min_line, handler); + min_line + } + + pub fn handle_irq_line(&self, line: usize, vector: IrqVector) -> bool { + let row = self.rows[line].read(); + for handler in row.iter() { + if handler.clone().handle_irq(vector) { + return true; + } + } + false + } +} diff --git a/kernel/libk/src/device/mod.rs b/kernel/libk/src/device/mod.rs index 10edeb37..dc82bb2a 100644 --- a/kernel/libk/src/device/mod.rs +++ b/kernel/libk/src/device/mod.rs @@ -7,6 +7,7 @@ use yggdrasil_abi::error::Error; pub mod block; pub mod char; pub mod display; +pub mod interrupt; pub mod manager; // TODO get rid of this, this does not work when there are multiple interrupt controllers diff --git a/kernel/src/arch/aarch64/gic/mod.rs b/kernel/src/arch/aarch64/gic/mod.rs index 72c74b79..b47c339e 100644 --- a/kernel/src/arch/aarch64/gic/mod.rs +++ b/kernel/src/arch/aarch64/gic/mod.rs @@ -8,9 +8,8 @@ use alloc::sync::Arc; use device_api::{ device::{Device, DeviceInitContext}, interrupt::{ - ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, - IpiDeliveryTarget, IpiMessage, Irq, IrqHandle, IrqLevel, IrqOptions, IrqTrigger, IrqVector, - LocalInterruptController, + ExternalInterruptController, InterruptHandler, IpiDeliveryTarget, IpiMessage, Irq, + IrqHandle, IrqLevel, IrqOptions, IrqTrigger, IrqVector, LocalInterruptController, }, }; use device_tree::{ @@ -18,12 +17,15 @@ use device_tree::{ driver::{DeviceTreeInterruptController, Node, ProbeContext, device_tree_driver}, }; use kernel_arch_aarch64::{CPU_COUNT, GicInterface}; -use libk::{arch::Cpu, device::register_external_interrupt_controller, task::cpu_index}; +use libk::{ + arch::Cpu, + device::{interrupt::FixedInterruptTable, register_external_interrupt_controller}, + task::cpu_index, +}; use libk_mm::{ address::PhysicalAddress, device::{DeviceMemoryIo, RawDeviceMemoryMapping}, }; -use libk_util::sync::spin_rwlock::IrqSafeRwLock; use self::{gicc::Gicc, gicd::Gicd}; @@ -43,7 +45,7 @@ pub mod gicv2m; pub struct Gic { gicc: Gicc, gicd: Gicd, - table: IrqSafeRwLock>, + table: FixedInterruptTable, } unsafe impl Sync for Gic {} @@ -72,7 +74,7 @@ impl ExternalInterruptController for Gic { options: IrqOptions, handler: Arc, ) -> Result<(), Error> { - let mut table = self.table.write(); + // let mut table = self.table.write(); let index = match irq { Irq::External(i) => i + GIC_SPI_START, @@ -89,7 +91,7 @@ impl ExternalInterruptController for Gic { if index >= GIC_SPI_START as usize { self.gicd.configure_irq(index, options); } - table.insert(index, handler)?; + self.table.insert(index, handler); Ok(()) } @@ -128,17 +130,9 @@ impl ExternalInterruptController for Gic { Irq::External(irq_number as u32 - GIC_SPI_START) }; - { - let table = self.table.read(); - let entry = match table.handler(irq_number) { - Some(handler) => handler.clone(), - None => { - log::warn!("No handler for irq{}", irq_number); - return; - } - }; - - entry.handle_irq(IrqVector::Irq(irq)); + let vector = IrqVector::Irq(irq); + if !self.table.handle_irq_line(irq_number, vector) { + log::warn!("No handler for irq{irq_number}"); } } } @@ -242,11 +236,12 @@ impl Gic { // self.gicd.init(gicd); // self.gicc.init(gicc); + let table = FixedInterruptTable::new(MAX_IRQ); Ok(Self { gicd, gicc, - table: IrqSafeRwLock::new(FixedInterruptTable::new()), + table, // table: IrqSafeRwLock::new(FixedInterruptTable::new()), }) } } diff --git a/kernel/src/arch/x86_64/apic/ioapic.rs b/kernel/src/arch/x86_64/apic/ioapic.rs index 80e6a176..7a639884 100644 --- a/kernel/src/arch/x86_64/apic/ioapic.rs +++ b/kernel/src/arch/x86_64/apic/ioapic.rs @@ -5,13 +5,14 @@ use alloc::sync::Arc; use device_api::{ device::{Device, DeviceInitContext}, interrupt::{ - ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq, - IrqLevel, IrqOptions, IrqTrigger, IrqVector, + ExternalInterruptController, InterruptHandler, Irq, IrqLevel, IrqOptions, IrqTrigger, + IrqVector, }, }; use kernel_arch_x86::ISA_IRQ_OFFSET; +use libk::device::interrupt::FixedInterruptTable; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; -use libk_util::sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock}; +use libk_util::sync::IrqSafeSpinlock; use tock_registers::{ interfaces::{Readable, Writeable}, register_structs, @@ -64,7 +65,7 @@ struct Inner { pub struct IoApic { inner: IrqSafeSpinlock, isa_redirections: [Option; 16], - table: IrqSafeRwLock>, + table: FixedInterruptTable, } impl Regs { @@ -170,7 +171,8 @@ impl ExternalInterruptController for IoApic { handler: Arc, ) -> Result<(), Error> { let mut inner = self.inner.lock(); - let table_vector = self.table.write().insert_least_loaded(handler.clone())?; + let table_vector = self.table.insert_least_loaded(handler.clone()); + // let table_vector = self.table.write().insert_least_loaded(handler.clone())?; let gsi_target_vector = (table_vector as u32) + IO_APIC_VECTOR_OFFSET; let bsp_apic = *BSP_APIC_ID.get(); @@ -216,12 +218,8 @@ 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(vector); - } else { + if !self.table.handle_irq_line(gsi, vector) { log::warn!("No handler set for GSI #{}", gsi); } } @@ -295,7 +293,7 @@ impl IoApic { Ok(Arc::new(Self { isa_redirections, inner: IrqSafeSpinlock::new(inner), - table: IrqSafeRwLock::new(FixedInterruptTable::new()), + table: FixedInterruptTable::new(POPULATED_EXTERNAL_VECTORS as usize), })) } diff --git a/kernel/src/device/i2c/mod.rs b/kernel/src/device/i2c/mod.rs index 817198de..9ff30416 100644 --- a/kernel/src/device/i2c/mod.rs +++ b/kernel/src/device/i2c/mod.rs @@ -57,7 +57,7 @@ impl Device for I2CMux { } fn display_name(&self) -> &str { - &self.name + self.name } } diff --git a/kernel/src/device/mod.rs b/kernel/src/device/mod.rs index f8774626..d8073d60 100644 --- a/kernel/src/device/mod.rs +++ b/kernel/src/device/mod.rs @@ -6,6 +6,7 @@ use libk_util::OneTimeInit; pub mod bus; pub mod clock; pub mod display; +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", rust_analyzer))] pub mod i2c; pub mod power; // pub mod timer;