From 906259c02436f47fb5c9dc0f0d191ee34e9a7c0f Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Mon, 21 Oct 2024 19:55:00 +0300 Subject: [PATCH] Pull irqchip from aarch64 code into more generic place --- src/arch/aarch64/device/generic_timer.rs | 13 +- src/arch/aarch64/device/irqchip/gic.rs | 3 +- src/arch/aarch64/device/irqchip/gicv3.rs | 3 +- .../aarch64/device/irqchip/irq_bcm2835.rs | 4 +- .../aarch64/device/irqchip/irq_bcm2836.rs | 3 +- src/arch/aarch64/device/irqchip/mod.rs | 273 +----------------- src/arch/aarch64/device/mod.rs | 4 +- src/arch/aarch64/device/serial.rs | 7 +- src/arch/aarch64/init/device_tree/mod.rs | 38 --- src/arch/aarch64/init/mod.rs | 1 - src/arch/aarch64/interrupt/irq.rs | 6 +- src/arch/aarch64/interrupt/mod.rs | 15 - src/arch/aarch64/mod.rs | 3 - src/arch/riscv64/device/irqchip/mod.rs | 6 + src/arch/riscv64/device/mod.rs | 1 + src/arch/riscv64/interrupt/mod.rs | 10 - src/dtb/irqchip.rs | 269 +++++++++++++++++ src/dtb/mod.rs | 39 +++ src/scheme/irq.rs | 11 +- 19 files changed, 356 insertions(+), 353 deletions(-) delete mode 100644 src/arch/aarch64/init/device_tree/mod.rs delete mode 100644 src/arch/aarch64/init/mod.rs create mode 100644 src/arch/riscv64/device/irqchip/mod.rs create mode 100644 src/dtb/irqchip.rs diff --git a/src/arch/aarch64/device/generic_timer.rs b/src/arch/aarch64/device/generic_timer.rs index 86e1028f8b..517cc06c8f 100644 --- a/src/arch/aarch64/device/generic_timer.rs +++ b/src/arch/aarch64/device/generic_timer.rs @@ -2,15 +2,20 @@ use alloc::boxed::Box; use log::info; use crate::{ - arch::device::irqchip::IRQ_CHIP, context, context::timeout, - device::cpu::registers::control_regs, dtb::DTB_BINARY, interrupt::irq::trigger, time, + context, + context::timeout, + device::cpu::registers::control_regs, + dtb::{ + irqchip::{register_irq, InterruptHandler, IRQ_CHIP}, + DTB_BINARY, + }, + interrupt::irq::trigger, + time, }; use alloc::vec::Vec; use byteorder::{ByteOrder, BE}; use fdt::Fdt; -use super::irqchip::{register_irq, InterruptHandler}; - bitflags! { struct TimerCtrlFlags: u32 { const ENABLE = 1 << 0; diff --git a/src/arch/aarch64/device/irqchip/gic.rs b/src/arch/aarch64/device/irqchip/gic.rs index 7cb7e485a7..cf6bf26c47 100644 --- a/src/arch/aarch64/device/irqchip/gic.rs +++ b/src/arch/aarch64/device/irqchip/gic.rs @@ -1,14 +1,13 @@ use core::ptr::{read_volatile, write_volatile}; use fdt::{node::FdtNode, Fdt}; +use crate::dtb::irqchip::{InterruptController, IrqDesc}; use log::info; use syscall::{ error::{Error, EINVAL}, Result, }; -use super::{InterruptController, IrqDesc}; - static GICD_CTLR: u32 = 0x000; static GICD_TYPER: u32 = 0x004; static GICD_ISENABLER: u32 = 0x100; diff --git a/src/arch/aarch64/device/irqchip/gicv3.rs b/src/arch/aarch64/device/irqchip/gicv3.rs index abe5cf71a1..cde9d2085f 100644 --- a/src/arch/aarch64/device/irqchip/gicv3.rs +++ b/src/arch/aarch64/device/irqchip/gicv3.rs @@ -3,13 +3,12 @@ use core::arch::asm; use fdt::{node::NodeProperty, Fdt}; use super::gic::GicDistIf; +use crate::dtb::irqchip::{InterruptController, IrqDesc}; use syscall::{ error::{Error, EINVAL}, Result, }; -use super::{InterruptController, IrqDesc}; - #[derive(Debug)] pub struct GicV3 { gic_dist_if: GicDistIf, diff --git a/src/arch/aarch64/device/irqchip/irq_bcm2835.rs b/src/arch/aarch64/device/irqchip/irq_bcm2835.rs index e7d3542860..27ef2c3b7c 100644 --- a/src/arch/aarch64/device/irqchip/irq_bcm2835.rs +++ b/src/arch/aarch64/device/irqchip/irq_bcm2835.rs @@ -1,19 +1,17 @@ use alloc::vec::Vec; use core::ptr::{read_volatile, write_volatile}; -use crate::arch::device::irqchip::IRQ_CHIP; use byteorder::{ByteOrder, BE}; use fdt::{node::FdtNode, Fdt}; use log::{debug, error, info}; +use crate::dtb::irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP}; use syscall::{ error::{Error, EINVAL}, Result, }; -use super::{InterruptController, InterruptHandler, IrqDesc}; - #[inline(always)] fn ffs(num: u32) -> u32 { let mut x = num; diff --git a/src/arch/aarch64/device/irqchip/irq_bcm2836.rs b/src/arch/aarch64/device/irqchip/irq_bcm2836.rs index 9fbfe38e75..a16f5e7e74 100644 --- a/src/arch/aarch64/device/irqchip/irq_bcm2836.rs +++ b/src/arch/aarch64/device/irqchip/irq_bcm2836.rs @@ -4,14 +4,13 @@ use core::{ }; use fdt::{node::FdtNode, Fdt}; +use crate::dtb::irqchip::{InterruptController, IrqDesc}; use log::{debug, info}; use syscall::{ error::{Error, EINVAL}, Result, }; -use super::{InterruptController, IrqDesc}; - const LOCAL_CONTROL: u32 = 0x000; const LOCAL_PRESCALER: u32 = 0x008; const LOCAL_GPU_ROUTING: u32 = 0x00C; diff --git a/src/arch/aarch64/device/irqchip/mod.rs b/src/arch/aarch64/device/irqchip/mod.rs index 25de0cb807..256a0d4d58 100644 --- a/src/arch/aarch64/device/irqchip/mod.rs +++ b/src/arch/aarch64/device/irqchip/mod.rs @@ -1,267 +1,22 @@ -use alloc::{boxed::Box, vec::Vec}; -use byteorder::{ByteOrder, BE}; -use fdt::Fdt; -use syscall::Result; - -use crate::init::device_tree::travel_interrupt_ctrl; -use log::{debug, error}; +use crate::dtb::irqchip::InterruptController; +use alloc::boxed::Box; mod gic; mod gicv3; mod irq_bcm2835; mod irq_bcm2836; -pub trait InterruptController { - fn irq_init( - &mut self, - fdt: &Fdt, - irq_desc: &mut [IrqDesc; 1024], - ic_idx: usize, - irq_idx: &mut usize, - ) -> Result>; - fn irq_ack(&mut self) -> u32; - fn irq_eoi(&mut self, irq_num: u32); - fn irq_enable(&mut self, irq_num: u32); - #[allow(unused)] - fn irq_disable(&mut self, irq_num: u32); - fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result; - fn irq_to_virq(&mut self, hwirq: u32) -> Option; - fn irq_handler(&mut self, irq: u32); -} - -pub trait InterruptHandler { - fn irq_handler(&mut self, irq: u32); -} - -pub struct IrqChipItem { - pub phandle: u32, - pub parent_phandle: Option, - pub parent: Option, //parent idx in chiplist - pub childs: Vec, //child idx in chiplist - pub interrupts: Vec, - pub ic: Box, -} - -pub struct IrqChipList { - pub chips: Vec, - pub root_phandle: u32, - pub root_idx: usize, -} - -pub struct IrqDescItem { - pub idx: usize, - pub ic_idx: usize, //ic idx in irq chip list - pub child_ic_idx: Option, //ic idx in irq chip list - pub ic_irq: u32, //hwirq in ic - pub used: bool, -} - -pub struct IrqDesc { - pub basic: IrqDescItem, - pub handler: Option>, -} - -impl IrqChipList { - fn init_inner1(&mut self, fdt: &Fdt) { - let root_node = fdt.root(); - let mut idx = 0; - let intr = root_node.property("interrupt-parent").unwrap(); - - let root_intr_parent = intr.as_usize().unwrap() as u32; - debug!("root parent = 0x{:08x}", root_intr_parent); - self.root_phandle = root_intr_parent; - for node in fdt.all_nodes() { - if node.property("interrupt-controller").is_some() { - let compatible = node.property("compatible").unwrap().as_str().unwrap(); - let phandle = node.property("phandle").unwrap().as_usize().unwrap() as u32; - let intr_cells = node.interrupt_cells().unwrap(); - let _intr = node.property("interrupt-parent"); - let _intr_data = node.property("interrupts"); - - debug!( - "{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", - node.name, compatible, intr_cells, phandle - ); - let mut item = IrqChipItem { - phandle, - parent_phandle: None, - parent: None, - childs: Vec::new(), - interrupts: Vec::new(), - ic: IrqChipCore::new_ic(compatible).unwrap(), - }; - if let Some(intr) = _intr { - if let Some(intr_data) = _intr_data { - let intr = intr.as_usize().unwrap() as u32; - debug!("interrupt-parent = 0x{:08x}", intr); - item.parent_phandle = Some(intr); - debug!("interrupts begin:"); - for chunk in intr_data.value.chunks(4) { - debug!("0x{:08x}, ", BE::read_u32(chunk)); - item.interrupts.push(BE::read_u32(chunk)); - } - debug!("interrupts end"); - } - } - if item.phandle == root_intr_parent { - self.root_idx = idx as usize; - } - - self.chips.push(item); - - idx += 1; - } - } - } - - fn init_inner2(&mut self) { - let mut x = 0; - - while x < self.chips.len() { - let mut y = 0; - while y < self.chips.len() { - if x == y { - y += 1; - continue; - } - if let Some(pp) = self.chips[y].parent_phandle - && pp == self.chips[x].phandle - { - self.chips[y].parent = Some(x); - self.chips[x].childs.push(y); - } - y += 1; - } - x += 1; - } - } - - fn init_inner3(&mut self, fdt: &fdt::Fdt, irq_desc: &mut [IrqDesc; 1024]) { - //run init - let mut queue = Vec::new(); - let mut irq_idx: usize = 0; - queue.push(self.root_idx); - while !queue.is_empty() { - let cur_idx = queue.pop().unwrap(); - queue.extend_from_slice(&self.chips[cur_idx].childs); - let virq = self.chips[cur_idx] - .ic - .irq_init(fdt, irq_desc, cur_idx, &mut irq_idx); - if let Ok(Some(virq)) = virq { - irq_desc[virq].basic.child_ic_idx = Some(cur_idx); - } - } - } -} - -pub struct IrqChipCore { - //TODO: support multi level interrupt constrollers - pub irq_chip_list: IrqChipList, - pub irq_desc: [IrqDesc; 1024], -} - -impl IrqChipCore { - pub fn irq_ack(&mut self) -> u32 { - self.irq_chip_list.chips[self.irq_chip_list.root_idx] - .ic - .irq_ack() - } - - pub fn irq_eoi(&mut self, virq: u32) { - let irq_desc = &self.irq_desc[virq as usize]; - let ic_idx = irq_desc.basic.ic_idx; - let hwirq = irq_desc.basic.ic_irq; - - self.irq_chip_list.chips[ic_idx].ic.irq_eoi(hwirq) - } - - pub fn irq_enable(&mut self, virq: u32) { - let irq_desc = &self.irq_desc[virq as usize]; - let ic_idx = irq_desc.basic.ic_idx; - let hwirq = irq_desc.basic.ic_irq; - - self.irq_chip_list.chips[ic_idx].ic.irq_enable(hwirq) - } - - #[allow(unused)] - pub fn irq_disable(&mut self, virq: u32) { - let irq_desc = &self.irq_desc[virq as usize]; - let ic_idx = irq_desc.basic.ic_idx; - let hwirq = irq_desc.basic.ic_irq; - - self.irq_chip_list.chips[ic_idx].ic.irq_disable(hwirq) - } - - pub fn irq_to_virq(&mut self, hwirq: u32) -> Option { - self.irq_chip_list.chips[self.irq_chip_list.root_idx] - .ic - .irq_to_virq(hwirq) - } - - pub fn init(&mut self, fdt: &Fdt) { - for i in 0..1024 { - self.irq_desc[i].basic.idx = i; - } - self.irq_chip_list.init_inner1(fdt); - self.irq_chip_list.init_inner2(); - self.irq_chip_list.init_inner3(fdt, &mut self.irq_desc); - } - - pub fn new_ic(ic_str: &str) -> Option> { - if ic_str.contains("arm,gic-v3") { - Some(Box::new(gicv3::GicV3::new())) - } else if ic_str.contains("arm,cortex-a15-gic") { - Some(Box::new(gic::GenericInterruptController::new())) - } else if ic_str.contains("brcm,bcm2836-l1-intc") { - Some(Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new())) - } else if ic_str.contains("brcm,bcm2836-armctrl-ic") { - Some(Box::new(irq_bcm2835::Bcm2835ArmInterruptController::new())) - } else { - log::warn!("no driver for interrupt controller {:?}", ic_str); - None - } - } -} - -const INIT_HANDLER: Option> = None; -const INIT_IRQ_DESC: IrqDesc = IrqDesc { - basic: IrqDescItem { - idx: 0, - ic_idx: 0, - ic_irq: 0, - child_ic_idx: None, - used: false, - }, - handler: INIT_HANDLER, -}; -pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore { - irq_chip_list: IrqChipList { - chips: Vec::new(), - root_phandle: 0, - root_idx: 0, - }, - irq_desc: [INIT_IRQ_DESC; 1024], -}; - -pub fn init(fdt: &Fdt) { - travel_interrupt_ctrl(fdt); - unsafe { - IRQ_CHIP.init(fdt); - } -} - -pub fn register_irq(virq: u32, handler: Box) { - if virq >= 1024 { - error!("irq {} exceed 1024!!!", virq); - return; - } - - unsafe { - if IRQ_CHIP.irq_desc[virq as usize].handler.is_some() { - error!("irq {} has already been registered!", virq); - return; - } - - IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler); +pub fn new_irqchip(ic_str: &str) -> Option> { + if ic_str.contains("arm,gic-v3") { + Some(Box::new(gicv3::GicV3::new())) + } else if ic_str.contains("arm,cortex-a15-gic") { + Some(Box::new(gic::GenericInterruptController::new())) + } else if ic_str.contains("brcm,bcm2836-l1-intc") { + Some(Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new())) + } else if ic_str.contains("brcm,bcm2836-armctrl-ic") { + Some(Box::new(irq_bcm2835::Bcm2835ArmInterruptController::new())) + } else { + log::warn!("no driver for interrupt controller {:?}", ic_str); + None } } diff --git a/src/arch/aarch64/device/mod.rs b/src/arch/aarch64/device/mod.rs index fcc96c132a..00abdf6167 100644 --- a/src/arch/aarch64/device/mod.rs +++ b/src/arch/aarch64/device/mod.rs @@ -1,4 +1,4 @@ -use crate::{dtb::DTB_BINARY, info}; +use crate::{dtb, dtb::DTB_BINARY, info}; pub mod cpu; pub mod generic_timer; @@ -11,7 +11,7 @@ pub unsafe fn init() { info!("IRQCHIP INIT"); let data = DTB_BINARY.get().unwrap(); let fdt = fdt::Fdt::new(data).unwrap(); - irqchip::init(&fdt); + dtb::irqchip::init(&fdt); info!("GIT INIT"); generic_timer::init(); } diff --git a/src/arch/aarch64/device/serial.rs b/src/arch/aarch64/device/serial.rs index db51de9d30..329d1bee57 100644 --- a/src/arch/aarch64/device/serial.rs +++ b/src/arch/aarch64/device/serial.rs @@ -3,8 +3,11 @@ use spin::Mutex; use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger}; -use super::irqchip::{register_irq, InterruptHandler, IRQ_CHIP}; -use crate::dtb::{diag_uart_range, DTB_BINARY}; +use crate::dtb::{ + diag_uart_range, + irqchip::{register_irq, InterruptHandler, IRQ_CHIP}, + DTB_BINARY, +}; use alloc::vec::Vec; use byteorder::{ByteOrder, BE}; use fdt::Fdt; diff --git a/src/arch/aarch64/init/device_tree/mod.rs b/src/arch/aarch64/init/device_tree/mod.rs deleted file mode 100644 index 45afe736cb..0000000000 --- a/src/arch/aarch64/init/device_tree/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -use byteorder::{ByteOrder, BE}; -use fdt::{node::NodeProperty, Fdt}; -use log::debug; - -pub fn travel_interrupt_ctrl(fdt: &Fdt) { - let root_intr_parent = fdt - .root() - .property("interrupt-parent") - .and_then(NodeProperty::as_usize) - .unwrap(); - debug!("root parent = 0x{:08x}", root_intr_parent); - for node in fdt.all_nodes() { - if node.property("interrupt-controller").is_some() { - let compatible = node.property("compatible").unwrap().as_str().unwrap(); - let phandle = node.property("phandle").unwrap().as_usize().unwrap(); - let intr_cells = node.interrupt_cells().unwrap(); - let _intr = node - .property("interrupt-parent") - .and_then(NodeProperty::as_usize); - let _intr_data = node.property("interrupts"); - - debug!( - "{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", - node.name, compatible, intr_cells, phandle - ); - if let Some(intr) = _intr { - if let Some(intr_data) = _intr_data { - debug!("interrupt-parent = 0x{:08x}", intr); - debug!("interrupts begin:"); - for chunk in intr_data.value.chunks(4) { - debug!("0x{:08x}, ", BE::read_u32(chunk)); - } - debug!("interrupts end"); - } - } - } - } -} diff --git a/src/arch/aarch64/init/mod.rs b/src/arch/aarch64/init/mod.rs deleted file mode 100644 index 16a16cdb31..0000000000 --- a/src/arch/aarch64/init/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod device_tree; diff --git a/src/arch/aarch64/interrupt/irq.rs b/src/arch/aarch64/interrupt/irq.rs index eccbe221cc..dab968a6b4 100644 --- a/src/arch/aarch64/interrupt/irq.rs +++ b/src/arch/aarch64/interrupt/irq.rs @@ -1,4 +1,4 @@ -use crate::device::irqchip::IRQ_CHIP; +use crate::dtb::irqchip::IRQ_CHIP; exception_stack!(irq_at_el0, |_stack| { let irq = IRQ_CHIP.irq_ack(); @@ -44,10 +44,6 @@ pub unsafe fn trigger(irq: u32) { IRQ_CHIP.irq_eoi(irq); } -pub unsafe fn acknowledge(_irq: usize) { - // TODO -} - /* pub unsafe fn irq_handler_gentimer(irq: u32) { GENTIMER.clear_irq(); diff --git a/src/arch/aarch64/interrupt/mod.rs b/src/arch/aarch64/interrupt/mod.rs index 5fee770a53..f3bf58b5e8 100644 --- a/src/arch/aarch64/interrupt/mod.rs +++ b/src/arch/aarch64/interrupt/mod.rs @@ -51,22 +51,7 @@ pub fn pause() { unsafe { asm!("nop") }; } -pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator + 'static { - 0..0 -} - pub fn bsp_apic_id() -> Option { //TODO None } - -#[inline] -pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> bool { - //TODO - true -} - -#[inline] -pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) { - //TODO -} diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 4c96a984c3..739cbbf854 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -33,9 +33,6 @@ pub mod stop; // Interrupt vectors pub mod vectors; -/// Early init support -pub mod init; - pub mod time; pub use ::rmm::AArch64Arch as CurrentRmmArch; diff --git a/src/arch/riscv64/device/irqchip/mod.rs b/src/arch/riscv64/device/irqchip/mod.rs new file mode 100644 index 0000000000..bb93c393ca --- /dev/null +++ b/src/arch/riscv64/device/irqchip/mod.rs @@ -0,0 +1,6 @@ +use crate::dtb::irqchip::InterruptController; +use alloc::boxed::Box; + +pub fn new_irqchip(_ic_str: &str) -> Option> { + None +} diff --git a/src/arch/riscv64/device/mod.rs b/src/arch/riscv64/device/mod.rs index e86c4c00e5..496249d394 100644 --- a/src/arch/riscv64/device/mod.rs +++ b/src/arch/riscv64/device/mod.rs @@ -5,6 +5,7 @@ use fdt::{ }; pub mod cpu; +pub mod irqchip; pub mod serial; fn string_property(name: &str) -> bool { diff --git a/src/arch/riscv64/interrupt/mod.rs b/src/arch/riscv64/interrupt/mod.rs index 8a8af53c3b..a44bb15024 100644 --- a/src/arch/riscv64/interrupt/mod.rs +++ b/src/arch/riscv64/interrupt/mod.rs @@ -15,16 +15,6 @@ pub use handler::InterruptStack; pub fn bsp_apic_id() -> Option { Some(0) } -pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator + 'static { - unimplemented!(); - 0..0 -} -pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> ! { - unimplemented!() -} -pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) -> ! { - unimplemented!() -} /// Clear interrupts #[inline(always)] diff --git a/src/dtb/irqchip.rs b/src/dtb/irqchip.rs new file mode 100644 index 0000000000..ececd51a07 --- /dev/null +++ b/src/dtb/irqchip.rs @@ -0,0 +1,269 @@ +use super::travel_interrupt_ctrl; +use crate::{ + arch, arch::device::irqchip::new_irqchip, cpu_set::LogicalCpuId, scheme::irq::irq_trigger, +}; +use alloc::{boxed::Box, vec::Vec}; +use byteorder::{ByteOrder, BE}; +use fdt::{node::NodeProperty, Fdt}; +use log::{debug, error}; +use syscall::{Error, Result, ENOENT}; + +pub trait InterruptHandler { + fn irq_handler(&mut self, irq: u32); +} + +pub trait InterruptController { + fn irq_init( + &mut self, + fdt: &Fdt, + irq_desc: &mut [IrqDesc; 1024], + ic_idx: usize, + irq_idx: &mut usize, + ) -> Result>; + fn irq_ack(&mut self) -> u32; + fn irq_eoi(&mut self, irq_num: u32); + fn irq_enable(&mut self, irq_num: u32); + #[allow(unused)] + fn irq_disable(&mut self, irq_num: u32); + fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result; + fn irq_to_virq(&mut self, hwirq: u32) -> Option; + fn irq_handler(&mut self, irq: u32); +} + +pub struct IrqChipItem { + pub phandle: u32, + pub parent_phandle: Option, + pub parent: Option, //parent idx in chiplist + pub childs: Vec, //child idx in chiplist + pub interrupts: Vec, + pub ic: Box, +} + +pub struct IrqChipList { + pub chips: Vec, + pub root_phandle: u32, + pub root_idx: usize, +} + +pub struct IrqDescItem { + pub idx: usize, + pub ic_idx: usize, //ic idx in irq chip list + pub child_ic_idx: Option, //ic idx in irq chip list + pub ic_irq: u32, //hwirq in ic + pub used: bool, +} + +pub struct IrqDesc { + pub basic: IrqDescItem, + pub handler: Option>, +} + +impl IrqChipList { + fn init_inner1(&mut self, fdt: &Fdt) { + let root_node = fdt.root(); + let mut idx = 0; + let intr = root_node.property("interrupt-parent").unwrap(); + + let root_intr_parent = intr.as_usize().unwrap() as u32; + debug!("root parent = 0x{:08x}", root_intr_parent); + self.root_phandle = root_intr_parent; + for node in fdt.all_nodes() { + if node.property("interrupt-controller").is_some() { + let compatible = node.property("compatible").unwrap().as_str().unwrap(); + let phandle = node.property("phandle").unwrap().as_usize().unwrap() as u32; + let intr_cells = node.interrupt_cells().unwrap(); + let _intr = node.property("interrupt-parent"); + let _intr_data = node.property("interrupts"); + + debug!( + "{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", + node.name, compatible, intr_cells, phandle + ); + let mut item = IrqChipItem { + phandle, + parent_phandle: None, + parent: None, + childs: Vec::new(), + interrupts: Vec::new(), + ic: new_irqchip(compatible).unwrap(), + }; + if let Some(intr) = _intr { + if let Some(intr_data) = _intr_data { + let intr = intr.as_usize().unwrap() as u32; + debug!("interrupt-parent = 0x{:08x}", intr); + item.parent_phandle = Some(intr); + debug!("interrupts begin:"); + for chunk in intr_data.value.chunks(4) { + debug!("0x{:08x}, ", BE::read_u32(chunk)); + item.interrupts.push(BE::read_u32(chunk)); + } + debug!("interrupts end"); + } + } + if item.phandle == root_intr_parent { + self.root_idx = idx as usize; + } + + self.chips.push(item); + + idx += 1; + } + } + } + + fn init_inner2(&mut self) { + let mut x = 0; + + while x < self.chips.len() { + let mut y = 0; + while y < self.chips.len() { + if x == y { + y += 1; + continue; + } + if let Some(pp) = self.chips[y].parent_phandle + && pp == self.chips[x].phandle + { + self.chips[y].parent = Some(x); + self.chips[x].childs.push(y); + } + y += 1; + } + x += 1; + } + } + + fn init_inner3(&mut self, fdt: &fdt::Fdt, irq_desc: &mut [IrqDesc; 1024]) { + //run init + let mut queue = Vec::new(); + let mut irq_idx: usize = 0; + queue.push(self.root_idx); + while !queue.is_empty() { + let cur_idx = queue.pop().unwrap(); + queue.extend_from_slice(&self.chips[cur_idx].childs); + let virq = self.chips[cur_idx] + .ic + .irq_init(fdt, irq_desc, cur_idx, &mut irq_idx); + if let Ok(Some(virq)) = virq { + irq_desc[virq].basic.child_ic_idx = Some(cur_idx); + } + } + } +} + +pub struct IrqChipCore { + //TODO: support multi level interrupt constrollers + pub irq_chip_list: IrqChipList, + pub irq_desc: [IrqDesc; 1024], +} + +impl IrqChipCore { + pub fn irq_ack(&mut self) -> u32 { + self.irq_chip_list.chips[self.irq_chip_list.root_idx] + .ic + .irq_ack() + } + + pub fn irq_eoi(&mut self, virq: u32) { + let irq_desc = &self.irq_desc[virq as usize]; + let ic_idx = irq_desc.basic.ic_idx; + let hwirq = irq_desc.basic.ic_irq; + + self.irq_chip_list.chips[ic_idx].ic.irq_eoi(hwirq) + } + + pub fn irq_enable(&mut self, virq: u32) { + let irq_desc = &self.irq_desc[virq as usize]; + let ic_idx = irq_desc.basic.ic_idx; + let hwirq = irq_desc.basic.ic_irq; + + self.irq_chip_list.chips[ic_idx].ic.irq_enable(hwirq) + } + + #[allow(unused)] + pub fn irq_disable(&mut self, virq: u32) { + let irq_desc = &self.irq_desc[virq as usize]; + let ic_idx = irq_desc.basic.ic_idx; + let hwirq = irq_desc.basic.ic_irq; + + self.irq_chip_list.chips[ic_idx].ic.irq_disable(hwirq) + } + + pub fn irq_to_virq(&mut self, hwirq: u32) -> Option { + self.irq_chip_list.chips[self.irq_chip_list.root_idx] + .ic + .irq_to_virq(hwirq) + } + + pub fn init(&mut self, fdt: &Fdt) { + for i in 0..1024 { + self.irq_desc[i].basic.idx = i; + } + self.irq_chip_list.init_inner1(fdt); + self.irq_chip_list.init_inner2(); + self.irq_chip_list.init_inner3(fdt, &mut self.irq_desc); + } +} + +pub unsafe fn acknowledge(_irq: usize) { + // TODO +} + +const INIT_HANDLER: Option> = None; +const INIT_IRQ_DESC: IrqDesc = IrqDesc { + basic: IrqDescItem { + idx: 0, + ic_idx: 0, + ic_irq: 0, + child_ic_idx: None, + used: false, + }, + handler: INIT_HANDLER, +}; +pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore { + irq_chip_list: IrqChipList { + chips: Vec::new(), + root_phandle: 0, + root_idx: 0, + }, + irq_desc: [INIT_IRQ_DESC; 1024], +}; + +pub fn init(fdt: &Fdt) { + travel_interrupt_ctrl(fdt); + unsafe { + IRQ_CHIP.init(fdt); + } +} + +pub fn register_irq(virq: u32, handler: Box) { + if virq >= 1024 { + error!("irq {} exceed 1024!!!", virq); + return; + } + + unsafe { + if IRQ_CHIP.irq_desc[virq as usize].handler.is_some() { + error!("irq {} has already been registered!", virq); + return; + } + + IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler); + } +} + +#[inline] +pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> bool { + //TODO + true +} + +#[inline] +pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) { + //TODO +} + +pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator + 'static { + error!("available_irqs_iter has been called"); + 0..0 +} diff --git a/src/dtb/mod.rs b/src/dtb/mod.rs index 49acb3cceb..2d216e827c 100644 --- a/src/dtb/mod.rs +++ b/src/dtb/mod.rs @@ -1,7 +1,11 @@ +pub mod irqchip; + use crate::startup::memory::{register_memory_region, BootloaderMemoryKind}; use alloc::vec::Vec; +use byteorder::{ByteOrder, BE}; use core::slice; use fdt::{node::NodeProperty, Fdt}; +use log::debug; use spin::once::Once; pub static DTB_BINARY: Once> = Once::new(); @@ -23,6 +27,41 @@ pub unsafe fn init(dtb: Option<(usize, usize)>) { } } +pub fn travel_interrupt_ctrl(fdt: &Fdt) { + let root_intr_parent = fdt + .root() + .property("interrupt-parent") + .and_then(NodeProperty::as_usize) + .unwrap(); + debug!("root parent = 0x{:08x}", root_intr_parent); + for node in fdt.all_nodes() { + if node.property("interrupt-controller").is_some() { + let compatible = node.property("compatible").unwrap().as_str().unwrap(); + let phandle = node.property("phandle").unwrap().as_usize().unwrap(); + let intr_cells = node.interrupt_cells().unwrap(); + let _intr = node + .property("interrupt-parent") + .and_then(NodeProperty::as_usize); + let _intr_data = node.property("interrupts"); + + debug!( + "{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", + node.name, compatible, intr_cells, phandle + ); + if let Some(intr) = _intr { + if let Some(intr_data) = _intr_data { + debug!("interrupt-parent = 0x{:08x}", intr); + debug!("interrupts begin:"); + for chunk in intr_data.value.chunks(4) { + debug!("0x{:08x}, ", BE::read_u32(chunk)); + } + debug!("interrupts end"); + } + } + } + } +} + #[allow(unused)] pub fn register_memory_ranges(dt: &Fdt) { for chunk in dt.memory().regions() { diff --git a/src/scheme/irq.rs b/src/scheme/irq.rs index 7fee52a47e..c153aa6b53 100644 --- a/src/scheme/irq.rs +++ b/src/scheme/irq.rs @@ -14,9 +14,13 @@ use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; use crate::context::file::InternalFlags; -use crate::arch::interrupt::{available_irqs_iter, bsp_apic_id, is_reserved, set_reserved}; +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +use crate::arch::interrupt::{available_irqs_iter, irq::acknowledge, is_reserved, set_reserved}; +#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] +use crate::dtb::irqchip::{acknowledge, available_irqs_iter, is_reserved, set_reserved}; use crate::{ + arch::interrupt::bsp_apic_id, cpu_set::LogicalCpuId, event, syscall::{ @@ -27,9 +31,6 @@ use crate::{ }, }; -#[cfg(not(target_arch = "riscv64"))] -use crate::interrupt::irq::acknowledge; - use super::{CallerCtx, GlobalSchemes, OpenResult}; /// IRQ queues @@ -330,7 +331,7 @@ impl crate::scheme::KernelScheme for IrqScheme { return Ok(0); } handle_ack.store(ack, Ordering::SeqCst); - #[cfg(not(target_arch = "riscv64"))] + unsafe { acknowledge(handle_irq as usize); }