xv6TimerInterrupt - ccc-sp/riscv2os GitHub Wiki

xv6: 時間中斷時,會發生甚麼事?

5.4 Timer interrupts

Xv6 uses timer interrupts to maintain its clock and to enable it to switch among compute-bound processes; the yield calls in usertrap and kerneltrap cause this switching. Timer interrupts come from clock hardware attached to each RISC-V CPU. Xv6 programs this clock hardware to interrupt each CPU periodically.

RISC-V requires that timer interrupts be taken in machine mode, not supervisor mode. RISCV machine mode executes without paging, and with a separate set of control registers, so it’s not practical to run ordinary xv6 kernel code in machine mode. As a result, xv6 handles timer interrupts completely separately from the trap mechanism laid out above.

kernel/start.c

// 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..2] : space for timervec to save registers.
  // scratch[3] : address of CLINT MTIMECMP register.
  // scratch[4] : desired interval (in cycles) between timer interrupts.
  uint64 *scratch = &timer_scratch[id][0]; // 設定 scratch 暫存區,[0..2] 保存 a1, a2, a3 等暫存器
  scratch[3] = CLINT_MTIMECMP(id); // 放入 CLINT_MTIMECMP 到 scratch[3] 給 timervec 使用
  scratch[4] = interval;           // 放入 interval 到 scratch[4] 給 timervec 使用
  w_mscratch((uint64)scratch);     // 寫入到 msratch 暫存器

  // set the machine-mode trap handler.
  w_mtvec((uint64)timervec);       // 設定時間中斷函數 (M-mode)

  // enable machine-mode interrupts.
  w_mstatus(r_mstatus() | MSTATUS_MIE); // 啟動中斷 (M-mode)

  // enable machine-mode timer interrupts.
  w_mie(r_mie() | MIE_MTIE); // 啟動時間中斷 (M-mode)
}