5.4 定时器中断
Xv6使用定时器中断来维持其时钟,并使其能够在受计算量限制的进程(compute-bound processes)之间切换;usertrap
和kerneltrap
中的yield
调用会导致这种切换。定时器中断来自附加到每个RISC-V CPU上的时钟硬件。Xv6对该时钟硬件进行编程,以定期中断每个CPU。
RISC-V要求定时器中断在机器模式而不是管理模式下进行。RISC-V机器模式无需分页即可执行,并且有一组单独的控制寄存器,因此在机器模式下运行普通的xv6内核代码是不实际的。因此,xv6处理定时器中断完全不同于上面列出的陷阱机制。
机器模式下执行的代码位于main
之前的start.c中,它设置了接收定时器中断(kernel/start.c:57)。工作的一部分是对CLINT(core-local interruptor)硬件编程,以在特定延迟后生成中断。另一部分是设置一个scratch区域,类似于trapframe,以帮助定时器中断处理程序保存寄存器和CLINT寄存器的地址。最后,start
将mtvec
设置为timervec
,并使能定时器中断。
计时器中断可能发生在用户或内核代码正在执行的任何时候;内核无法在临界区操作期间禁用计时器中断。因此,计时器中断处理程序必须保证不干扰中断的内核代码。基本策略是处理程序要求RISC-V发出“软件中断”并立即返回。RISC-V用普通陷阱机制将软件中断传递给内核,并允许内核禁用它们。处理由定时器中断产生的软件中断的代码可以在devintr
(kernel/trap.c:204)中看到。
机器模式定时器中断向量是timervec
(kernel/kernelvec.S:93)。它在start
准备的scratch区域中保存一些寄存器,以告诉CLINT何时生成下一个定时器中断,要求RISC-V引发软件中断,恢复寄存器,并且返回。定时器中断处理程序中没有C代码。