draft: aarch64: add irq_bcm2835. Need refactoring

This commit is contained in:
Ivan Tan
2023-10-08 11:15:05 +08:00
committed by Jeremy Soller
parent 9a5b9798ca
commit bfbf435546
9 changed files with 668 additions and 150 deletions
+32 -3
View File
@@ -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 {
+56 -17
View File
@@ -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<Option<usize>> {
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<usize> {
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<usize> {
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 {
+163 -38
View File
@@ -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<usize>)> {
//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<usize>)> {
//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<Option<usize>> {
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<usize> {
//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<usize> {
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);
}
}
}
+111 -41
View File
@@ -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<Option<usize>> {
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<usize> {
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<usize> {
if hwirq > LOCAL_IRQ_LAST {
None
} else {
Some(self.irq_range.0 + hwirq as usize)
}
}
fn irq_handler(&mut self, irq: u32) {
}
}
+211 -27
View File
@@ -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<Option<usize>>;
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<usize>;
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize>;
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<u32>,
pub intr_cell_size: u32,
pub parent: Option<usize>, //parent idx in chiplist
pub childs: Vec<usize>, //child idx in chiplist
pub interrupts: Vec<u32>,
pub ic: Box<dyn InterruptController>,
}
pub struct IrqChipList {
pub chips: Vec<IrqChipItem>,
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<usize>, //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<Box<dyn InterruptHandler>>,
}
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<Box<dyn InterruptController>>,
pub ic_idx: usize,
pub irq_chip_list: IrqChipList,
pub handlers: [Option<Box<dyn InterruptHandler>>; 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<usize> {
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<Box<dyn InterruptController>> {
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<Box<dyn InterruptHandler>> = 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<dyn InterruptHandler>) {
if irq >= 1024 {
println!("irq {} exceed 1024!!!", {irq});
pub fn register_irq(virq: u32, handler: Box<dyn InterruptHandler>) {
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);
}
}
+7 -6
View File
@@ -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");
+34 -3
View File
@@ -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<Option<SerialPort>> = 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);
}
}
+31
View File
@@ -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();
+23 -15
View File
@@ -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);