#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); }