#include "types.h" #include "param.h" #include "memlayout.h" #include "riscv.h" void main(); void timerinit(); // Entry.S needs one stack per CPU. __attribute__((aligned(16))) char stack0[4096 * NCPU]; // A scratch area per CPU for machine-mode timer interrupts. u64 timer_scratch[NCPU][5]; // Assembly code in kernelvec.S for machine-mode timer interrupt. extern void timervec(); // Entry.S jumps here in machine mode on stack0. void start() { // Set M Previous Privilege mode to Supervisor, for mret. unsigned long x = r_mstatus(); x &= ~MSTATUS_MPP_MASK; x |= MSTATUS_MPP_S; w_mstatus(x); // Set M Exception Program Counter to main, for mret. // Requires gcc -mcmodel=medany w_mepc((u64)main); // Disable paging for now. w_satp(0); // Delegate all interrupts and exceptions to supervisor mode. w_medeleg(0xffff); w_mideleg(0xffff); w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE); // Configure Physical Memory Protection to give supervisor mode // Access to all of physical memory. w_pmpaddr0(0x3fffffffffffffull); w_pmpcfg0(0xf); // Ask for clock interrupts. timerinit(); // Keep each CPU's hartid in its tp register, for cpuid(). int id = r_mhartid(); w_tp(id); // Switch to supervisor mode and jump to main(). asm volatile("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. 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. *(u64 *)CLINT_MTIMECMP(id) = *(u64 *)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. u64 *scratch = &timer_scratch[id][0]; scratch[3] = CLINT_MTIMECMP(id); scratch[4] = interval; w_mscratch((u64)scratch); // Set the machine-mode trap handler. w_mtvec((u64)timervec); // Enable machine-mode interrupts. w_mstatus(r_mstatus() | MSTATUS_MIE); // Enable machine-mode timer interrupts. w_mie(r_mie() | MIE_MTIE); }