diff --git a/kernel/defs.h b/kernel/defs.h index a3c962b37d..6fd054fb18 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -9,6 +9,9 @@ struct sleeplock; struct stat; struct superblock; +// start.c +void timerhalt(void); + // bio.c void binit(void); struct buf* bread(uint, uint); diff --git a/kernel/kernelvec.S b/kernel/kernelvec.S index fb31b328c4..538e5c892d 100644 --- a/kernel/kernelvec.S +++ b/kernel/kernelvec.S @@ -97,12 +97,17 @@ timervec: # scratch[0,8,16] : register save area. # scratch[24] : address of CLINT's MTIMECMP register. # scratch[32] : desired interval between interrupts. + # scratch[40] : halt flag set by timerhalt. csrrw a0, mscratch, a0 sd a1, 0(a0) sd a2, 8(a0) sd a3, 16(a0) + # halt if timerhalt has set halt flag to 1 + ld a1, 40(a0) + bne a1, zero, halt + # schedule the next timer interrupt # by adding interval to mtimecmp. ld a1, 24(a0) # CLINT_MTIMECMP(hart) @@ -122,3 +127,14 @@ timervec: csrrw a0, mscratch, a0 mret + +halt: + # based on qemu's hw/riscv/virt.c: + # qemu halts if FINISHER_PASS(=0x5555) is + # written at address *VIRT_TEST(=0x100000L) + lui a1, 0x100 + lui a2, 0x5 + addi a2, a2, 0x555 + sw a2, 0(a1) +spin: + j spin diff --git a/kernel/printf.c b/kernel/printf.c index 1a50203d9a..7246eea43c 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -123,6 +123,7 @@ panic(char *s) printf(s); printf("\n"); panicked = 1; // freeze uart output from other CPUs + timerhalt(); for(;;) ; } diff --git a/kernel/start.c b/kernel/start.c index e16f18a37b..b15829d29d 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -11,7 +11,7 @@ void timerinit(); __attribute__ ((aligned (16))) char stack0[4096 * NCPU]; // a scratch area per CPU for machine-mode timer interrupts. -uint64 timer_scratch[NCPU][5]; +uint64 timer_scratch[NCPU][6]; // assembly code in kernelvec.S for machine-mode timer interrupt. extern void timervec(); @@ -73,9 +73,11 @@ timerinit() // 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. + // scratch[5] : halt flag to signal halt to timervec. uint64 *scratch = &timer_scratch[id][0]; scratch[3] = CLINT_MTIMECMP(id); scratch[4] = interval; + scratch[5] = 0; w_mscratch((uint64)scratch); // set the machine-mode trap handler. @@ -87,3 +89,12 @@ timerinit() // enable machine-mode timer interrupts. w_mie(r_mie() | MIE_MTIE); } + +// signal halt to timervec. +void +timerhalt() +{ + uint64 *scratch = &timer_scratch[0][0]; + scratch[5] = 1; + w_mscratch((uint64)scratch); +}