diff --git a/kernel/kernelvec.S b/kernel/kernelvec.S index 0efde8b..9aabe96 100644 --- a/kernel/kernelvec.S +++ b/kernel/kernelvec.S @@ -86,6 +86,11 @@ kernelvec: .globl machinevec .align 4 machinevec: + # start.c has set up the memory that mscratch points to: + # scratch[0,8,16] : register save area. + # scratch[32] : address of CLINT's MTIMECMP register. + # scratch[40] : desired interval between interrupts. + csrrw a0, mscratch, a0 sd a1, 0(a0) sd a2, 8(a0) diff --git a/kernel/memlayout.h b/kernel/memlayout.h index ace0464..fdfeab7 100644 --- a/kernel/memlayout.h +++ b/kernel/memlayout.h @@ -29,7 +29,7 @@ // local interrupt controller, which contains the timer. #define CLINT 0x2000000L #define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid)) -#define CLINT_MTIME (CLINT + 0xBFF8) +#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot. // qemu puts programmable interrupt controller here. #define PLIC 0x0c000000L diff --git a/kernel/riscv.h b/kernel/riscv.h index e35f3bc..63f71b4 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -9,11 +9,11 @@ r_mhartid() // Machine Status Register, mstatus -#define MSTATUS_MPP_MASK (3L << 11) +#define MSTATUS_MPP_MASK (3L << 11) // previous mode. #define MSTATUS_MPP_M (3L << 11) #define MSTATUS_MPP_S (1L << 11) #define MSTATUS_MPP_U (0L << 11) -#define MSTATUS_MIE (1L << 3) +#define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable. static inline uint64 r_mstatus() @@ -95,8 +95,8 @@ w_sie(uint64 x) // Machine-mode Interrupt Enable #define MIE_MEIE (1L << 11) // external -#define MIE_MTIE (1L << 7) // timer -#define MIE_MSIE (1L << 3) // software +#define MIE_MTIE (1L << 7) // timer +#define MIE_MSIE (1L << 3) // software static inline uint64 r_mie() { diff --git a/kernel/start.c b/kernel/start.c index ea896eb..6dc106d 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -37,16 +37,26 @@ start() w_mideleg(0xffff); // set up to receive timer interrupts in machine mode, - // for pre-emptive switching and (on hart 0) to drive time. + // which arrive at machinevec in kernelvec.S, + // which turns them into software interrupts for + // devintr() in trap.c. int id = r_mhartid(); - uint64 *scratch = &mscratch0[32 * id]; + // ask the CLINT for a timer interrupt 10,000 cycles from now. *(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + 10000; + // prepare information in scratch[] for machinevec. + // scratch[0..3] : space for machinevec to save registers. + // scratch[4] : address of CLINT MTIMECMP register. + // scratch[5] : desired interval (in cycles) between timer interrupts. + uint64 *scratch = &mscratch0[32 * id]; scratch[4] = CLINT_MTIMECMP(id); scratch[5] = 10000000; w_mscratch((uint64)scratch); + // set the machine-mode trap handler. w_mtvec((uint64)machinevec); + // enable machine-mode interrupts. w_mstatus(r_mstatus() | MSTATUS_MIE); - w_mie(r_mie() | MIE_MTIE); + // enable machine-mode timer interrupts. + w_mie(r_mie() | MIE_MTIE); // keep each CPU's hartid in its tp register, for cpuid(). w_tp(id);