1 #include "types.h" 2 #include "param.h" 3 #include "memlayout.h" 4 #include "riscv.h" 5 #include "defs.h" 6 7 void main(); 8 void timerinit(); 9 10 // entry.S needs one stack per CPU. 11 __attribute__ ((aligned (16))) char stack0[4096 * NCPU]; 12 13 // a scratch area per CPU for machine-mode timer interrupts. 14 uint64 timer_scratch[NCPU][5]; 15 16 // assembly code in kernelvec.S for machine-mode timer interrupt. 17 extern void timervec(); 18 19 // entry.S jumps here in machine mode on stack0. 20 void 21 start() 22 { 23 // set M Previous Privilege mode to Supervisor, for mret. 24 unsigned long x = r_mstatus(); 25 x &= ~MSTATUS_MPP_MASK; 26 x |= MSTATUS_MPP_S; 27 w_mstatus(x); 28 29 // set M Exception Program Counter to main, for mret. 30 // requires gcc -mcmodel=medany 31 w_mepc((uint64)main); 32 33 // disable paging for now. 34 w_satp(0); 35 36 // delegate all interrupts and exceptions to supervisor mode. 37 w_medeleg(0xffff); 38 w_mideleg(0xffff); 39 w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE); 40 41 // configure Physical Memory Protection to give supervisor mode 42 // access to all of physical memory. 43 w_pmpaddr0(0x3fffffffffffffull); 44 w_pmpcfg0(0xf); 45 46 // ask for clock interrupts. 47 timerinit(); 48 49 // keep each CPU's hartid in its tp register, for cpuid(). 50 int id = r_mhartid(); 51 w_tp(id); 52 53 // switch to supervisor mode and jump to main(). 54 asm volatile("mret"); 55 } 56 57 // arrange to receive timer interrupts. 58 // they will arrive in machine mode at 59 // at timervec in kernelvec.S, 60 // which turns them into software interrupts for 61 // devintr() in trap.c. 62 void 63 timerinit() 64 { 65 // each CPU has a separate source of timer interrupts. 66 int id = r_mhartid(); 67 68 // ask the CLINT for a timer interrupt. 69 int interval = 1000000; // cycles; about 1/10th second in qemu. 70 *(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + interval; 71 72 // prepare information in scratch[] for timervec. 73 // scratch[0..2] : space for timervec to save registers. 74 // scratch[3] : address of CLINT MTIMECMP register. 75 // scratch[4] : desired interval (in cycles) between timer interrupts. 76 uint64 *scratch = &timer_scratch[id][0]; 77 scratch[3] = CLINT_MTIMECMP(id); 78 scratch[4] = interval; 79 w_mscratch((uint64)scratch); 80 81 // set the machine-mode trap handler. 82 w_mtvec((uint64)timervec); 83 84 // enable machine-mode interrupts. 85 w_mstatus(r_mstatus() | MSTATUS_MIE); 86 87 // enable machine-mode timer interrupts. 88 w_mie(r_mie() | MIE_MTIE); 89 }