diff --git a/src/arch/aarch64/device/generic_timer.rs b/src/arch/aarch64/device/generic_timer.rs index 7b34ff47de..fbdbbb305c 100644 --- a/src/arch/aarch64/device/generic_timer.rs +++ b/src/arch/aarch64/device/generic_timer.rs @@ -1,11 +1,15 @@ use alloc::boxed::Box; +use alloc::vec::Vec; +use byteorder::{ByteOrder, BE}; use crate::arch::device::irqchip::IRQ_CHIP; use crate::context::timeout; use crate::device::cpu::registers::control_regs; +use crate::init::device_tree::find_compatible_node; use crate::interrupt::irq::trigger; use crate::time; use crate::context; +use crate::dtb::DTB_BINARY; use super::irqchip::InterruptHandler; use super::irqchip::register_irq; @@ -21,9 +25,34 @@ bitflags! { pub unsafe fn init() { let mut timer = GenericTimer{ clk_freq: 0, reload_count: 0}; timer.init(); - //TODO: REMOVE HARD CODE IRQ NUMBER - register_irq(30, Box::new(timer)); - IRQ_CHIP.irq_enable(30); + let data = DTB_BINARY.get().unwrap(); + let fdt = fdt::DeviceTree::new(data).unwrap(); + if let Some(node) = find_compatible_node(&fdt, "arm,armv7-timer") { + let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap(); + let mut intr_data = Vec::new(); + for chunk in interrupts.data.chunks(4) { + let val = BE::read_u32(chunk); + intr_data.push(val); + } + let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx; + if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) { + let phandle = BE::read_u32(interrupt_parent.data); + let mut i = 0; + while i < IRQ_CHIP.irq_chip_list.chips.len() { + let item = &IRQ_CHIP.irq_chip_list.chips[i]; + if item.phandle == phandle { + ic_idx = i; + break; + } + i += 1; + } + } + //PHYS_NONSECURE_PPI only + let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 1).unwrap(); + println!("generic_timer virq = {}", virq); + register_irq(virq as u32, Box::new(timer)); + IRQ_CHIP.irq_enable(virq as u32); + } } pub struct GenericTimer { diff --git a/src/arch/aarch64/device/irqchip/gic.rs b/src/arch/aarch64/device/irqchip/gic.rs index 771f44590c..570f06315a 100644 --- a/src/arch/aarch64/device/irqchip/gic.rs +++ b/src/arch/aarch64/device/irqchip/gic.rs @@ -6,7 +6,7 @@ use byteorder::{ByteOrder, BE}; use crate::{device::io_mmap, init::device_tree::find_compatible_node}; use syscall::{Result, error::{Error, EINVAL}}; -use super::InterruptController; +use super::{InterruptController, IrqDesc}; static GICD_CTLR: u32 = 0x000; static GICD_TYPER: u32 = 0x004; @@ -24,6 +24,7 @@ static GICC_PMR: u32 = 0x0004; pub struct GenericInterruptController { gic_dist_if: GicDistIf, gic_cpu_if: GicCpuIf, + irq_range: (usize, usize), } impl GenericInterruptController { @@ -37,18 +38,13 @@ impl GenericInterruptController { address: 0, }; - GenericInterruptController { gic_dist_if, gic_cpu_if } + GenericInterruptController { gic_dist_if, gic_cpu_if, irq_range: (0, 0) } } - pub fn parse(fdt: Option<&DeviceTree>) -> Result<(usize, usize, usize, usize)> { - match fdt { - None => Err(Error::new(EINVAL)), - Some(dtb) => { - if let Some(node) = find_compatible_node(dtb, "arm,cortex-a15-gic") { - return GenericInterruptController::parse_inner(&node); - } else { - return Err(Error::new(EINVAL)); - } - } + pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, usize, usize)> { + if let Some(node) = find_compatible_node(fdt, "arm,cortex-a15-gic") { + return GenericInterruptController::parse_inner(&node); + } else { + return Err(Error::new(EINVAL)); } } fn parse_inner(node: &Node) -> Result<(usize, usize, usize, usize)> { @@ -79,9 +75,11 @@ impl GenericInterruptController { } impl InterruptController for GenericInterruptController { - fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()> { - let (dist_addr, dist_size, cpu_addr, cpu_size) = - GenericInterruptController::parse(fdt).unwrap(); + fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result> { + let (dist_addr, dist_size, cpu_addr, cpu_size) = match GenericInterruptController::parse(fdt) { + Ok(regs) => regs, + Err(err) => return Err(err), + }; unsafe { //TODO: do kernel memory map using node.ranges @@ -98,9 +96,23 @@ impl InterruptController for GenericInterruptController { self.gic_cpu_if.write(GICC_CTLR, 1); // Set CPU0's Interrupt Priority Mask self.gic_cpu_if.write(GICC_PMR, 0xff); - } - Ok(()) + let idx = *irq_idx; + let cnt = if self.gic_dist_if.nirqs > 1024 { 1024 } else { self.gic_dist_if.nirqs as usize }; + let mut i: usize = 0; + //only support linear irq map now. + while i < cnt && (idx + i < 1024) { + irq_desc[idx + i].basic.ic_idx = ic_idx; + irq_desc[idx + i].basic.ic_irq = i as u32; + irq_desc[idx + i].basic.used = true; + + i += 1; + } + + println!("gic irq_range = ({}, {})", idx, idx + cnt); + self.irq_range = (idx, idx + cnt); + *irq_idx = idx + cnt; + Ok(None) } fn irq_ack(&mut self) -> u32 { unsafe { self.gic_cpu_if.irq_ack() } @@ -114,6 +126,33 @@ impl InterruptController for GenericInterruptController { fn irq_disable(&mut self, irq_num: u32) { unsafe { self.gic_dist_if.irq_disable(irq_num) } } + fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result { + let mut off: usize = 0; + let mut i = 0; + for chunk in irq_data.chunks(3) { + if i == idx { + match chunk[0] { + 0 => off = chunk[1] as usize + 32, //SPI + 1 => off = chunk[1] as usize + 16, //PPI, + _ => return Err(Error::new(EINVAL)), + } + off += self.irq_range.0; + return Ok(off); + } + i += 1; + } + Err(Error::new(EINVAL)) + } + fn irq_to_virq(&mut self, hwirq: u32) -> Option { + if hwirq >= self.gic_dist_if.nirqs { + None + } else { + Some(self.irq_range.0 + hwirq as usize) + } + } + fn irq_handler(&mut self, irq: u32) { + + } } pub struct GicDistIf { diff --git a/src/arch/aarch64/device/irqchip/irq_bcm2835.rs b/src/arch/aarch64/device/irqchip/irq_bcm2835.rs index e5084ec221..522814953d 100644 --- a/src/arch/aarch64/device/irqchip/irq_bcm2835.rs +++ b/src/arch/aarch64/device/irqchip/irq_bcm2835.rs @@ -1,12 +1,15 @@ use core::ptr::{read_volatile, write_volatile}; +use alloc::boxed::Box; +use alloc::vec::Vec; use byteorder::{ByteOrder, BE}; use fdt::{DeviceTree, Node}; +use crate::arch::device::irqchip::IRQ_CHIP; use crate::{device::io_mmap, init::device_tree::find_compatible_node}; use syscall::{Result, error::{Error, EINVAL}}; -use super::InterruptController; +use super::{InterruptController, IrqDesc, InterruptHandler}; #[inline(always)] fn ffs(num: u32) -> u32 { @@ -39,49 +42,67 @@ fn ffs(num: u32) -> u32 { r } -const PENDING_0: u32 = 0x200; -const PENDING_1: u32 = 0x204; -const PENDING_2: u32 = 0x208; -const FIQ_CTRL: u32 = 0x20c; -const ENABLE_0: u32 = 0x218; -const ENABLE_1: u32 = 0x210; -const ENABLE_2: u32 = 0x214; -const DISABLE_0: u32 = 0x224; -const DISABLE_1: u32 = 0x21c; -const DISABLE_2: u32 = 0x220; - +const PENDING_0: u32 = 0x0; +const PENDING_1: u32 = 0x4; +const PENDING_2: u32 = 0x8; +const FIQ_CTRL: u32 = 0xc; +const ENABLE_0: u32 = 0x18; +const ENABLE_1: u32 = 0x10; +const ENABLE_2: u32 = 0x14; +const DISABLE_0: u32 = 0x24; +const DISABLE_1: u32 = 0x1c; +const DISABLE_2: u32 = 0x20; pub struct Bcm2835ArmInterruptController { pub address: usize, + pub irq_range: (usize, usize), } impl Bcm2835ArmInterruptController { pub fn new() -> Self { - Bcm2835ArmInterruptController { address: 0 } + Bcm2835ArmInterruptController { address: 0, irq_range: (0, 0) } } - pub fn parse(fdt: Option<&DeviceTree>) -> Result<(usize, usize)> { - match fdt { - //TODO: remove hard code for qemu-virt - None => Err(Error::new(EINVAL)), - Some(dtb) => { - //TODO: try to parse dtb using stable library - if let Some(node) = find_compatible_node(dtb, "brcm,bcm2835-armctrl-ic") { - return Bcm2835ArmInterruptController::parse_inner(&node); - } else { - return Err(Error::new(EINVAL)); - } - } + pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, Option)> { + //TODO: try to parse dtb using stable library + if let Some(node) = find_compatible_node(fdt, "brcm,bcm2836-armctrl-ic") { + return unsafe { Bcm2835ArmInterruptController::parse_inner(&node) }; + } else { + return Err(Error::new(EINVAL)); } } - fn parse_inner(node: &Node) -> Result<(usize, usize)> { + unsafe fn parse_inner(node: &Node) -> Result<(usize, usize, Option)> { //assert address_cells == 0x1, size_cells == 0x1 let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); let (base, size) = reg.data.split_at(4); let base = BE::read_u32(base); let size = BE::read_u32(size); + let mut ret_virq = None; - Ok((base as usize, size as usize)) + if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) { + let phandle = BE::read_u32(interrupt_parent.data); + let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap(); + let mut intr_data = Vec::new(); + for chunk in interrupts.data.chunks(4) { + let val = BE::read_u32(chunk); + intr_data.push(val); + } + let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx; + let mut i = 0; + while i < IRQ_CHIP.irq_chip_list.chips.len() { + let item = &IRQ_CHIP.irq_chip_list.chips[i]; + if item.phandle == phandle { + ic_idx = i; + break; + } + i += 1; + } + //PHYS_NONSECURE_PPI only + let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 0).unwrap(); + println!("bcm2835arm_ctrl virq = {}", virq); + ret_virq = Some(virq); + } + Ok((base as usize, size as usize, ret_virq)) } unsafe fn init(&mut self) { @@ -105,38 +126,55 @@ impl Bcm2835ArmInterruptController { } impl InterruptController for Bcm2835ArmInterruptController { - fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()> { - let (base, size) = match Bcm2835ArmInterruptController::parse(fdt) { - Ok((a, b)) => (a, b), + fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result> { + let (base, size, virq) = match Bcm2835ArmInterruptController::parse(fdt) { + Ok((a, b, c)) => (a, b, c), Err(_) => return Err(Error::new(EINVAL)), }; unsafe { io_mmap(base, size); - self.address = base; + self.address = base + crate::PHYS_OFFSET; self.init(); + let idx = *irq_idx; + let cnt = 3 << 5; //3 * 32 irqs, basic == 8, reg1 = 32, reg2 = 32 + let mut i: usize = 0; + //only support linear irq map now. + while i < cnt && (idx + i < 1024) { + irq_desc[idx + i].basic.ic_idx = ic_idx; + irq_desc[idx + i].basic.ic_irq = i as u32; + irq_desc[idx + i].basic.used = true; + + i += 1; + } + + println!("bcm2835 irq_range = ({}, {})", idx, idx + cnt); + self.irq_range = (idx, idx + cnt); + *irq_idx = idx + cnt; } - Ok(()) + Ok(virq) } fn irq_ack(&mut self) -> u32 { //TODO: support smp self.read(LOCAL_IRQ_PENDING + 4 * cpu) - //assert cpu == 0 - let sources = unsafe { self.read(PENDING_0) }; + let sources = unsafe { self.read(PENDING_0) & 0x3ff }; let pending_num = ffs(sources) - 1; match pending_num { - num@0..=7 => return num, + num@0..=7 => { + println!("inner interrupt {}", num); + return num + }, 8 => { let sources1 = unsafe { self.read(PENDING_1) }; let irq_0_31 = ffs(sources1) - 1; - return irq_0_31; + return irq_0_31 + 32; }, 9 => { let sources2 = unsafe { self.read(PENDING_2) }; let irq_32_63 = ffs(sources2) - 1; - return irq_32_63 + 32; + return irq_32_63 + 64; }, num => { println!("unexpected irq pending in BASIC PENDING: {}", num); @@ -150,10 +188,97 @@ impl InterruptController for Bcm2835ArmInterruptController { } fn irq_enable(&mut self, irq_num: u32) { - + println!("bcm2835 enable {} {}", irq_num, irq_num & 0x1f); + match irq_num { + num @0..=31 => { + let val = 1 << num; + unsafe { self.write(ENABLE_0, val); } + }, + num @32..=63 => { + let val = 1 << (num & 0x1f); + unsafe { self.write(ENABLE_1, val); } + }, + num @64..=95 => { + let val = 1 << (num & 0x1f); + unsafe { self.write(ENABLE_2, val); } + }, + _ => return, + } } fn irq_disable(&mut self, irq_num: u32) { + match irq_num { + num @0..=31 => { + let val = 1 << num; + unsafe { self.write(DISABLE_0, val); } + }, + num @32..=63 => { + let val = 1 << (num & 0x1f); + unsafe { self.write(DISABLE_1, val); } + }, + num @64..=95 => { + let val = 1 << (num & 0x1f); + unsafe { self.write(DISABLE_2, val); } + }, + _ => return, + } } + fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result { + //assert interrupt-cells == 0x2 + let mut off: usize = 0; + let mut i = 0; + //assert interrupt-cells == 0x2 + for chunk in irq_data.chunks(2) { + if i == idx { + let bank = chunk[0] as usize; + let irq = chunk[1] as usize; + //TODO: check bank && irq + let hwirq = bank << 5 | irq; + off = hwirq + self.irq_range.0; + return Ok(off); + } + i += 1; + } + Err(Error::new(EINVAL)) + } + fn irq_to_virq(&mut self, hwirq: u32) -> Option { + if hwirq > 95 { + None + } else { + Some(self.irq_range.0 + hwirq as usize) + } + } + + fn irq_handler(&mut self, irq: u32) { + + unsafe { + let irq = self.irq_ack(); + if let Some(virq) = self.irq_to_virq(irq) && virq < 1024 { + if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler { + handler.irq_handler(virq as u32); + } + } else { + println!("unexpected irq num {}", irq); + } + self.irq_eoi(irq); + } + } +} + +impl InterruptHandler for Bcm2835ArmInterruptController { + fn irq_handler(&mut self, irq: u32) { + + unsafe { + let irq = self.irq_ack(); + if let Some(virq) = self.irq_to_virq(irq) && virq < 1024 { + if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler { + handler.irq_handler(virq as u32); + } + } else { + println!("unexpected irq num {}", irq); + } + self.irq_eoi(irq); + } + } } diff --git a/src/arch/aarch64/device/irqchip/irq_bcm2836.rs b/src/arch/aarch64/device/irqchip/irq_bcm2836.rs index 5f6813ec60..d9e135d91e 100644 --- a/src/arch/aarch64/device/irqchip/irq_bcm2836.rs +++ b/src/arch/aarch64/device/irqchip/irq_bcm2836.rs @@ -1,4 +1,4 @@ -use core::ptr::{read_volatile, write_volatile}; +use core::{ptr::{read_volatile, write_volatile}, arch::asm}; use byteorder::{ByteOrder, BE}; use fdt::{DeviceTree, Node}; @@ -6,26 +6,26 @@ use fdt::{DeviceTree, Node}; use crate::{device::io_mmap, init::device_tree::find_compatible_node}; use syscall::{Result, error::{Error, EINVAL}}; -use super::InterruptController; +use super::{InterruptController, IrqDesc}; -static LOCAL_CONTROL: u32 = 0x000; -static LOCAL_PRESCALER: u32 = 0x008; -static LOCAL_GPU_ROUTING: u32 = 0x00C; -static LOCAL_TIMER_INT_CONTROL0: u32 = 0x040; -static LOCAL_IRQ_PENDING: u32 = 0x060; -static LOCAL_FIQ_PENDING: u32 = 0x070; +const LOCAL_CONTROL: u32 = 0x000; +const LOCAL_PRESCALER: u32 = 0x008; +const LOCAL_GPU_ROUTING: u32 = 0x00C; +const LOCAL_TIMER_INT_CONTROL0: u32 = 0x040; +const LOCAL_IRQ_PENDING: u32 = 0x060; +const LOCAL_FIQ_PENDING: u32 = 0x070; -static LOCAL_IRQ_CNTPSIRQ: u32 = 0x0; -static LOCAL_IRQ_CNTPNSIRQ: u32 = 0x1; -static LOCAL_IRQ_CNTHPIRQ: u32 = 0x2; -static LOCAL_IRQ_CNTVIRQ: u32 = 0x3; -static LOCAL_IRQ_MAILBOX0: u32 = 0x4; -static LOCAL_IRQ_MAILBOX1: u32 = 0x5; -static LOCAL_IRQ_MAILBOX2: u32 = 0x6; -static LOCAL_IRQ_MAILBOX3: u32 = 0x7; -static LOCAL_IRQ_GPU_FAST: u32 = 0x8; -static LOCAL_IRQ_PMU_FAST: u32 = 0x9; -static LOCAL_IRQ_LAST: u32 = 0x9; +const LOCAL_IRQ_CNTPSIRQ: u32 = 0x0; +const LOCAL_IRQ_CNTPNSIRQ: u32 = 0x1; +const LOCAL_IRQ_CNTHPIRQ: u32 = 0x2; +const LOCAL_IRQ_CNTVIRQ: u32 = 0x3; +const LOCAL_IRQ_MAILBOX0: u32 = 0x4; +const LOCAL_IRQ_MAILBOX1: u32 = 0x5; +const LOCAL_IRQ_MAILBOX2: u32 = 0x6; +const LOCAL_IRQ_MAILBOX3: u32 = 0x7; +const LOCAL_IRQ_GPU_FAST: u32 = 0x8; +const LOCAL_IRQ_PMU_FAST: u32 = 0x9; +const LOCAL_IRQ_LAST: u32 = LOCAL_IRQ_PMU_FAST; #[inline(always)] fn ffs(num: u32) -> u32 { @@ -60,25 +60,21 @@ fn ffs(num: u32) -> u32 { pub struct Bcm2836ArmInterruptController { pub address: usize, + pub irq_range: (usize, usize), + pub active_cpu: u32, } impl Bcm2836ArmInterruptController { pub fn new() -> Self { - Bcm2836ArmInterruptController { address: 0 } + Bcm2836ArmInterruptController { address: 0, irq_range: (0, 0), active_cpu: 0 } } - pub fn parse(fdt: Option<&DeviceTree>) -> Result<(usize, usize)> { - match fdt { - //TODO: remove hard code for qemu-virt - None => Err(Error::new(EINVAL)), - Some(dtb) => { - //TODO: try to parse dtb using stable library - if let Some(node) = find_compatible_node(dtb, "brcm,bcm2836-l1-intc") { - return Bcm2836ArmInterruptController::parse_inner(&node); - } else { - return Err(Error::new(EINVAL)); - } - } + pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize)> { + //TODO: try to parse dtb using stable library + if let Some(node) = find_compatible_node(fdt, "brcm,bcm2836-l1-intc") { + return Bcm2836ArmInterruptController::parse_inner(&node); + } else { + return Err(Error::new(EINVAL)); } } fn parse_inner(node: &Node) -> Result<(usize, usize)> { @@ -97,8 +93,9 @@ impl Bcm2836ArmInterruptController { self.write(LOCAL_CONTROL, 0x0); self.write(LOCAL_PRESCALER, 0x8000_0000); - //routing all irq to core0 - self.write(LOCAL_GPU_ROUTING, 0x0); + //routing all irq to core + self.write(LOCAL_GPU_ROUTING, self.active_cpu); + println!("routing all irq to core {}", self.active_cpu); println!("IRQ BCM2836 END"); } @@ -113,7 +110,7 @@ impl Bcm2836ArmInterruptController { } impl InterruptController for Bcm2836ArmInterruptController { - fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()> { + fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result> { let (base, size) = match Bcm2836ArmInterruptController::parse(fdt) { Ok((a, b)) => (a, b), Err(_) => return Err(Error::new(EINVAL)), @@ -121,18 +118,37 @@ impl InterruptController for Bcm2836ArmInterruptController { unsafe { io_mmap(base, size); - self.address = base; + self.address = base + crate::PHYS_OFFSET; + let mut cpuid: usize = 0; + asm!("mrs {}, mpidr_el1", out(reg) cpuid); + self.active_cpu = cpuid as u32 & 0x3; self.init(); + let idx = *irq_idx; + let cnt = LOCAL_IRQ_LAST as usize; + let mut i: usize = 0; + //only support linear irq map now. + while i < cnt && (idx + i < 1024) { + irq_desc[idx + i].basic.ic_idx = ic_idx; + irq_desc[idx + i].basic.ic_irq = i as u32; + irq_desc[idx + i].basic.used = true; + + i += 1; + } + + println!("bcm2836 irq_range = ({}, {})", idx, idx + cnt); + self.irq_range = (idx, idx + cnt); + *irq_idx = idx + cnt; } - Ok(()) + Ok(None) } fn irq_ack(&mut self) -> u32 { - //TODO: support smp self.read(LOCAL_IRQ_PENDING + 4 * cpu) - //assert cpu == 0 - let sources = unsafe { self.read(LOCAL_IRQ_PENDING) }; + let mut cpuid: usize = 0; + unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); } + let mut cpu = cpuid as u32 & 0x3; + let sources: u32 = unsafe { self.read(LOCAL_IRQ_PENDING + 4 * cpu) }; ffs(sources) - 1 } @@ -141,10 +157,64 @@ impl InterruptController for Bcm2836ArmInterruptController { } fn irq_enable(&mut self, irq_num: u32) { - + match irq_num { + LOCAL_IRQ_CNTPNSIRQ => unsafe { + let mut cpuid: usize = 0; + unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); } + let mut cpu = cpuid as u32 & 0x3; + let mut reg_val = self.read(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu); + reg_val |= 0x2; + self.write(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu, reg_val); + }, + LOCAL_IRQ_GPU_FAST => { + //GPU IRQ always enable + }, + _ => { + //ignore + } + } } fn irq_disable(&mut self, irq_num: u32) { + match irq_num { + LOCAL_IRQ_CNTPNSIRQ => unsafe { + let mut cpuid: usize = 0; + unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); } + let mut cpu = cpuid as u32 & 0x3; + let mut reg_val = self.read(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu); + reg_val &= !0x2; + self.write(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu, reg_val); + }, + LOCAL_IRQ_GPU_FAST => { + //GPU IRQ always enable + }, + _ => { + //ignore + } + } + } + fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result { + let mut off: usize = 0; + let mut i = 0; + //assert interrupt-cells == 0x2 + for chunk in irq_data.chunks(2) { + if i == idx { + off = chunk[0] as usize + self.irq_range.0; + return Ok(off); + } + i += 1; + } + Err(Error::new(EINVAL)) + } + fn irq_to_virq(&mut self, hwirq: u32) -> Option { + if hwirq > LOCAL_IRQ_LAST { + None + } else { + Some(self.irq_range.0 + hwirq as usize) + } + } + + fn irq_handler(&mut self, irq: u32) { } } diff --git a/src/arch/aarch64/device/irqchip/mod.rs b/src/arch/aarch64/device/irqchip/mod.rs index 707feaaca3..1c394b041b 100644 --- a/src/arch/aarch64/device/irqchip/mod.rs +++ b/src/arch/aarch64/device/irqchip/mod.rs @@ -1,79 +1,263 @@ -use alloc::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, vec::Vec, string::{String, ToString}}; +use byteorder::{ByteOrder, BE}; use syscall::Result; use fdt::DeviceTree; +use crate::init::device_tree::travel_interrupt_ctrl; + mod gic; mod irq_bcm2835; mod irq_bcm2836; +pub const IRQ_TYPE_NONE: u32 = 0; +pub const IRQ_TYPE_EDGE_RISING: u32 = 1; +pub const IRQ_TYPE_EDGE_FALLING: u32 = 2; +pub const IRQ_TYPE_EDGE: u32 = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; //both rising && failling +pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4; +pub const IRQ_TYPE_LEVEL_LOW: u32 = 8; + pub trait InterruptController { - fn irq_init(&mut self, fdt: Option<&DeviceTree>) -> Result<()>; + fn irq_init(&mut self, fdt: &DeviceTree, 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); 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 compatible: String, + pub phandle: u32, + pub parent_phandle: Option, + pub intr_cell_size: u32, + 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::DeviceTree) { + let root_node = fdt.nodes().nth(0).unwrap(); + let mut idx = 0; + let intr = root_node.properties().find(|p| p.name.contains("interrupt-parent")).unwrap(); + + let root_intr_parent = BE::read_u32(&intr.data); + println!("root parent = 0x{:08x}", root_intr_parent); + self.root_phandle = root_intr_parent; + for node in fdt.nodes() { + if node.properties().find(|p| p.name.contains("interrupt-controller")).is_some() { + let compatible = node.properties().find(|p| p.name.contains("compatible")).unwrap(); + let phandle = node.properties().find(|p| p.name.contains("phandle")).unwrap(); + let intr_cells = node.properties().find(|p| p.name.contains("#interrupt-cells")).unwrap(); + let _intr = node.properties().find(|p| p.name.contains("interrupt-parent")); + let _intr_data = node.properties().find(|p| p.name.contains("interrupts")); + + let s = core::str::from_utf8(compatible.data).unwrap(); + println!("{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", node.name, s, BE::read_u32(intr_cells.data), + BE::read_u32(phandle.data)); + let mut item = IrqChipItem { + compatible: s.to_string(), + phandle: BE::read_u32(phandle.data), + parent_phandle: None, + intr_cell_size: BE::read_u32(intr_cells.data), + parent: None, + childs: Vec::new(), + interrupts: Vec::new(), + ic: IrqChipCore::new_ic(&s).unwrap(), + }; + if let Some(intr) = _intr { + if let Some(intr_data) = _intr_data { + println!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data)); + item.parent_phandle = Some(BE::read_u32(intr.data)); + println!("interrupts begin:"); + for chunk in intr_data.data.chunks(4) { + print!("0x{:08x}, ", BE::read_u32(chunk)); + item.interrupts.push(BE::read_u32(chunk)); + } + println!("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; + let mut y = 0; + + while x < self.chips.len() { + 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::DeviceTree, 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 ic: Vec>, - pub ic_idx: usize, + pub irq_chip_list: IrqChipList, pub handlers: [Option>; 1024], + pub irq_desc: [IrqDesc; 1024], } impl IrqChipCore { pub fn irq_ack(&mut self) -> u32 { - self.ic[self.ic_idx].irq_ack() + self.irq_chip_list.chips[self.irq_chip_list.root_idx].ic.irq_ack() } - pub fn irq_eoi(&mut self, irq_num: u32) { - self.ic[self.ic_idx].irq_eoi(irq_num) + 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, irq_num: u32) { - self.ic[self.ic_idx].irq_enable(irq_num) + 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) } - pub fn irq_disable(&mut self, irq_num: u32) { - self.ic[self.ic_idx].irq_disable(irq_num) + 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: &DeviceTree) { + 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,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 { + 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 { - ic: Vec::new(), - ic_idx: 0, + irq_chip_list: IrqChipList { + chips: Vec::new(), + root_phandle: 0, + root_idx: 0, + }, handlers: [INIT_HANDLER; 1024], + irq_desc: [INIT_IRQ_DESC; 1024], }; -pub fn init(fdt: Option<&DeviceTree>) { + +pub fn init(fdt: &DeviceTree) { + travel_interrupt_ctrl(fdt); unsafe { - let ic = Box::new(gic::GenericInterruptController::new()); - IRQ_CHIP.ic.push(ic); - let ic = Box::new(irq_bcm2836::Bcm2836ArmInterruptController::new()); - IRQ_CHIP.ic.push(ic); - for ic in IRQ_CHIP.ic.iter_mut() { - let _ = ic.irq_init(fdt); - } + IRQ_CHIP.init(fdt); } } -pub fn register_irq(irq: u32, handler: Box) { - if irq >= 1024 { - println!("irq {} exceed 1024!!!", {irq}); +pub fn register_irq(virq: u32, handler: Box) { + if virq >= 1024 { + println!("irq {} exceed 1024!!!", virq); return ; } unsafe { - if let Some(_) = IRQ_CHIP.handlers[irq as usize] { - println!("irq {} has already been registered!", irq); + if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq as usize].handler { + println!("irq {} has already been registered!", virq); return ; } - IRQ_CHIP.handlers[irq as usize] = Some(handler); + IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler); } } diff --git a/src/arch/aarch64/device/mod.rs b/src/arch/aarch64/device/mod.rs index 2b4cd9eb3f..f1435af781 100644 --- a/src/arch/aarch64/device/mod.rs +++ b/src/arch/aarch64/device/mod.rs @@ -1,3 +1,5 @@ +use core::arch::asm; + use crate::memory::Frame; use crate::paging::{KernelMapper, PhysicalAddress, Page, PageFlags, VirtualAddress}; use crate::dtb::DTB_BINARY; @@ -12,17 +14,16 @@ pub mod uart_pl011; pub unsafe fn init() { println!("IRQCHIP INIT"); let data = DTB_BINARY.get().unwrap(); - if data.len() == 0 { - irqchip::init(None); - } else { - let fdt = fdt::DeviceTree::new(data).unwrap(); - irqchip::init(Some(&fdt)); - } + let fdt = fdt::DeviceTree::new(data).unwrap(); + irqchip::init(&fdt); println!("GIT INIT"); generic_timer::init(); } pub unsafe fn init_noncore() { + let mut daif: usize = 0; + asm!("mrs {0}, daif", out(reg) daif); + println!("daif = 0x{:08x}", daif); println!("SERIAL INIT"); serial::init(); println!("RTC INIT"); diff --git a/src/arch/aarch64/device/serial.rs b/src/arch/aarch64/device/serial.rs index c7e6960158..7b22a109e5 100644 --- a/src/arch/aarch64/device/serial.rs +++ b/src/arch/aarch64/device/serial.rs @@ -5,6 +5,10 @@ use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger}; use crate::init::device_tree; use super::irqchip::{register_irq, IRQ_CHIP, InterruptHandler}; +use crate::dtb::DTB_BINARY; +use byteorder::{ByteOrder, BE}; +use crate::init::device_tree::find_compatible_node; +use alloc::vec::Vec; pub static COM1: Mutex> = Mutex::new(None); @@ -39,10 +43,37 @@ pub unsafe fn init_early(dtb_base: usize, dtb_size: usize) { } pub unsafe fn init() { + println!("test 1"); if let Some(ref mut serial_port) = *COM1.lock() { + serial_port.receive(); serial_port.init(true); - register_irq(33, Box::new(Com1Irq {})); - // Enable interrupt at GIC distributor - unsafe { IRQ_CHIP.irq_enable(33); } + } + println!("test 2"); + let data = DTB_BINARY.get().unwrap(); + let fdt = fdt::DeviceTree::new(data).unwrap(); + if let Some(node) = find_compatible_node(&fdt, "arm,pl011") { + let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap(); + let mut intr_data = Vec::new(); + for chunk in interrupts.data.chunks(4) { + let val = BE::read_u32(chunk); + intr_data.push(val); + } + let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx; + if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) { + let phandle = BE::read_u32(interrupt_parent.data); + let mut i = 0; + while i < IRQ_CHIP.irq_chip_list.chips.len() { + let item = &IRQ_CHIP.irq_chip_list.chips[i]; + if item.phandle == phandle { + ic_idx = i; + break; + } + i += 1; + } + } + let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 0).unwrap(); + println!("serial_port virq = {}", virq); + register_irq(virq as u32, Box::new(Com1Irq {})); + IRQ_CHIP.irq_enable(virq as u32); } } diff --git a/src/arch/aarch64/init/device_tree/mod.rs b/src/arch/aarch64/init/device_tree/mod.rs index 29712d3cad..50cea53ab7 100644 --- a/src/arch/aarch64/init/device_tree/mod.rs +++ b/src/arch/aarch64/init/device_tree/mod.rs @@ -22,6 +22,37 @@ pub fn root_cell_sz(dt: &fdt::DeviceTree) -> Option<(u32, u32)> { Some((BE::read_u32(&size_cells.data), BE::read_u32(&size_cells.data))) } +pub fn travel_interrupt_ctrl(fdt: &fdt::DeviceTree) { + let root_node = fdt.nodes().nth(0).unwrap(); + let intr = root_node.properties().find(|p| p.name.contains("interrupt-parent")).unwrap(); + + let root_intr_parent = BE::read_u32(&intr.data); + println!("root parent = 0x{:08x}", root_intr_parent); + for node in fdt.nodes() { + if node.properties().find(|p| p.name.contains("interrupt-controller")).is_some() { + let compatible = node.properties().find(|p| p.name.contains("compatible")).unwrap(); + let phandle = node.properties().find(|p| p.name.contains("phandle")).unwrap(); + let intr_cells = node.properties().find(|p| p.name.contains("#interrupt-cells")).unwrap(); + let _intr = node.properties().find(|p| p.name.contains("interrupt-parent")); + let _intr_data = node.properties().find(|p| p.name.contains("interrupts")); + + let s = core::str::from_utf8(compatible.data).unwrap(); + println!("{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", node.name, s, BE::read_u32(intr_cells.data), + BE::read_u32(phandle.data)); + if let Some(intr) = _intr { + if let Some(intr_data) = _intr_data { + println!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data)); + println!("interrupts begin:"); + for chunk in intr_data.data.chunks(4) { + print!("0x{:08x}, ", BE::read_u32(chunk)); + } + println!("interrupts end"); + } + } + } + } +} + fn memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usize, ranges: &mut [(usize, usize); 10]) -> usize { let (memory_node, _memory_cells) = dt.find_node("/memory").unwrap(); diff --git a/src/arch/aarch64/interrupt/irq.rs b/src/arch/aarch64/interrupt/irq.rs index bfccbd9de6..a8016c9290 100644 --- a/src/arch/aarch64/interrupt/irq.rs +++ b/src/arch/aarch64/interrupt/irq.rs @@ -1,34 +1,42 @@ -use crate::context; -use crate::context::timeout; //use crate::device::generic_timer::{GENTIMER}; use crate::device::irqchip::IRQ_CHIP; -use crate::device::serial::{COM1}; -use crate::time; +use crate::device::serial::COM1; -use crate::{exception_stack}; +pub struct IrqDesc { + pub virq: u32, + pub hwirq: u32, +} exception_stack!(irq_at_el0, |stack| { let irq = IRQ_CHIP.irq_ack(); - if irq >= 1024 { - println!("unexpected irq num {}", irq); - } else { - if let Some(handler) = &mut IRQ_CHIP.handlers[irq as usize] { - handler.irq_handler(irq); + //println!("el0 irq num {}", irq); + if let Some(virq) = IRQ_CHIP.irq_to_virq(irq) && virq < 1024 { + if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler { + handler.irq_handler(virq as u32); + } else if let Some(ic_idx) = IRQ_CHIP.irq_desc[virq].basic.child_ic_idx { + IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_handler(virq as u32); } + } else { + println!("unexpected irq num {}", irq); } }); exception_stack!(irq_at_el1, |stack| { let irq = IRQ_CHIP.irq_ack(); - if irq >= 1024 { - println!("unexpected irq num {}", irq); - } else { - if let Some(handler) = &mut IRQ_CHIP.handlers[irq as usize] { - handler.irq_handler(irq); + //println!("el1 irq num {}", irq); + if let Some(virq) = IRQ_CHIP.irq_to_virq(irq) && virq < 1024 { + if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler { + handler.irq_handler(virq as u32); + } else if let Some(ic_idx) = IRQ_CHIP.irq_desc[virq].basic.child_ic_idx { + IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_handler(virq as u32); } + } else { + println!("unexpected irq num {}", irq); } }); + +//TODO pub unsafe fn trigger(irq: u32) { extern { fn irq_trigger(irq: u32);