diff --git a/Makefile b/Makefile index 59a8e6e..9715e5b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,6 @@ U=user OBJS = \ $K/entry.o \ - $K/start.o \ $K/console.o \ $K/printf.o \ $K/kalloc.o \ diff --git a/kernel/start.c b/kernel/start.c deleted file mode 100644 index 74d8a4f..0000000 --- a/kernel/start.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "types.h" -#include "param.h" -#include "memlayout.h" -#include "riscv.h" -#include "defs.h" - -void timerinit(); - -// a scratch area per CPU for machine-mode timer interrupts. -uint64 timer_scratch[NCPU][5]; - -// assembly code in kernelvec.S for machine-mode timer interrupt. -extern void timervec(); - -// arrange to receive timer interrupts. -// they will arrive in machine mode at -// at timervec in kernelvec.S, -// which turns them into software interrupts for -// devintr() in trap.c. -void timerinit() { - // each CPU has a separate source of timer interrupts. - int id = r_mhartid(); - - // ask the CLINT for a timer interrupt. - int interval = 1000000; // cycles; about 1/10th second in qemu. - *(uint64 *)CLINT_MTIMECMP(id) = *(uint64 *)CLINT_MTIME + interval; - - // prepare information in scratch[] for timervec. - // scratch[0..2] : space for timervec to save registers. - // scratch[3] : address of CLINT MTIMECMP register. - // scratch[4] : desired interval (in cycles) between timer interrupts. - uint64 *scratch = &timer_scratch[id][0]; - scratch[3] = CLINT_MTIMECMP(id); - scratch[4] = interval; - w_mscratch((uint64)scratch); - - // set the machine-mode trap handler. - w_mtvec((uint64)timervec); - - // enable machine-mode interrupts. - w_mstatus(r_mstatus() | MSTATUS_MIE); - - // enable machine-mode timer interrupts. - w_mie(r_mie() | MIE_MTIE); -} diff --git a/theseus/src/memlayout.rs b/theseus/src/memlayout.rs index 114ca5d..4e34cdf 100644 --- a/theseus/src/memlayout.rs +++ b/theseus/src/memlayout.rs @@ -28,13 +28,12 @@ pub const VIRTIO0: i32 = 0x10001000; pub const VIRTIO0_IRQ: i32 = 1; // core local interruptor (CLINT), which contains the timer. -pub const CLINT: i64 = 0x2000000; -// const CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8 * (hartid)); +pub const CLINT: u64 = 0x2000000; #[inline] -pub fn CLINT_MTIMECMP(hartid: i32) -> i64 { - CLINT + 0x4000 + 8 * hartid as i64 +pub fn CLINT_MTIMECMP(hartid: u64) -> *mut u64 { + (CLINT + 0x4000 + 8 * hartid) as *mut u64 } -pub const CLINT_MTIME: i64 = CLINT + 0xBFF8; // cycles since boot. +pub const CLINT_MTIME: *mut u64 = (CLINT + 0xBFF8) as *mut u64; // cycles since boot. // qemu puts platform-level interrupt controller (PLIC) here. pub const PLIC: i64 = 0x0c000000; diff --git a/theseus/src/riscv.rs b/theseus/src/riscv.rs index 7d5d7b8..94994d2 100644 --- a/theseus/src/riscv.rs +++ b/theseus/src/riscv.rs @@ -93,16 +93,21 @@ pub unsafe fn w_sie(x: u64) { } // // Machine-mode Interrupt Enable -// #define MIE_MEIE (1L << 11) // external -// #define MIE_MTIE (1L << 7) // timer -// #define MIE_MSIE (1L << 3) // software -// static inline uint64 r_mie() { -// uint64 x; -// asm volatile("csrr %0, mie" : "=r"(x)); -// return x; -// } +pub const MIE_MEIE: u64 = 1 << 11; // external +pub const MIE_MTIE: u64 = 1 << 7; // timer +pub const MIE_MSIE: u64 = 1 << 3; // software -// static inline void w_mie(uint64 x) { asm volatile("csrw mie, %0" : : "r"(x)); } +#[inline] +pub unsafe fn r_mie() -> u64 { + let x: u64; + asm!("csrr {x}, mie", x = out(reg) x); + x +} + +#[inline] +pub unsafe fn w_mie(x: u64) { + asm!("csrw mie, {x}", x = in(reg) x); +} // // supervisor exception program counter, holds the // // instruction address to which a return from @@ -124,9 +129,6 @@ pub unsafe fn w_sie(x: u64) { // return x; // } -// static inline void w_medeleg(uint64 x) { -// asm volatile("csrw medeleg, %0" : : "r"(x)); -// } #[inline] pub unsafe fn w_medeleg(x: u64) { asm!("csrw medeleg, {x}", x = in(reg) x); @@ -139,9 +141,6 @@ pub unsafe fn w_medeleg(x: u64) { // return x; // } -// static inline void w_mideleg(uint64 x) { -// asm volatile("csrw mideleg, %0" : : "r"(x)); -// } #[inline] pub unsafe fn w_mideleg(x: u64) { asm!("csrw mideleg, {x}", x = in(reg) x); @@ -160,22 +159,17 @@ pub unsafe fn w_mideleg(x: u64) { // } // // Machine-mode interrupt vector -// static inline void w_mtvec(uint64 x) { -// asm volatile("csrw mtvec, %0" : : "r"(x)); -// } +#[inline] +pub unsafe fn w_mtvec(x: u64) { + asm!("csrw mtvec, {x}", x = in(reg) x); +} -// // Physical Memory Protection -// static inline void w_pmpcfg0(uint64 x) { -// asm volatile("csrw pmpcfg0, %0" : : "r"(x)); -// } +// Physical Memory Protection #[inline] pub unsafe fn w_pmpcfg0(x: u64) { asm!("csrw pmpcfg0, {x}", x = in(reg) x); } -// static inline void w_pmpaddr0(uint64 x) { -// asm volatile("csrw pmpaddr0, %0" : : "r"(x)); -// } #[inline] pub unsafe fn w_pmpaddr0(x: u64) { asm!("csrw pmpaddr0, {x}", x = in(reg) x); @@ -186,11 +180,8 @@ pub unsafe fn w_pmpaddr0(x: u64) { // #define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12)) -// // supervisor address translation and protection; -// // holds the address of the page table. -// static inline void w_satp(uint64 x) { -// asm volatile("csrw satp, %0" : : "r"(x)); -// } +// supervisor address translation and protection; +// holds the address of the page table. #[inline] pub unsafe fn w_satp(x: u64) { asm!("csrw satp, {x}", x = in(reg) x); @@ -202,9 +193,10 @@ pub unsafe fn w_satp(x: u64) { // return x; // } -// static inline void w_mscratch(uint64 x) { -// asm volatile("csrw mscratch, %0" : : "r"(x)); -// } +#[inline] +pub unsafe fn w_mscratch(x: u64) { + asm!("csrw mscratch, {x}", x = in(reg) x); +} // // Supervisor Trap Cause // static inline uint64 r_scause() { diff --git a/theseus/src/start.rs b/theseus/src/start.rs index 5bd0673..9f095d6 100644 --- a/theseus/src/start.rs +++ b/theseus/src/start.rs @@ -1,20 +1,27 @@ use core::arch::asm; +use core::usize; +use crate::memlayout::{CLINT_MTIME, CLINT_MTIMECMP}; use crate::param::NCPU; use crate::riscv as rv; extern "C" { - // start.c - fn timerinit(); + // assembly code in kernelvec.S for machine-mode timer interrupt. + fn timervec(); // main.c fn main(); } #[repr(align(16))] -pub struct AlignedStack([u8; 4096 * NCPU]); +pub struct EntryStack([u8; 4096 * NCPU]); + +// entry.S needs one stack per CPU. #[no_mangle] -pub static mut stack0: AlignedStack = AlignedStack([0; 4096 * NCPU]); +pub static mut stack0: EntryStack = EntryStack([0; 4096 * NCPU]); + +// a scratch area per CPU for machine-mode timer interrupts. +static mut timer_scratch: [[u64; 5]; NCPU] = [[0; 5]; NCPU]; // entry.S jumps here in machine mode on stack0. #[no_mangle] @@ -52,3 +59,36 @@ pub unsafe extern "C" fn start() { // switch to supervisor mode and jump to main(). asm!("mret"); } + +// arrange to receive timer interrupts. +// they will arrive in machine mode at +// at timervec in kernelvec.S, +// which turns them into software interrupts for +// devintr() in trap.c. +unsafe fn timerinit() { + // each CPU has a separate source of timer interrupts. + let id = rv::r_mhartid(); + + // ask the CLINT for a timer interrupt. + let interval: u64 = 1000000; // cycles; about 1/10th second in qemu. + *CLINT_MTIMECMP(id) = *CLINT_MTIME + interval; + + // prepare information in scratch[] for timervec. + // scratch[0..2] : space for timervec to save registers. + // scratch[3] : address of CLINT MTIMECMP register. + // scratch[4] : desired interval (in cycles) between timer interrupts. + timer_scratch[id as usize][3] = CLINT_MTIMECMP(id) as u64; + timer_scratch[id as usize][4] = interval; + + // w_mscratch((uint64)scratch); + rv::w_mscratch(timer_scratch[id as usize].as_ptr() as u64); + + // set the machine-mode trap handler. + rv::w_mtvec(timervec as *const () as u64); + + // enable machine-mode interrupts. + rv::w_mstatus(rv::r_mstatus() | rv::MSTATUS_MIE); + + // enable machine-mode timer interrupts. + rv::w_mie(rv::r_mie() | rv::MIE_MTIE); +}