diff options
Diffstat (limited to 'kernel/start.c')
-rw-r--r-- | kernel/start.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/kernel/start.c b/kernel/start.c new file mode 100644 index 0000000..203c5e6 --- /dev/null +++ b/kernel/start.c @@ -0,0 +1,82 @@ +#include "types.h" +#include "param.h" +#include "memlayout.h" +#include "riscv.h" +#include "defs.h" + +void main(); +void timerinit(); + +// entry.S needs one stack per CPU. +__attribute__ ((aligned (16))) char stack0[4096 * NCPU]; + +// scratch area for timer interrupt, one per CPU. +uint64 mscratch0[NCPU * 32]; + +// 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((uint64)main); + + // disable paging for now. + w_satp(0); + + // delegate all interrupts and exceptions to supervisor mode. + w_medeleg(0xffff); + w_mideleg(0xffff); + + // 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"); +} + +// set up to receive timer interrupts in machine mode, +// which arrive 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..3] : space for timervec 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] = 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); +} |