中断/异常委托机制的说明
默认情况下,所有特权级的中断和异常都会被发送给机器模式(Machine Mode, 以下简称M态),然后运行在M态的软件再根据中断/异常的目标特权级,转发给较低特权级去处理,转发手段通常是中断/异常注入(例如设置sip来注入S态中断)。但是这样的效率很低,所以RISC-V引入了委托机制,在硬件层面设置mideleg/medeleg,绕过M态,直接把低特权级的中断/异常路由给目标特权级处理。以下通过具体的场景来说明。
未启用中断委托机制时的场景(默认情况)
如图1,典型场景下M/S/U三态分别对应运行OpenSBI,Linux Kernel和用户态应用。

图1 - 未启用中断委托时的默认场景
默认未启用 中断委托时,mideleg相当于被短路,中断源发出的各种中断穿越该寄存器后,先到达中断开关(en),如果对应中断是开启的,就会沿着CPU的M态中断处理通道到达mtvec寄存器,这里是软件中断向量表的入口,从此处开始转入OpenSBI软件对中断的处理,如果发现中断其实是发给S态Linux的,还要再通过中断注入的方式继续转发。
注:中断开关en分为两级,全局开关是mstatus中的mie位,另外寄存器mie中的一些bit是针对每个中断号的特定开关,两级都启用才能让中断通过。
启用中断委托机制时的场景
为了缩短处理路径,可以设置mideleg,选择性的把针对S态的部分中断直接委托给S态处理,不经过M态,如图2所示。

图2 - 启用中断委托机制时的场景
在图2基础上,举一个更具体的例子。中断源是PLIC,发出两个特权级的ext外部中断,标记为mext(11号)和sext(9号)。
- 对于sext的处理路径:mideleg的第9位预先设置1,指示sext将被委托到S态处理,因而在硬件层面sext会经由S-IRQ通道逐步传递,最终到达Linux中的中断处理函数。注意S态通道的en中断开关是由Linux控制的,由Linux决定什么时候打开"水龙头"。
- 对于mext的处理路径:mext不会被路由委托,仍然试图沿着M-IRQ中断处理通道前进(红色虚线箭头),但是OpenSBI会在引导Linux Kernel之前,关闭M态的那个en开关,在那之后,mext的处理路径在硬件层面就被截断了。这样的效果是,Linux启动后就接管了所有的中断处理,OpenSBI不再参与,整体上的性能较好。
OpenSBI和Linux Kernel在引导过程中的任务
中断委托机制的启用由OpenSBI和LinuxKernel接替完成:
- OpenSBI在M态被引导,它会按需打开en中断开关,以完成必要的设备初始化。此时,只存在M态处理中断的路径,即图1所示的路径。
- OpenSBI在自身引导的最后阶段,即切换到S态启动Linux的前夕,一方面设置mideleg委托给S态中断,另一方面关闭了M态中断的开关en,不再有M态中断流处理。
- Linux Kernel启动时,由于OpenSBI的预先准备工作,它将能够全权处理中断。即所有中断都走S态路径,也就是图2所示的路径。
关于异常的委托
异常委托与中断委托类似,主要区别是三点:
- 异常委托基于medeleg寄存器。
- 异常委托的硬件处理路径上没有en开关,也就是无法像对待中断那样开关异常。
- OpenSBI把S态的ecall异常、缺页异常等都委托给S处理,但是它本身还能够处理M态的ecall,即SBI-Call,以此来为Linux提供一些调用服务。
要点
特别需要注意的是:中断的委托机制是前置于中断开关的,委托形成了多条IRQ的分流,每条分流各自有自己的中断开关。因此,中断开关不会影响委托机制。