Skip to content

Commit

Permalink
added a timerhalt() function
Browse files Browse the repository at this point in the history
The virt QEMU board integrates a "test finisher" device.
Writing FINISHER_PASS(=0x5555) to its address which
is VIRT_TEST(=0x100000), will halt virt machine.

Since this should be done in machine mode, a new flag
is set by timerhalt() in supervisor mode. Later timervec()
will check this flag, which is at the end of timer scratch
area. If the halt flag is not zero, it will branch to halt.

It can be used to halt when kernel panics in printf.c
It can be triggered in user mode by killing init process,
using the following command at shell:
kill 1
  • Loading branch information
meighti committed Mar 27, 2023
1 parent f5b93ef commit a4288af
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 1 deletion.
3 changes: 3 additions & 0 deletions kernel/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
16 changes: 16 additions & 0 deletions kernel/kernelvec.S
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
1 change: 1 addition & 0 deletions kernel/printf.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ panic(char *s)
printf(s);
printf("\n");
panicked = 1; // freeze uart output from other CPUs
timerhalt();
for(;;)
;
}
Expand Down
13 changes: 12 additions & 1 deletion kernel/start.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}

0 comments on commit a4288af

Please sign in to comment.