restructure interrupt handling to be architecture-specific
This commit is contained in:
parent
33e1f3d318
commit
d3d9526ffa
10
kernel/rustkernel/src/arch/interrupt.rs
Normal file
10
kernel/rustkernel/src/arch/interrupt.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//! Architecture-agnostic interrupt handling.
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use super::riscv::plic::plic_claim as handle_interrupt;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use super::riscv::plic::plic_complete as complete_interrupt;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use super::riscv::plic::plicinit as init;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use super::riscv::plic::plicinithart as inithart;
|
@ -1 +1,4 @@
|
|||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
pub mod riscv;
|
pub mod riscv;
|
||||||
|
|
||||||
|
pub mod interrupt;
|
||||||
|
@ -23,11 +23,11 @@ pub const QEMU_POWER: u64 = 0x100000u64;
|
|||||||
|
|
||||||
// QEMU puts UART registers here in physical memory.
|
// QEMU puts UART registers here in physical memory.
|
||||||
pub const UART0: usize = 0x10000000;
|
pub const UART0: usize = 0x10000000;
|
||||||
pub const UART0_IRQ: i32 = 10;
|
pub const UART0_IRQ: usize = 10;
|
||||||
|
|
||||||
// Virtio MMIO interface
|
// Virtio MMIO interface
|
||||||
pub const VIRTIO0: u64 = 0x10001000;
|
pub const VIRTIO0: usize = 0x10001000;
|
||||||
pub const VIRTIO0_IRQ: i32 = 1;
|
pub const VIRTIO0_IRQ: usize = 1;
|
||||||
|
|
||||||
// Core Local Interrupter (CLINT), which contains the timer.
|
// Core Local Interrupter (CLINT), which contains the timer.
|
||||||
pub const CLINT: u64 = 0x2000000;
|
pub const CLINT: u64 = 0x2000000;
|
||||||
@ -36,29 +36,6 @@ pub fn clint_mtimecmp(hartid: u64) -> u64 {
|
|||||||
CLINT + 0x4000 + (8 * hartid)
|
CLINT + 0x4000 + (8 * hartid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QEMU puts platform-level interrupt controller (PLIC) here.
|
|
||||||
pub const PLIC: u64 = 0x0c000000;
|
|
||||||
pub const PLIC_PRIORITY: u64 = PLIC;
|
|
||||||
pub const PLIC_PENDING: u64 = PLIC + 0x1000;
|
|
||||||
pub fn plic_menable(hartid: u64) -> u64 {
|
|
||||||
PLIC + 0x2000 + (0x100 * hartid)
|
|
||||||
}
|
|
||||||
pub fn plic_senable(hartid: u64) -> u64 {
|
|
||||||
PLIC + 0x2080 + (0x100 * hartid)
|
|
||||||
}
|
|
||||||
pub fn plic_mpriority(hartid: u64) -> u64 {
|
|
||||||
PLIC + 0x200000 + (0x2000 * hartid)
|
|
||||||
}
|
|
||||||
pub fn plic_spriority(hartid: u64) -> u64 {
|
|
||||||
PLIC + 0x201000 + (0x2000 * hartid)
|
|
||||||
}
|
|
||||||
pub fn plic_mclaim(hartid: u64) -> u64 {
|
|
||||||
PLIC + 0x200004 + (0x2000 * hartid)
|
|
||||||
}
|
|
||||||
pub fn plic_sclaim(hartid: u64) -> u64 {
|
|
||||||
PLIC + 0x201004 + (0x2000 * hartid)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The kernel expects there to be RAM
|
// The kernel expects there to be RAM
|
||||||
// for use by the kernel and user pages
|
// for use by the kernel and user pages
|
||||||
// from physical address 0x80000000 to PHYSTOP.
|
// from physical address 0x80000000 to PHYSTOP.
|
||||||
|
@ -1,35 +1,67 @@
|
|||||||
//! The RISC-V Platform Level Interrupt Controller (PLIC)
|
//! The RISC-V Platform Level Interrupt Controller (PLIC)
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::riscv::{plic_sclaim, plic_senable, plic_spriority, PLIC, UART0_IRQ, VIRTIO0_IRQ},
|
arch::riscv::{UART0_IRQ, VIRTIO0_IRQ},
|
||||||
proc::cpu::Cpu,
|
proc::cpu::Cpu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// QEMU puts platform-level interrupt controller (PLIC) here.
|
||||||
|
pub const PLIC: usize = 0x0c000000;
|
||||||
|
const PLIC_PRIORITY: usize = PLIC;
|
||||||
|
const PLIC_PENDING: usize = PLIC + 0x1000;
|
||||||
|
const UART0_IRQ_ADDR: usize = PLIC + UART0_IRQ * 4;
|
||||||
|
const VIRTIO0_IRQ_ADDR: usize = PLIC + VIRTIO0_IRQ * 4;
|
||||||
|
|
||||||
|
/// Get a pointer to the CPU-specific machine-mode enable register.
|
||||||
|
fn plic_menable(hartid: usize) -> *mut u32 {
|
||||||
|
(PLIC + 0x2000 + (0x100 * hartid)) as *mut u32
|
||||||
|
}
|
||||||
|
/// Get a pointer to the CPU-specific supervisor-mode enable register.
|
||||||
|
fn plic_senable(hartid: usize) -> *mut u32 {
|
||||||
|
(PLIC + 0x2080 + (0x100 * hartid)) as *mut u32
|
||||||
|
}
|
||||||
|
/// Get a pointer to the CPU-specific machine-mode priority register.
|
||||||
|
fn plic_mpriority(hartid: usize) -> *mut u32 {
|
||||||
|
(PLIC + 0x200000 + (0x2000 * hartid)) as *mut u32
|
||||||
|
}
|
||||||
|
/// Get a pointer to the CPU-specific supervisor-mode priority register.
|
||||||
|
fn plic_spriority(hartid: usize) -> *mut u32 {
|
||||||
|
(PLIC + 0x201000 + (0x2000 * hartid)) as *mut u32
|
||||||
|
}
|
||||||
|
/// Get a pointer to the CPU-specific machine-mode claim register.
|
||||||
|
fn plic_mclaim(hartid: usize) -> *mut u32 {
|
||||||
|
(PLIC + 0x200004 + (0x2000 * hartid)) as *mut u32
|
||||||
|
}
|
||||||
|
/// Get a pointer to the CPU-specific supervisor-mode claim register.
|
||||||
|
fn plic_sclaim(hartid: usize) -> *mut u32 {
|
||||||
|
(PLIC + 0x201004 + (0x2000 * hartid)) as *mut u32
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn plicinit() {
|
pub unsafe fn plicinit() {
|
||||||
// Set desired IRQ priorities non-zero (otherwise disabled).
|
// Set desired IRQ priorities non-zero (otherwise disabled).
|
||||||
*((PLIC + UART0_IRQ as u64 * 4) as *mut u32) = 1;
|
*(UART0_IRQ_ADDR as *mut u32) = 1;
|
||||||
*((PLIC + VIRTIO0_IRQ as u64 * 4) as *mut u32) = 1;
|
*(VIRTIO0_IRQ_ADDR as *mut u32) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn plicinithart() {
|
pub unsafe fn plicinithart() {
|
||||||
let hart = Cpu::current_id() as u64;
|
let hart = Cpu::current_id();
|
||||||
|
|
||||||
// Set enable bits for this hart's S-mode
|
// Set enable bits for this hart's S-mode
|
||||||
// for the UART and VIRTIO disk.
|
// for the UART and VIRTIO disk.
|
||||||
*(plic_senable(hart) as *mut u32) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
*plic_senable(hart) = (1 << UART0_IRQ) | (1 << VIRTIO0_IRQ);
|
||||||
|
|
||||||
// Set this hart's S-mode priority threshold to 0.
|
// Set this hart's S-mode priority threshold to 0.
|
||||||
*(plic_spriority(hart) as *mut u32) = 0;
|
*plic_spriority(hart) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the PLIC what interrupt we should serve.
|
/// Ask the PLIC what interrupt we should serve.
|
||||||
pub unsafe fn plic_claim() -> i32 {
|
pub unsafe fn plic_claim() -> usize {
|
||||||
let hart = Cpu::current_id() as u64;
|
let hart = Cpu::current_id();
|
||||||
*(plic_sclaim(hart) as *const i32)
|
(*plic_sclaim(hart)) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell the PLIC we've served this IRQ.
|
/// Tell the PLIC we've served this IRQ.
|
||||||
pub unsafe fn plic_complete(irq: i32) {
|
pub unsafe fn plic_complete(irq: usize) {
|
||||||
let hart = Cpu::current_id() as u64;
|
let hart = Cpu::current_id();
|
||||||
*(plic_sclaim(hart) as *mut i32) = irq;
|
*plic_sclaim(hart) = irq as u32;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use crate::sync::lock::Lock;
|
use crate::sync::lock::Lock;
|
||||||
use core::ffi::{c_char, CStr};
|
use core::ffi::{c_char, CStr};
|
||||||
|
|
||||||
pub use crate::panic;
|
|
||||||
|
|
||||||
pub static PRINT_LOCK: Lock = Lock::new();
|
pub static PRINT_LOCK: Lock = Lock::new();
|
||||||
|
|
||||||
/// Print out formatted text to the console.
|
/// Print out formatted text to the console.
|
||||||
@ -40,7 +38,7 @@ macro_rules! uprint {
|
|||||||
// only uses the &mut reference immutably.
|
// only uses the &mut reference immutably.
|
||||||
let uart: *const Uart = &$crate::console::uart::UART0 as *const Uart;
|
let uart: *const Uart = &$crate::console::uart::UART0 as *const Uart;
|
||||||
let uart: &mut Uart = unsafe { &mut *uart.cast_mut() };
|
let uart: &mut Uart = unsafe { &mut *uart.cast_mut() };
|
||||||
|
|
||||||
let _ = core::write!(uart, $($arg)*);
|
let _ = core::write!(uart, $($arg)*);
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@ -55,7 +53,6 @@ macro_rules! uprintln {
|
|||||||
}
|
}
|
||||||
pub(crate) use uprintln;
|
pub(crate) use uprintln;
|
||||||
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn printint(n: i32) {
|
pub extern "C" fn printint(n: i32) {
|
||||||
print!("{}", n);
|
print!("{}", n);
|
||||||
|
@ -24,7 +24,7 @@ mod trap;
|
|||||||
use crate::{proc::cpu::Cpu, sync::mutex::Mutex};
|
use crate::{proc::cpu::Cpu, sync::mutex::Mutex};
|
||||||
use core::ffi::{c_char, CStr};
|
use core::ffi::{c_char, CStr};
|
||||||
|
|
||||||
pub(crate) use crate::console::printf::{print, println, uprint, uprintln};
|
pub(crate) use crate::console::printf::{print, println, uprintln};
|
||||||
|
|
||||||
pub static mut STARTED: bool = false;
|
pub static mut STARTED: bool = false;
|
||||||
pub static PANICKED: Mutex<bool> = Mutex::new(false);
|
pub static PANICKED: Mutex<bool> = Mutex::new(false);
|
||||||
@ -65,8 +65,8 @@ pub unsafe fn main() -> ! {
|
|||||||
mem::virtual_memory::kvminithart();
|
mem::virtual_memory::kvminithart();
|
||||||
proc::process::procinit();
|
proc::process::procinit();
|
||||||
trap::trapinithart();
|
trap::trapinithart();
|
||||||
arch::riscv::plic::plicinit();
|
arch::interrupt::init();
|
||||||
arch::riscv::plic::plicinithart();
|
arch::interrupt::inithart();
|
||||||
io::bio::binit();
|
io::bio::binit();
|
||||||
fs::iinit();
|
fs::iinit();
|
||||||
fs::file::fileinit();
|
fs::file::fileinit();
|
||||||
@ -79,7 +79,7 @@ pub unsafe fn main() -> ! {
|
|||||||
}
|
}
|
||||||
mem::virtual_memory::kvminithart();
|
mem::virtual_memory::kvminithart();
|
||||||
trap::trapinithart();
|
trap::trapinithart();
|
||||||
arch::riscv::plic::plicinithart();
|
arch::interrupt::inithart();
|
||||||
}
|
}
|
||||||
|
|
||||||
proc::scheduler::scheduler();
|
proc::scheduler::scheduler();
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::riscv::{
|
arch::riscv::{
|
||||||
memlayout::{KERNBASE, PHYSTOP, TRAMPOLINE},
|
memlayout::{KERNBASE, PHYSTOP, TRAMPOLINE, UART0, VIRTIO0, QEMU_POWER},
|
||||||
*,
|
plic::PLIC,
|
||||||
|
asm,
|
||||||
|
PGSIZE,
|
||||||
|
pg_round_down,
|
||||||
|
pg_round_up,
|
||||||
|
Pagetable,
|
||||||
|
PagetableEntry,
|
||||||
|
PTE_V,
|
||||||
|
PTE_R,
|
||||||
|
PTE_W,
|
||||||
|
PTE_X,
|
||||||
|
PTE_U,
|
||||||
|
MAXVA,
|
||||||
|
pte2pa,
|
||||||
|
make_satp,
|
||||||
},
|
},
|
||||||
mem::{
|
mem::{
|
||||||
kalloc::{kalloc, kfree},
|
kalloc::{kalloc, kfree},
|
||||||
@ -33,10 +47,22 @@ pub unsafe fn kvmmake() -> Pagetable {
|
|||||||
kvmmap(pagetable, UART0 as u64, UART0 as u64, PGSIZE, PTE_R | PTE_W);
|
kvmmap(pagetable, UART0 as u64, UART0 as u64, PGSIZE, PTE_R | PTE_W);
|
||||||
|
|
||||||
// VirtIO MMIO disk interface
|
// VirtIO MMIO disk interface
|
||||||
kvmmap(pagetable, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
|
kvmmap(
|
||||||
|
pagetable,
|
||||||
|
VIRTIO0 as u64,
|
||||||
|
VIRTIO0 as u64,
|
||||||
|
PGSIZE,
|
||||||
|
PTE_R | PTE_W,
|
||||||
|
);
|
||||||
|
|
||||||
// PLIC
|
// PLIC
|
||||||
kvmmap(pagetable, PLIC, PLIC, 0x400000u64, PTE_R | PTE_W);
|
kvmmap(
|
||||||
|
pagetable,
|
||||||
|
PLIC as u64,
|
||||||
|
PLIC as u64,
|
||||||
|
0x400000u64,
|
||||||
|
PTE_R | PTE_W,
|
||||||
|
);
|
||||||
|
|
||||||
let etext_addr = addr_of!(etext) as usize as u64;
|
let etext_addr = addr_of!(etext) as usize as u64;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::riscv::*,
|
arch::{self, riscv::*},
|
||||||
println,
|
println,
|
||||||
proc::{
|
proc::{
|
||||||
cpu::Cpu,
|
cpu::Cpu,
|
||||||
@ -49,7 +49,7 @@ pub unsafe fn devintr() -> i32 {
|
|||||||
// This is a supervisor external interrupt, via PLIC.
|
// This is a supervisor external interrupt, via PLIC.
|
||||||
|
|
||||||
// IRQ indicates which device interrupted.
|
// IRQ indicates which device interrupted.
|
||||||
let irq = plic::plic_claim();
|
let irq = arch::interrupt::handle_interrupt();
|
||||||
|
|
||||||
if irq == UART0_IRQ {
|
if irq == UART0_IRQ {
|
||||||
crate::console::uart::UART0.interrupt();
|
crate::console::uart::UART0.interrupt();
|
||||||
@ -63,7 +63,7 @@ pub unsafe fn devintr() -> i32 {
|
|||||||
// interrupt at a time; tell the PLIC the device is
|
// interrupt at a time; tell the PLIC the device is
|
||||||
// now allowed to interrupt again.
|
// now allowed to interrupt again.
|
||||||
if irq > 0 {
|
if irq > 0 {
|
||||||
plic::plic_complete(irq);
|
arch::interrupt::complete_interrupt(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
1
|
1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user