Rework irqchip to support risc-v irqs, and add risc-v irq chips handling

This commit is contained in:
Andrey Turkin
2024-10-22 16:53:09 +03:00
parent 906259c024
commit cba02a26fa
26 changed files with 1011 additions and 355 deletions
+22 -34
View File
@@ -1,18 +1,15 @@
use alloc::boxed::Box;
use log::info;
use log::{error, info};
use super::ic_for_chip;
use crate::{
context,
context::timeout,
device::cpu::registers::control_regs,
dtb::{
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
DTB_BINARY,
},
dtb::irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
interrupt::irq::trigger,
time,
};
use alloc::vec::Vec;
use byteorder::{ByteOrder, BE};
use fdt::Fdt;
@@ -24,42 +21,33 @@ bitflags! {
}
}
pub unsafe fn init() {
pub unsafe fn init(fdt: &Fdt) {
let mut timer = GenericTimer {
clk_freq: 0,
reload_count: 0,
};
timer.init();
let data = DTB_BINARY.get().unwrap();
let fdt = Fdt::new(data).unwrap();
if let Some(node) = fdt.find_compatible(&["arm,armv7-timer"]) {
let interrupts = node.property("interrupts").unwrap();
let mut intr_data = Vec::new();
for chunk in interrupts.value.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.property("interrupt-parent") {
let phandle = interrupt_parent.as_usize().unwrap() as u32;
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)
let irq = interrupts
.value
.array_chunks::<4>()
.map(|f| BE::read_u32(f))
.skip(3)
.next_chunk::<3>()
.unwrap();
info!("generic_timer virq = {}", virq);
register_irq(virq as u32, Box::new(timer));
IRQ_CHIP.irq_enable(virq as u32);
if let Some(ic_idx) = ic_for_chip(&fdt, &node) {
//PHYS_NONSECURE_PPI only
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
.ic
.irq_xlate(&irq)
.unwrap();
info!("generic_timer virq = {}", virq);
register_irq(virq as u32, Box::new(timer));
IRQ_CHIP.irq_enable(virq as u32);
} else {
error!("Failed to find irq parent for generic timer");
}
}
}
+17 -22
View File
@@ -1,7 +1,7 @@
use super::InterruptController;
use crate::dtb::irqchip::{InterruptHandler, IrqDesc};
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},
@@ -75,6 +75,10 @@ impl GenericInterruptController {
}
}
impl InterruptHandler for GenericInterruptController {
fn irq_handler(&mut self, _irq: u32) {}
}
impl InterruptController for GenericInterruptController {
fn irq_init(
&mut self,
@@ -82,7 +86,7 @@ impl InterruptController for GenericInterruptController {
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> Result<Option<usize>> {
) -> Result<()> {
let (dist_addr, _dist_size, cpu_addr, _cpu_size) =
match GenericInterruptController::parse(fdt) {
Ok(regs) => regs,
@@ -117,7 +121,7 @@ impl InterruptController for GenericInterruptController {
info!("gic irq_range = ({}, {})", idx, idx + cnt);
self.irq_range = (idx, idx + cnt);
*irq_idx = idx + cnt;
Ok(None)
Ok(())
}
fn irq_ack(&mut self) -> u32 {
unsafe { self.gic_cpu_if.irq_ack() }
@@ -131,31 +135,22 @@ 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 i = 0;
for chunk in irq_data.chunks(3) {
if i == idx {
let mut off = match chunk[0] {
0 => chunk[1] as usize + 32, //SPI
1 => 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_xlate(&self, irq_data: &[u32; 3]) -> Result<usize> {
let mut off = match irq_data[0] {
0 => irq_data[1] as usize + 32, //SPI
1 => irq_data[1] as usize + 16, //PPI,
_ => return Err(Error::new(EINVAL)),
};
off += self.irq_range.0;
return Ok(off);
}
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
fn irq_to_virq(&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) {}
}
#[derive(Debug)]
+17 -22
View File
@@ -2,8 +2,8 @@ use alloc::vec::Vec;
use core::arch::asm;
use fdt::{node::NodeProperty, Fdt};
use super::gic::GicDistIf;
use crate::dtb::irqchip::{InterruptController, IrqDesc};
use super::{gic::GicDistIf, InterruptController};
use crate::dtb::irqchip::{InterruptHandler, IrqDesc};
use syscall::{
error::{Error, EINVAL},
Result,
@@ -71,6 +71,10 @@ impl GicV3 {
}
}
impl InterruptHandler for GicV3 {
fn irq_handler(&mut self, _irq: u32) {}
}
impl InterruptController for GicV3 {
fn irq_init(
&mut self,
@@ -78,7 +82,7 @@ impl InterruptController for GicV3 {
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> Result<Option<usize>> {
) -> Result<()> {
self.parse(fdt)?;
log::info!("{:X?}", self);
@@ -104,7 +108,7 @@ impl InterruptController for GicV3 {
log::info!("gic irq_range = ({}, {})", idx, idx + cnt);
self.irq_range = (idx, idx + cnt);
*irq_idx = idx + cnt;
Ok(None)
Ok(())
}
fn irq_ack(&mut self) -> u32 {
let irq_num = unsafe { self.gic_cpu_if.irq_ack() };
@@ -119,31 +123,22 @@ impl InterruptController for GicV3 {
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 i = 0;
for chunk in irq_data.chunks(3) {
if i == idx {
let mut off = match chunk[0] {
0 => chunk[1] as usize + 32, //SPI
1 => 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_xlate(&self, irq_data: &[u32; 3]) -> Result<usize> {
let mut off = match irq_data[0] {
0 => irq_data[1] as usize + 32, //SPI
1 => irq_data[1] as usize + 16, //PPI,
_ => return Err(Error::new(EINVAL)),
};
off += self.irq_range.0;
return Ok(off);
}
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
fn irq_to_virq(&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) {}
}
#[derive(Debug)]
+23 -56
View File
@@ -1,12 +1,10 @@
use alloc::vec::Vec;
use core::ptr::{read_volatile, write_volatile};
use byteorder::{ByteOrder, BE};
use core::ptr::{read_volatile, write_volatile};
use fdt::{node::FdtNode, Fdt};
use log::{debug, error, info};
use crate::dtb::irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP};
use super::InterruptController;
use crate::dtb::irqchip::{InterruptHandler, IrqDesc, IRQ_CHIP};
use syscall::{
error::{Error, EINVAL},
Result,
@@ -81,25 +79,17 @@ impl Bcm2835ArmInterruptController {
if let Some(interrupt_parent) = node.property("interrupt-parent") {
let phandle = interrupt_parent.as_usize().unwrap() as u32;
let interrupts = node.property("interrupts").unwrap();
let mut intr_data = Vec::new();
for chunk in interrupts.value.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;
}
let irq = interrupts
.value
.array_chunks::<4>()
.map(|f| BE::read_u32(f))
.next_chunk::<3>()
.unwrap();
let ic_idx = IRQ_CHIP.phandle_to_ic_idx(phandle).unwrap();
//PHYS_NONSECURE_PPI only
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
.ic
.irq_xlate(&intr_data, 0)
.irq_xlate(&irq)
.unwrap();
info!("bcm2835arm_ctrl virq = {}", virq);
ret_virq = Some(virq);
@@ -134,8 +124,8 @@ impl InterruptController for Bcm2835ArmInterruptController {
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> Result<Option<usize>> {
let (base, _size, virq) = match Bcm2835ArmInterruptController::parse(fdt) {
) -> Result<()> {
let (base, _size, _virq) = match Bcm2835ArmInterruptController::parse(fdt) {
Ok((a, b, c)) => (a, b, c),
Err(_) => return Err(Error::new(EINVAL)),
};
@@ -160,7 +150,7 @@ impl InterruptController for Bcm2835ArmInterruptController {
*irq_idx = idx + cnt;
}
Ok(virq)
Ok(())
}
fn irq_ack(&mut self) -> u32 {
@@ -259,46 +249,23 @@ impl InterruptController for Bcm2835ArmInterruptController {
_ => return,
}
}
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize> {
fn irq_xlate(&self, irq_data: &[u32; 3]) -> Result<usize> {
//assert interrupt-cells == 0x2
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;
let off = hwirq + self.irq_range.0;
return Ok(off);
}
i += 1;
}
Err(Error::new(EINVAL))
let bank = irq_data[0] as usize;
let irq = irq_data[1] as usize;
//TODO: check bank && irq
let hwirq = bank << 5 | irq;
let off = hwirq + self.irq_range.0;
return Ok(off);
}
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
fn irq_to_virq(&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 {
error!("unexpected irq num {}", irq);
}
self.irq_eoi(irq);
}
}
}
impl InterruptHandler for Bcm2835ArmInterruptController {
+12 -17
View File
@@ -1,10 +1,10 @@
use super::InterruptController;
use crate::dtb::irqchip::{InterruptHandler, IrqDesc};
use core::{
arch::asm,
ptr::{read_volatile, write_volatile},
};
use fdt::{node::FdtNode, Fdt};
use crate::dtb::irqchip::{InterruptController, IrqDesc};
use log::{debug, info};
use syscall::{
error::{Error, EINVAL},
@@ -102,6 +102,10 @@ impl Bcm2836ArmInterruptController {
}
}
impl InterruptHandler for Bcm2836ArmInterruptController {
fn irq_handler(&mut self, _irq: u32) {}
}
impl InterruptController for Bcm2836ArmInterruptController {
fn irq_init(
&mut self,
@@ -109,7 +113,7 @@ impl InterruptController for Bcm2836ArmInterruptController {
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> Result<Option<usize>> {
) -> Result<()> {
let (base, _size) = match Bcm2836ArmInterruptController::parse(fdt) {
Ok((a, b)) => (a, b),
Err(_) => return Err(Error::new(EINVAL)),
@@ -138,7 +142,7 @@ impl InterruptController for Bcm2836ArmInterruptController {
*irq_idx = idx + cnt;
}
Ok(None)
Ok(())
}
fn irq_ack(&mut self) -> u32 {
@@ -190,25 +194,16 @@ impl InterruptController for Bcm2836ArmInterruptController {
}
}
}
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize> {
let mut i = 0;
fn irq_xlate(&self, irq_data: &[u32; 3]) -> Result<usize> {
//assert interrupt-cells == 0x2
for chunk in irq_data.chunks(2) {
if i == idx {
let off = chunk[0] as usize + self.irq_range.0;
return Ok(off);
}
i += 1;
}
Err(Error::new(EINVAL))
let off = irq_data[0] as usize + self.irq_range.0;
return Ok(off);
}
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
fn irq_to_virq(&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) {}
}
+19 -2
View File
@@ -1,12 +1,13 @@
use crate::dtb::irqchip::InterruptController;
use crate::dtb::irqchip::{InterruptController, IRQ_CHIP};
use alloc::boxed::Box;
use fdt::{node::FdtNode, Fdt};
mod gic;
mod gicv3;
mod irq_bcm2835;
mod irq_bcm2836;
pub fn new_irqchip(ic_str: &str) -> Option<Box<dyn InterruptController>> {
pub(crate) fn new_irqchip(ic_str: &str) -> Option<Box<dyn InterruptController>> {
if ic_str.contains("arm,gic-v3") {
Some(Box::new(gicv3::GicV3::new()))
} else if ic_str.contains("arm,cortex-a15-gic") {
@@ -20,3 +21,19 @@ pub fn new_irqchip(ic_str: &str) -> Option<Box<dyn InterruptController>> {
None
}
}
pub(crate) fn ic_for_chip(fdt: &Fdt, node: &FdtNode) -> Option<usize> {
if let Some(_) = node.property("interrupts-extended") {
log::error!("multi-parented device not supported");
None
} else if let Some(irqc_phandle) = node
.property("interrupt-parent")
.or(fdt.root().property("interrupt-parent"))
.and_then(|f| f.as_usize())
{
unsafe { IRQ_CHIP.phandle_to_ic_idx(irqc_phandle as u32) }
} else {
log::error!("no irq parent found");
None
}
}
+29 -10
View File
@@ -1,4 +1,6 @@
use crate::{dtb, dtb::DTB_BINARY, info};
use crate::info;
use core::sync::atomic::{AtomicUsize, Ordering};
use fdt::Fdt;
pub mod cpu;
pub mod generic_timer;
@@ -7,18 +9,35 @@ pub mod rtc;
pub mod serial;
pub mod uart_pl011;
pub unsafe fn init() {
info!("IRQCHIP INIT");
let data = DTB_BINARY.get().unwrap();
let fdt = fdt::Fdt::new(data).unwrap();
dtb::irqchip::init(&fdt);
info!("GIT INIT");
generic_timer::init();
use crate::dtb::irqchip::IRQ_CHIP;
use irqchip::ic_for_chip;
pub static ROOT_IC_IDX: AtomicUsize = AtomicUsize::new(0);
unsafe fn init_root_ic(fdt: &Fdt) {
let root_irqc_phandle = fdt
.root()
.property("interrupt-parent")
.unwrap()
.as_usize()
.unwrap();
let ic_idx = IRQ_CHIP
.phandle_to_ic_idx(root_irqc_phandle as u32)
.unwrap();
ROOT_IC_IDX.store(ic_idx, Ordering::Relaxed);
}
pub unsafe fn init_noncore() {
pub unsafe fn init(fdt: &Fdt) {
info!("IRQCHIP INIT");
crate::dtb::irqchip::init(&fdt);
init_root_ic(&fdt);
info!("GIT INIT");
generic_timer::init(fdt);
}
pub unsafe fn init_noncore(fdt: &Fdt) {
info!("SERIAL INIT");
serial::init();
serial::init(fdt);
info!("RTC INIT");
rtc::init();
}
+24 -33
View File
@@ -3,15 +3,16 @@ use spin::Mutex;
use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger};
use crate::dtb::{
diag_uart_range,
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
DTB_BINARY,
use crate::{
arch::device::irqchip::ic_for_chip,
dtb::{
diag_uart_range,
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
},
};
use alloc::vec::Vec;
use byteorder::{ByteOrder, BE};
use fdt::Fdt;
use log::info;
use log::{error, info};
pub static COM1: Mutex<Option<SerialPort>> = Mutex::new(None);
@@ -45,36 +46,26 @@ pub unsafe fn init_early(dtb: &Fdt) {
}
}
pub unsafe fn init() {
let data = DTB_BINARY.get().unwrap();
let fdt = Fdt::new(data).unwrap();
pub unsafe fn init(fdt: &Fdt) {
if let Some(node) = fdt.find_compatible(&["arm,pl011"]) {
let interrupts = node.property("interrupts").unwrap();
let mut intr_data = Vec::new();
for chunk in interrupts.value.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.property("interrupt-parent") {
let phandle = interrupt_parent.as_usize().unwrap() as u32;
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)
let irq = interrupts
.value
.array_chunks::<4>()
.map(|f| BE::read_u32(f))
.next_chunk::<3>()
.unwrap();
info!("serial_port virq = {}", virq);
register_irq(virq as u32, Box::new(Com1Irq {}));
IRQ_CHIP.irq_enable(virq as u32);
if let Some(ic_idx) = ic_for_chip(&fdt, &node) {
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
.ic
.irq_xlate(&irq)
.unwrap();
info!("serial_port virq = {}", virq);
register_irq(virq as u32, Box::new(Com1Irq {}));
IRQ_CHIP.irq_enable(virq as u32);
} else {
error!("serial port irq parent not found");
}
}
if let Some(ref mut serial_port) = *COM1.lock() {
serial_port.enable_irq();
+14 -19
View File
@@ -1,34 +1,29 @@
use crate::dtb::irqchip::IRQ_CHIP;
use crate::{arch::device::ROOT_IC_IDX, dtb::irqchip::IRQ_CHIP};
use core::sync::atomic::Ordering;
unsafe fn irq_ack() -> (u32, Option<usize>) {
let ic = &mut IRQ_CHIP.irq_chip_list.chips[ROOT_IC_IDX.load(Ordering::Relaxed)].ic;
let irq = ic.irq_ack();
(irq, ic.irq_to_virq(irq))
}
exception_stack!(irq_at_el0, |_stack| {
let irq = IRQ_CHIP.irq_ack();
if let Some(virq) = IRQ_CHIP.irq_to_virq(irq)
let (irq, virq) = irq_ack();
if let Some(virq) = virq
&& 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);
}
IRQ_CHIP.trigger_virq(virq as u32);
} else {
println!("unexpected irq num {}", irq);
}
});
exception_stack!(irq_at_el1, |_stack| {
let irq = IRQ_CHIP.irq_ack();
if let Some(virq) = IRQ_CHIP.irq_to_virq(irq)
let (irq, virq) = irq_ack();
if let Some(virq) = virq
&& 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);
}
IRQ_CHIP.trigger_virq(virq as u32);
} else {
println!("unexpected irq num {}", irq);
}
-2
View File
@@ -10,8 +10,6 @@ pub mod irq;
pub mod syscall;
pub mod trace;
use crate::cpu_set::LogicalCpuId;
pub use self::handler::InterruptStack;
/// Clear interrupts
+8 -11
View File
@@ -69,11 +69,10 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
} else {
None
};
let dtb = dtb.unwrap();
if let Some(dt) = &dtb {
// Try to find serial port prior to logging
device::serial::init_early(dt);
}
// Try to find serial port prior to logging
device::serial::init_early(&dtb);
// Convert env to slice
let env = slice::from_raw_parts(
@@ -138,12 +137,10 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
tmp = out(reg) _,
);
if let Some(dt) = &dtb {
//in uefi boot mode, ignore memory node, just read the device memory range
//register_memory_ranges(dt);
//in uefi boot mode, ignore memory node, just read the device memory range
//register_memory_ranges(&dtb);
register_dev_memory_ranges(dt);
}
register_dev_memory_ranges(&dtb);
register_bootloader_areas(args.areas_base, args.areas_size);
@@ -202,10 +199,10 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
dtb::init(Some((crate::PHYS_OFFSET + args.dtb_base, args.dtb_size)));
// Initialize devices
device::init();
device::init(&dtb);
// Initialize all of the non-core devices not otherwise needed to complete initialization
device::init_noncore();
device::init_noncore(&dtb);
BSP_READY.store(true, Ordering::SeqCst);
+42
View File
@@ -0,0 +1,42 @@
use spin::Mutex;
use syscall::{Io, Mmio};
use crate::context::switch::tick;
#[repr(packed(4))]
#[repr(C)]
struct ClintRegs {
/// per-hart MSIP registers
/// bit 0: trigger IPI for the hart
msip: [Mmio<u32>; 4095], // +0000 -- 3fff
_rsrv1: u32,
/// per-hart MTIMECMP registers
/// timer interrupt trigger threshold
mtimecmp: [Mmio<u64>; 4095], // +4000 - bff7
mtime: Mmio<u64> // current time
}
pub struct Clint {
regs: &'static mut ClintRegs,
freq: u64
}
pub static CLINT: Mutex<Option<Clint>> = Mutex::new(None);
impl Clint {
pub fn new(addr: *mut u8, size: usize, freq: usize) -> Self {
assert!(size >= core::mem::size_of::<ClintRegs>());
Self {
regs: unsafe { (addr as *mut ClintRegs).as_mut().unwrap() },
freq: freq as u64
}
}
pub fn init(self: &mut Self) {
(*self.regs).mtimecmp[0].write((*self.regs).mtime.read() + self.freq / 100);
}
pub fn timer_irq(self: &mut Self, hart: usize) {
(*self.regs).mtimecmp[hart].write((*self.regs).mtimecmp[hart].read() + self.freq / 100);
tick();
}
}
@@ -0,0 +1,144 @@
use crate::{
arch::riscv64::sbi::SBI,
dtb::irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
};
use alloc::{boxed::Box, vec::Vec};
use byteorder::{ByteOrder, BE};
use core::{arch::asm, cmp::max};
use fdt::node::FdtNode;
use spin::Mutex;
// This is a Core-Local Interruptor (CLINT). A single device directly routed into each HLIC
// It is responsible for local timer and IPI interrupts
// An example DTS:
// /soc/
// clint@2000000/
// interrupts-extended = <&hlic0 3>, <&hlic0 7>, <&hlic1 3>, <&hlic1 7>,
// <&hlic2 3>, <&hlic2 7>, <&hlic3 3>, <&hlic3 7>;
// reg = <0x200000000 0x10000>;
// compatible = "sifive,clint0", "riscv,clint0";
pub struct Clint {
freq: u64,
next_event: Vec<u64>,
}
pub static CLINT: Mutex<Option<Clint>> = Mutex::new(None);
const TICKS_PER_SECOND: u64 = 100;
const IRQ_IPI: usize = 0;
const IRQ_TIMER: usize = 1;
struct ClintConnector {
hart_id: usize,
irq: usize,
}
impl InterruptHandler for ClintConnector {
fn irq_handler(&mut self, _irq: u32) {
CLINT
.lock()
.as_mut()
.unwrap()
.irq_handler(self.hart_id, self.irq);
}
}
fn map_interrupt(irq: u32) -> u32 {
match irq {
3 => 1, // map M-mode IPI to S-mode IPI
7 => 5, // map M-mode timer to S-mode timer
x => x,
}
}
impl Clint {
pub fn new(freq: usize, node: &FdtNode) -> Self {
// TODO IPI
// let reg = clint_node.reg().unwrap().next().unwrap();
// reg.starting_address.add(crate::PHYS_OFFSET) as *mut u8;
// reg.size.unwrap();
let mut me = Self {
freq: freq as u64,
next_event: Vec::new(),
};
let mut interrupts = node
.property("interrupts-extended")
.unwrap()
.value
.chunks(4)
.map(|x| BE::read_u32(x));
let mut hart_id = 0;
while let Ok([phandle1, irq0, phandle2, irq1]) = interrupts.next_chunk::<4>() {
assert_eq!(
phandle1, phandle2,
"Invalid interrupts-extended property for CLINT"
);
let hlic = unsafe {
IRQ_CHIP
.irq_chip_list
.chips
.iter()
.find(|x| x.phandle == phandle1)
.expect("Couldn't find HLIC in irqchip list for CLINT")
};
// FIXME dirty hack map M-mode interrupts (handled by SBI) to S-mode interrupts we get from SBI
// Why aren't S-mode interrupts in the DTB already?
let irq0 = map_interrupt(irq0);
let irq1 = map_interrupt(irq1);
let virq0 = hlic
.ic
.irq_xlate(&[irq0, 0, 0])
.expect("Couldn't get virq 0 from HLIC");
let virq1 = hlic
.ic
.irq_xlate(&[irq1, 0, 0])
.expect("Couldn't get virq 1 from HLIC");
register_irq(virq0 as u32, Box::new(ClintConnector { hart_id, irq: 0 }));
register_irq(virq1 as u32, Box::new(ClintConnector { hart_id, irq: 1 }));
hart_id += 1;
}
me.next_event.resize_with(hart_id, || 0);
me
}
pub(crate) fn irq_handler(self: &mut Self, hart_id: usize, irq: usize) {
match irq {
IRQ_IPI => {
println!("IPI interrupt at {}", hart_id);
}
IRQ_TIMER => {
let mtime: usize;
unsafe {
asm!(
"rdtime t0",
lateout("t0") mtime
)
};
self.next_event[hart_id] =
max(self.next_event[hart_id], mtime as u64) + self.freq / TICKS_PER_SECOND;
SBI.set_timer(self.next_event[hart_id])
.expect("SBI timer cannot be set!");
}
_ => {
panic!("Unexpected CLINT irq")
}
}
}
pub fn init(self: &mut Self, hart: usize) {
let mtime: usize;
unsafe {
asm!(
"rdtime t0",
lateout("t0") mtime
)
};
self.next_event[hart] = mtime as u64 + (self.freq / TICKS_PER_SECOND);
SBI.set_timer(self.next_event[hart])
.expect("SBI timer cannot be set!");
}
}
+159
View File
@@ -0,0 +1,159 @@
use crate::dtb::irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP};
use alloc::vec::Vec;
use core::arch::asm;
use fdt::{node::NodeProperty, Fdt};
use syscall::{Error, ENOENT};
// This is a hart-local interrupt controller, a root of irqchip tree
// An example DTS:
// /cpus/
// cpu@1/
// interrupt-controller/
// #interrupt-cells = 0x00000001
// interrupt-controller =
// compatible = "riscv,cpu-intc"
// phandle = 0x00000006
fn acknowledge(interrupt: usize) {
unsafe {
asm!(
"csrc sip, t0",
in("t0") 1usize << interrupt,
options(nostack)
)
}
}
pub unsafe fn interrupt(hart: usize, interrupt: usize) {
assert!(
hart < CPU_INTERRUPT_HANDLERS.len(),
"Unexpected hart in interrupt routine"
);
acknowledge(interrupt);
let ic_idx = CPU_INTERRUPT_HANDLERS[hart].unwrap_or_else(|| {
panic!(
"No hlic connected to hart {} yet interrupt {} occurred",
hart, interrupt
)
});
let virq = IRQ_CHIP
.irq_to_virq(ic_idx, interrupt as u32)
.unwrap_or_else(|| panic!("HLIC doesn't know of interrupt {}", interrupt));
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 {
panic!(
"Unconnected interrupt {} occurred on hlic connected to hart {}",
interrupt, hart
);
}
}
pub fn init() {
unsafe {
asm!(
"csrs sie, t0",
in("t0") (0xFFFF),
options(nostack)
)
}
}
static mut CPU_INTERRUPT_HANDLERS: Vec<Option<usize>> = Vec::new();
pub struct Hlic {
virq_base: usize,
}
impl Hlic {
pub(crate) fn new() -> Self {
return Self { virq_base: 0 };
}
}
impl InterruptHandler for Hlic {
fn irq_handler(&mut self, irq: u32) {
assert!(irq < 16, "Unsupported HLIC interrupt raised!");
unsafe {
IRQ_CHIP.trigger_virq(self.virq_base as u32 + irq);
}
}
}
impl InterruptController for Hlic {
fn irq_init(
&mut self,
fdt: &Fdt,
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> syscall::Result<()> {
let desc = unsafe { &IRQ_CHIP.irq_chip_list.chips[ic_idx] };
let cpu_node = fdt
.find_all_nodes("/cpus/cpu")
.find(|x| {
x.children().any(|x| {
x.property("phandle").and_then(NodeProperty::as_usize)
== Some(desc.phandle as usize)
})
})
.expect("Could not find CPU node for HLIC controller");
let hart = cpu_node.property("reg").unwrap().as_usize().unwrap();
unsafe {
if CPU_INTERRUPT_HANDLERS.len() <= hart {
CPU_INTERRUPT_HANDLERS.resize(hart + 1, None);
}
assert!(
CPU_INTERRUPT_HANDLERS[hart].replace(ic_idx).is_none(),
"Conflicting HLIC interrupt handler found"
);
}
self.virq_base = *irq_idx;
for i in 0..16 {
irq_desc[self.virq_base + i].basic.ic_idx = ic_idx;
irq_desc[self.virq_base + i].basic.ic_irq = i as u32;
}
*irq_idx += 16;
Ok(())
}
fn irq_ack(&mut self) -> u32 {
panic!("Cannot ack HLIC interrupt");
}
fn irq_eoi(&mut self, _irq_num: u32) {}
fn irq_enable(&mut self, _irq_num: u32) {
// This would require IPI to a correct core
// Not bothering with this, all interrupts are enabled at all times
}
fn irq_disable(&mut self, _irq_num: u32) {
// This would require IPI to a correct core
// Not bothering with this, all interrupts are enabled at all times
}
fn irq_xlate(&self, irq_data: &[u32; 3]) -> syscall::Result<usize> {
let irq = irq_data[0];
match irq {
0..=0xF => Ok(self.virq_base + irq as usize),
_ => Err(Error::new(ENOENT)),
}
}
fn irq_to_virq(&self, hwirq: u32) -> Option<usize> {
if hwirq > 0 && hwirq <= 0xF {
Some(self.virq_base + hwirq as usize)
} else {
None
}
}
}
pub fn irqchip_for_hart(hart: usize) -> Option<usize> {
let value = unsafe { CPU_INTERRUPT_HANDLERS.get(hart) }?;
*value
}
+40 -2
View File
@@ -1,6 +1,44 @@
use self::clint::Clint;
use crate::dtb::irqchip::InterruptController;
use alloc::boxed::Box;
use fdt::Fdt;
pub fn new_irqchip(_ic_str: &str) -> Option<Box<dyn InterruptController>> {
None
pub(crate) mod hlic;
mod plic;
#[path = "clint_sbi.rs"]
mod clint;
// pub mod clint; // actual clint.rs off limits if SBI is present
pub fn new_irqchip(ic_str: &str) -> Option<Box<dyn InterruptController>> {
if ic_str.contains("riscv,cpu-intc") {
Some(Box::new(hlic::Hlic::new()))
} else if ic_str.contains("riscv,plic0") {
Some(Box::new(plic::Plic::new()))
} else {
log::warn!("no driver for interrupt controller {:?}", ic_str);
None
}
}
pub unsafe fn init_clint(fdt: &Fdt) {
let cpus = fdt.find_node("/cpus").unwrap();
let clock_freq = cpus
.property("timebase-frequency")
.unwrap()
.as_usize()
.unwrap();
let clint_node = fdt.find_node("/soc/clint").unwrap();
assert!(clint_node
.compatible()
.unwrap()
.all()
.find(|x| ((*x).eq("riscv,clint0")))
.is_some());
let clint = Clint::new(clock_freq, &clint_node);
*clint::CLINT.lock() = Some(clint);
clint::CLINT.lock().as_mut().unwrap().init(0);
}
+196
View File
@@ -0,0 +1,196 @@
use crate::{
arch::{device::irqchip::hlic, start::BOOT_HART_ID},
dtb::irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP},
};
use core::{mem, num::NonZero, sync::atomic::Ordering};
use fdt::Fdt;
use log::{error, info};
use syscall::{Error, Io, Mmio, ENODEV};
#[repr(packed(4))]
#[repr(C)]
struct InterruptThresholdRegs {
threshold: Mmio<u32>,
claim_complete: Mmio<u32>,
_rsrv: [u32; 1022],
}
static MAX_CONTEXTS: usize = 64;
#[repr(packed(4))]
#[repr(C)]
struct PlicRegs {
/// source priorities
source_priority: [Mmio<u32>; 1024], // +0000 -- 0fff
// pending interrupts
pending: [Mmio<u32>; 1024], // +1000 -- 1fff
// per-context interrupt enable
enable: [[Mmio<u32>; 32]; 16320], // +2000 - 1f'ffff
// per-context priority threshold and acknowledge
thresholds: [InterruptThresholdRegs; 64], // specced at +20'0000 - 0fff'ffff for 15872 contexts
// but actual memory allotted in firmware is much lower
}
const _: () = assert!(0x1000 == mem::offset_of!(PlicRegs, pending));
const _: () = assert!(0x2000 == mem::offset_of!(PlicRegs, enable));
const _: () = assert!(0x20_0000 == mem::offset_of!(PlicRegs, thresholds));
const _: () = assert!(0x1000 == mem::size_of::<InterruptThresholdRegs>());
impl PlicRegs {
pub fn set_priority(self: &mut Self, irq: usize, priority: usize) {
assert!(irq > 0 && irq <= 1023 && priority < 8);
self.source_priority[irq].write(priority as u32);
}
pub fn pending(self: &Self, irq_lane: usize) -> u32 {
assert!(irq_lane < 32);
self.pending[irq_lane].read()
}
pub fn enable(self: &mut Self, context: usize, irq: NonZero<usize>, enable: bool) {
assert!(irq.get() <= 1023 && context < MAX_CONTEXTS);
let irq_lane = irq.get() / 32;
let irq = irq.get() % 32;
self.enable[context][irq_lane].writef(1u32 << irq, enable);
}
pub fn set_priority_threshold(self: &mut Self, context: usize, priority: usize) {
assert!(context < MAX_CONTEXTS && priority <= 7);
self.thresholds[context].threshold.write(priority as u32);
}
pub fn claim(self: &mut Self, context: usize) -> Option<NonZero<usize>> {
assert!(context < MAX_CONTEXTS);
let claim = self.thresholds[context].claim_complete.read();
NonZero::new(claim as usize)
}
pub fn complete(self: &mut Self, context: usize, claim: NonZero<usize>) {
assert!(context < MAX_CONTEXTS);
self.thresholds[context]
.claim_complete
.write(claim.get() as u32);
}
}
pub struct Plic {
regs: *mut PlicRegs,
ndev: usize,
virq_base: usize,
context: usize,
}
impl Plic {
pub fn new() -> Self {
Self {
regs: 0 as *mut PlicRegs,
ndev: 0,
virq_base: 0,
context: 0,
}
}
}
impl InterruptHandler for Plic {
fn irq_handler(&mut self, _irq: u32) {
unsafe {
let irq = self.irq_ack();
//println!("PLIC interrupt {}", irq);
if let Some(virq) = self.irq_to_virq(irq) {
IRQ_CHIP.trigger_virq(virq as u32);
} else {
error!("unexpected irq num {}", irq);
self.irq_eoi(irq);
}
}
//println!("PLIC interrupt done");
}
}
impl InterruptController for Plic {
fn irq_init(
&mut self,
fdt: &Fdt,
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> syscall::Result<()> {
let desc = unsafe { &IRQ_CHIP.irq_chip_list.chips[ic_idx] };
let my_node = fdt.find_phandle(desc.phandle).unwrap();
// MMIO region
let reg = my_node.reg().unwrap().next().unwrap();
// Specifies how many external interrupts are supported by this controller.
let ndev = my_node
.property("riscv,ndev")
.and_then(|x| x.as_usize())
.unwrap();
unsafe {
self.regs = reg.starting_address.add(crate::PHYS_OFFSET) as *mut PlicRegs;
}
self.ndev = ndev;
self.virq_base = *irq_idx;
for i in 0..ndev {
irq_desc[self.virq_base + i].basic.ic_idx = ic_idx;
irq_desc[self.virq_base + i].basic.ic_irq = i as u32;
}
*irq_idx += ndev;
// route all interrupts to boot HART
// TODO spread irqs over all the cores when we have them?
let hlic_ic_idx = hlic::irqchip_for_hart(BOOT_HART_ID.load(Ordering::Relaxed))
.expect("Could not find HLIC irqchip for the boot hart while initing PLIC");
self.context = desc
.parents
.iter()
.position(|x| x.parent_interrupt[0] != u32::MAX && x.parent == hlic_ic_idx)
.unwrap();
info!("PLIC: using context {}", self.context);
let regs = unsafe { self.regs.as_mut().unwrap() };
regs.set_priority_threshold(self.context, 0);
Ok(())
}
fn irq_ack(&mut self) -> u32 {
let regs = unsafe { self.regs.as_mut().unwrap() };
regs.claim(self.context).unwrap().get() as u32
}
fn irq_eoi(&mut self, irq_num: u32) {
let regs = unsafe { self.regs.as_mut().unwrap() };
regs.complete(self.context, NonZero::new(irq_num as usize).unwrap());
}
fn irq_enable(&mut self, irq_num: u32) {
assert!(irq_num > 0 && irq_num as usize <= self.ndev);
let regs = unsafe { self.regs.as_mut().unwrap() };
regs.set_priority(irq_num as usize, 1);
regs.enable(self.context, NonZero::new(irq_num as usize).unwrap(), true);
}
fn irq_disable(&mut self, irq_num: u32) {
assert!(irq_num > 0 && irq_num as usize <= self.ndev);
let regs = unsafe { self.regs.as_mut().unwrap() };
regs.set_priority(irq_num as usize, 1);
regs.enable(self.context, NonZero::new(irq_num as usize).unwrap(), false);
}
fn irq_xlate(&self, irq_data: &[u32; 3]) -> syscall::Result<usize> {
if (irq_data[0] as usize) < self.ndev {
Ok(self.virq_base + irq_data[0] as usize)
} else {
Err(Error::new(ENODEV))
}
}
fn irq_to_virq(&self, hwirq: u32) -> Option<usize> {
if (hwirq as usize) < self.ndev {
Some(self.virq_base + hwirq as usize)
} else {
None
}
}
}
+12 -2
View File
@@ -1,13 +1,18 @@
use crate::{arch::time, dtb::DTB_BINARY};
use crate::{
arch::{device::irqchip::hlic, time},
dtb::DTB_BINARY,
};
use fdt::{
node::{FdtNode, NodeProperty},
Fdt,
};
pub mod cpu;
pub mod irqchip;
pub(crate) mod irqchip;
pub mod serial;
use crate::arch::device::irqchip::init_clint;
fn string_property(name: &str) -> bool {
name == "compatible"
|| name == "model"
@@ -59,12 +64,16 @@ unsafe fn init_intc(cpu: &FdtNode) {
.find(|x| x.name == "interrupt-controller")
.unwrap();
assert_eq!(intc_node.compatible().unwrap().first(), "riscv,cpu-intc");
// This controller is hardwired into interrupt handler code and has no Mmios
hlic::init(); // enable interrupts at HLIC level
}
pub unsafe fn init() {
let data = DTB_BINARY.get().unwrap();
let fdt = Fdt::new(data).unwrap();
crate::dtb::irqchip::init(&fdt);
let cpu = fdt.find_node(format!("/cpus/cpu@{}", 0).as_str()).unwrap();
init_intc(&cpu);
init_time(&fdt);
@@ -84,6 +93,7 @@ pub unsafe fn init_noncore() {
let data = DTB_BINARY.get().unwrap();
let fdt = Fdt::new(data).unwrap();
init_clint(&fdt);
serial::init(&fdt);
}
+30 -5
View File
@@ -1,4 +1,4 @@
use alloc::{boxed::Box, vec::Vec};
use alloc::boxed::Box;
use byteorder::{ByteOrder, BE};
use fdt::Fdt;
use log::info;
@@ -7,7 +7,10 @@ use syscall::Mmio;
use crate::{
devices::uart_16550,
dtb::{diag_uart_range, DTB_BINARY},
dtb::{
diag_uart_range,
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
},
scheme::{
debug::{debug_input, debug_notify},
irq::irq_trigger,
@@ -33,6 +36,18 @@ pub static COM1: Mutex<Option<SerialPort>> = Mutex::new(None);
pub struct Com1Irq {}
impl InterruptHandler for Com1Irq {
fn irq_handler(&mut self, irq: u32) {
if let Some(ref mut serial_port) = *COM1.lock() {
serial_port.receive();
};
unsafe {
irq_trigger(irq as u8);
IRQ_CHIP.irq_eoi(irq);
}
}
}
pub unsafe fn init_early(dtb: &Fdt) {
if COM1.lock().is_some() {
// Hardcoded UART
@@ -58,8 +73,6 @@ pub unsafe fn init_early(dtb: &Fdt) {
}
pub unsafe fn init(fdt: &Fdt) -> Option<()> {
let data = DTB_BINARY.get().unwrap();
let fdt = Fdt::new(data).unwrap();
if let Some(node) = fdt.find_compatible(&["ns16550a"]) {
let interrupts = node.property("interrupts").unwrap();
let mut intr_data: [u32; 3] = [0, 0, 0];
@@ -70,8 +83,20 @@ pub unsafe fn init(fdt: &Fdt) -> Option<()> {
let val = BE::read_u32(chunk);
intr_data[idx] = val;
}
let interrupt_parent = node.interrupt_parent()?;
let phandle = interrupt_parent.property("phandle")?.as_usize()? as u32;
let ic_idx = IRQ_CHIP.phandle_to_ic_idx(phandle)?;
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
.ic
.irq_xlate(&intr_data)
.unwrap();
info!("serial_port virq = {}", virq);
register_irq(virq as u32, Box::new(Com1Irq {}));
IRQ_CHIP.irq_enable(virq as u32);
}
if let Some(ref mut serial_port) = *COM1.lock() {
if let Some(ref mut _serial_port) = *COM1.lock() {
// serial_port.enable_irq(); // FIXME receive int is enabled by default in 16550. Disable by default?
}
Some(())
+14 -6
View File
@@ -1,11 +1,14 @@
use core::{
arch::global_asm,
sync::atomic::{AtomicUsize, Ordering},
};
use core::{arch::global_asm, sync::atomic::Ordering};
use log::{error, info};
use rmm::VirtualAddress;
use crate::{memory::GenericPfFlags, panic::stack_trace, ptrace, syscall, syscall::flag::*};
use crate::{
arch::{device::irqchip, start::BOOT_HART_ID},
memory::GenericPfFlags,
panic::stack_trace,
ptrace, syscall,
syscall::flag::*,
};
const BREAKPOINT: usize = 3;
const USERMODE_ECALL: usize = 8;
@@ -133,7 +136,12 @@ unsafe fn handle_system_exception(scause: usize, regs: &InterruptStack) {
loop {}
}
unsafe fn handle_interrupt(interrupt: usize) {}
unsafe fn handle_interrupt(interrupt: usize) {
// FIXME retrieve from percpu area
// For now all the interrupts go to boot hart so this suffices...
let hart: usize = BOOT_HART_ID.load(Ordering::Relaxed);
irqchip::hlic::interrupt(hart, interrupt);
}
unsafe fn handle_user_exception(scause: usize, regs: &mut InterruptStack) {
if scause == USERMODE_ECALL {
-3
View File
@@ -7,9 +7,6 @@ mod exception;
pub mod syscall;
pub mod trace;
pub use self::trace::StackTrace;
use crate::cpu_set::LogicalCpuId;
pub use handler::InterruptStack;
pub fn bsp_apic_id() -> Option<u32> {
-1
View File
@@ -1,4 +1,3 @@
use super::CurrentRmmArch as RmmA;
use rmm::{Arch, PageFlags, VirtualAddress};
pub struct KernelMapper {
+1 -4
View File
@@ -20,10 +20,7 @@ use crate::{
#[cfg(feature = "graphical_debug")]
use crate::devices::graphical_debug;
use crate::{
devices::graphical_debug::{DebugDisplay, DEBUG_DISPLAY, FRAMEBUFFER},
dtb::register_dev_memory_ranges,
};
use crate::dtb::register_dev_memory_ranges;
/// Test of zero values in BSS.
static mut BSS_TEST_ZERO: usize = 0;
+2
View File
@@ -23,6 +23,8 @@ pub mod entry {
pub mod mapper;
pub const ENTRY_COUNT: usize = RmmA::PAGE_ENTRIES;
/// Size of pages
pub const PAGE_SIZE: usize = RmmA::PAGE_SIZE;
pub const PAGE_MASK: usize = RmmA::PAGE_OFFSET_MASK;
-4
View File
@@ -8,18 +8,14 @@ use crate::{
percpu::PercpuBlock,
syscall::FloatRegisters,
};
use alloc::sync::Arc;
use core::{mem::offset_of, sync::atomic::AtomicBool};
use rmm::{Arch, TableKind, VirtualAddress};
use spin::Once;
use spinning_top::RwSpinlock;
use syscall::{error::*, EnvRegisters};
pub static CONTEXT_SWITCH_LOCK: AtomicBool = AtomicBool::new(false);
pub const KFX_ALIGN: usize = 16;
pub const KSTACK_SIZE: usize = 65536;
pub const KSTACK_ALIGN: usize = 16;
#[derive(Clone, Debug, Default)]
pub struct Context {
+182 -97
View File
@@ -1,48 +1,47 @@
use super::travel_interrupt_ctrl;
use crate::{
arch, arch::device::irqchip::new_irqchip, cpu_set::LogicalCpuId, scheme::irq::irq_trigger,
};
use crate::{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};
use syscall::{Error, Result};
pub trait InterruptHandler {
fn irq_handler(&mut self, irq: u32);
}
pub trait InterruptController {
pub trait InterruptController: InterruptHandler {
fn irq_init(
&mut self,
fdt: &Fdt,
irq_desc: &mut [IrqDesc; 1024],
ic_idx: usize,
irq_idx: &mut usize,
) -> Result<Option<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<usize>;
fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize>;
fn irq_handler(&mut self, irq: u32);
fn irq_xlate(&self, irq_data: &[u32; 3]) -> Result<usize>;
fn irq_to_virq(&self, hwirq: u32) -> Option<usize>;
}
pub struct IrqConnection {
pub parent_phandle: u32,
pub parent: usize, // parent idx in chiplist
pub parent_interrupt: [u32; 3],
}
pub struct IrqChipItem {
pub phandle: u32,
pub parent_phandle: Option<u32>,
pub parent: Option<usize>, //parent idx in chiplist
pub childs: Vec<usize>, //child idx in chiplist
pub interrupts: Vec<u32>,
pub parents: Vec<IrqConnection>,
pub children: Vec<usize>, // child idx in chiplist
pub ic: Box<dyn InterruptController>,
}
pub struct IrqChipList {
pub chips: Vec<IrqChipItem>,
pub root_phandle: u32,
pub root_idx: usize,
}
pub struct IrqDescItem {
@@ -60,20 +59,11 @@ pub struct IrqDesc {
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}",
@@ -81,72 +71,146 @@ impl IrqChipList {
);
let mut item = IrqChipItem {
phandle,
parent_phandle: None,
parent: None,
childs: Vec::new(),
interrupts: Vec::new(),
parents: Vec::new(),
children: 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");
fn interrupt_address(
iter: &mut impl Iterator<Item = u32>,
interrupt_cells: usize,
) -> Option<[u32; 3]> {
match interrupt_cells {
1 if let Some(a) = iter.next() => Some([a, 0, 0]),
2 if let Ok([a, b]) = iter.next_chunk() => Some([a, b, 0]),
3 => iter.next_chunk::<3>().ok(),
_ => None,
}
}
if item.phandle == root_intr_parent {
self.root_idx = idx as usize;
if let Some(parent) = node.interrupt_parent()
&& let Some(intr_data) = node.property("interrupts")
{
// FIXME use interrupts() helper when fixed (see gh#12)
let parent_interrupt_cells = parent.interrupt_cells().unwrap();
let parent_phandle = parent
.property("phandle")
.and_then(NodeProperty::as_usize)
.unwrap() as u32;
debug!("interrupt-parent = 0x{:08x}", parent_phandle);
debug!("interrupts begin:");
let mut intr_data = intr_data.value.chunks(4).map(|x| BE::read_u32(x));
while let Some(parent_interrupt) =
interrupt_address(&mut intr_data, parent_interrupt_cells)
{
debug!("{:?}, ", parent_interrupt);
item.parents.push(IrqConnection {
parent_phandle,
parent: 0,
parent_interrupt,
});
}
debug!("interrupts end");
} else if let Some(intr_data) = node.property("interrupts-extended") {
// FIXME use the helper when fixed (see gh#37)
// Shouldn't matter much since ARM seems to not use extended interrupt and
// RISC-V seems to not use 3-sized interrupt addresses
let mut intr_data = intr_data.value.chunks(4).map(|x| BE::read_u32(x));
while let Some(parent_phandle) = intr_data.next()
&& let Some(parent) = fdt.find_phandle(parent_phandle)
&& let Some(parent_interrupt_cells) = parent.interrupt_cells()
&& let Some(parent_interrupt) =
interrupt_address(&mut intr_data, parent_interrupt_cells)
{
debug!("{:?}, ", parent_interrupt);
item.parents.push(IrqConnection {
parent_phandle,
parent: 0,
parent_interrupt,
});
}
}
self.chips.push(item);
idx += 1;
}
}
}
fn init_inner2(&mut self) {
let mut x = 0;
fn init_inner2(&mut self) -> Vec<usize> {
let mut roots = Vec::new();
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;
for child_i in 0..self.chips.len() {
let child = &mut self.chips[child_i];
let phandle = child.phandle;
if child.parents.is_empty() {
roots.push(child_i);
continue;
}
for conn_i in 0..child.parents.len() {
let parent_phandle = self.chips[child_i].parents[conn_i].parent_phandle;
let parent_i = self
.chips
.iter()
.position(|x| parent_phandle == x.phandle)
.unwrap_or_else(|| {
panic!(
"Cannot find parent intc {} (connection from {})",
parent_phandle, phandle
)
});
self.chips[child_i].parents[conn_i].parent = parent_i;
let parent = &mut self.chips[parent_i];
if !parent.children.contains(&child_i) {
parent.children.push(child_i);
}
}
x += 1;
}
roots
}
fn init_inner3(&mut self, fdt: &fdt::Fdt, irq_desc: &mut [IrqDesc; 1024]) {
fn init_inner3(&mut self, fdt: &Fdt, irq_desc: &mut [IrqDesc; 1024], mut queue: Vec<usize>) {
//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);
let mut queue_idx = 0;
while queue_idx < queue.len() {
let cur_idx = queue[queue_idx];
let cur_chip = &mut self.chips[cur_idx];
for child in &cur_chip.children {
if let Some(child_pos) = queue.iter().position(|x| *child == *x) {
assert!(
child_pos > queue_idx,
"IRQ chip tree has a cycle with phandle {} in it",
cur_chip.phandle
);
} else {
queue.push(*child);
}
}
cur_chip
.ic
.irq_init(fdt, irq_desc, cur_idx, &mut irq_idx)
.expect("Failed to initialize irq chip");
let cur_chip = &self.chips[cur_idx];
for connection in &cur_chip.parents {
debug_assert!(queue[0..queue_idx].contains(&connection.parent));
if connection.parent_interrupt[0] != u32::MAX {
let parent = &self.chips[connection.parent];
if let Ok(virq) = parent.ic.irq_xlate(&connection.parent_interrupt) {
// assert is unused
irq_desc[virq].basic.child_ic_idx = Some(cur_idx);
} else {
error!(
"Cannot connect irq chip {} to parent irq {} : {:?}",
cur_chip.phandle, parent.phandle, connection.parent_interrupt
);
}
}
}
queue_idx += 1;
}
}
}
@@ -158,12 +222,6 @@ pub struct IrqChipCore {
}
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;
@@ -189,24 +247,49 @@ impl IrqChipCore {
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)
#[cfg(target_arch = "riscv64")]
pub fn irq_to_virq(&self, ic_idx: usize, hwirq: u32) -> Option<usize> {
self.irq_chip_list.chips[ic_idx].ic.irq_to_virq(hwirq)
}
#[cfg(target_arch = "riscv64")]
pub fn irq_xlate(&self, ic_idx: usize, irq_data: &[u32; 3]) -> Result<usize, Error> {
self.irq_chip_list.chips[ic_idx].ic.irq_xlate(irq_data)
}
pub fn trigger_virq(&mut self, virq: u32) {
if virq < 1024 {
let desc = &mut self.irq_desc[virq as usize];
if let Some(handler) = &mut desc.handler {
handler.irq_handler(virq);
} else if let Some(ic_idx) = desc.basic.child_ic_idx {
self.irq_chip_list.chips[ic_idx].ic.irq_handler(virq);
} else {
irq_trigger(virq as u8);
}
}
}
pub fn init(&mut self, fdt: &Fdt) {
for i in 0..1024 {
self.irq_desc[i].basic.idx = i;
for (i, desc) in self.irq_desc.iter_mut().enumerate() {
desc.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);
let roots = self.irq_chip_list.init_inner2();
self.irq_chip_list
.init_inner3(fdt, &mut self.irq_desc, roots);
}
pub fn phandle_to_ic_idx(&self, phandle: u32) -> Option<usize> {
self.irq_chip_list
.chips
.iter()
.position(|x| x.phandle == phandle)
}
}
pub unsafe fn acknowledge(_irq: usize) {
// TODO
pub unsafe fn acknowledge(irq: usize) {
IRQ_CHIP.irq_eoi(irq as u32);
}
const INIT_HANDLER: Option<Box<dyn InterruptHandler>> = None;
@@ -221,11 +304,7 @@ const INIT_IRQ_DESC: IrqDesc = IrqDesc {
handler: INIT_HANDLER,
};
pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
irq_chip_list: IrqChipList {
chips: Vec::new(),
root_phandle: 0,
root_idx: 0,
},
irq_chip_list: IrqChipList { chips: Vec::new() },
irq_desc: [INIT_IRQ_DESC; 1024],
};
@@ -253,14 +332,20 @@ pub fn register_irq(virq: u32, handler: Box<dyn InterruptHandler>) {
}
#[inline]
pub fn is_reserved(_cpu_id: LogicalCpuId, _index: u8) -> bool {
//TODO
true
pub fn is_reserved(_cpu_id: LogicalCpuId, index: u8) -> bool {
unsafe { IRQ_CHIP.irq_desc[index as usize].basic.used }
}
#[inline]
pub fn set_reserved(_cpu_id: LogicalCpuId, _index: u8, _reserved: bool) {
//TODO
pub fn set_reserved(_cpu_id: LogicalCpuId, index: u8, reserved: bool) {
unsafe {
IRQ_CHIP.irq_desc[index as usize].basic.used = reserved;
if reserved {
IRQ_CHIP.irq_enable(index as u32);
} else {
IRQ_CHIP.irq_enable(index as u32);
}
}
}
pub fn available_irqs_iter(_cpu_id: LogicalCpuId) -> impl Iterator<Item = u8> + 'static {
+4 -3
View File
@@ -28,12 +28,13 @@ pub unsafe fn init(dtb: Option<(usize, usize)>) {
}
pub fn travel_interrupt_ctrl(fdt: &Fdt) {
let root_intr_parent = fdt
if let Some(root_intr_parent) = fdt
.root()
.property("interrupt-parent")
.and_then(NodeProperty::as_usize)
.unwrap();
debug!("root parent = 0x{:08x}", root_intr_parent);
{
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();