number headings: auto, first-level 2, max 6, 1.1
- Cortex-M3 权威指南,Joseph Yiu著;宋岩译。
- ARM Cortex-M3与Cortex-M4权威指南(第3版),Joseph Yiu著;吴常玉,曹孟娟,王丽红译。
8 异常和中断
8.6 SVC和PendSV
- SVC:Supervisor Call,系统服务调用。
- PendSV:Pendable Service,可挂起系统调用
上述两个中断的区别就在于能否得到延缓执行。
8.6.1 SVC系统服务调用
SVC用于完成用户态的系统调用请求。其主要由如下几个部分组成:
- SVC指令:用于在用户态唤起内核提供的系统调用,在调用SVC指令时,必须附加目标系统调用对应的SVC服务编号参数。
- SVC中断:
- 当用户态调用SVC指令后,CPU会产生SVC中断。
- 在触发SVC中断前,CPU会自动保存现场(PC等)到当前活动堆栈中。
- SVC中断响应例程:
- 在进入操作系统的SVC中断响应例程后,响应例程会判断
LR
的第2个bit判断其使用的是主栈(MSP)还是进程栈(PSP)
- 从目标栈中提取
PC
对应地址的数据,该数据的第一个字节为SVC服务编号,第二个字节为SVC指令
- 在缺第该SVC服务编号后,操作系统会完成对应的系统调用。


需要注意的是,CM3内核在SVC中断产生时,会检测当前能否正常响应SVC中断:
- 若SVC被屏蔽(例如
PRIMASK=1
),则无法响应SVC中断
- 正在运行更高优先级的中断时无法响应SVC中断(此情况正常情况下不会发生,见注2)。
即当前内核无法响应SVC中断时,内核会触发UsageFault,且若未使能UsageFault,则会变成HardFault。即SVC系统服务调用必须在可以得到响应时才能被调用,否则会触发异常。并且SVC需要占用高优先级中断。
- 在关键代码段关闭中断时,需要注意禁止关闭SVC中断。
- 在比SVC优先级更高的中断中严禁触发SVC中断。而在多核CPU中,每个CPU都有自己独立的SVC中断。因此:^eoeevc
- 所有用户可以访问的中断,其优先级均应小于SVC的优先级。
- 当CPU在处理更高级中断时,用户不可能触发SVC调用;而内核代码只要做到上述原则,就不会出现正在运行更高优先级的中断时无法响应SVC中断的问题。
- 因此SVC中断优先级应尽可能的高,这样可以提高SVC的响应速度,并且更容易的将需要访问SVC的中断放到比SVC低的优先级中。
8.6.2 PendSV可挂起系统调用
8.6.2.1 Why PendSV?
现在假设我们使用普通的定时器(例如Systick)来实现任务的分时调度,使用SVC来接收用户的系统调用。现在考虑如下几个场景:
- 当在处理一个比Systick优先级低的中断时,触发了Systick的中断并发生调度,则会出现优先级反转问题:"用户线程优先级看起来比中断优先级高了",如下图。

- 根据上一章节中的设计,SVC的优先级通常非常高。如果在SVC中就直接完成用户态的系统调用的话,是否过于耗时?是否有必要把用户的系统调用的后端实现放到SVC如此高的优先级?如何把系统调用的后端放到更低的优先级中处理?
当然,解决上述问题只需要实现一个"延迟执行的机制"。该机制可以直接依靠"ARM中断嵌套及其优先级"的机制进行解决,可见下一章节。
8.6.2.2 PendSV规则及原理
上一章节的问题可以考虑实现一种延迟执行机制,将系统调用的后端实现及上下文切换丢到所有其他中断运行结束后自动运行即可。也正如上述章节所述,可以直接依靠ARM中断嵌套机制实现,配置一个优先级最低的专用中断,将SVC中断的后半、系统调用后端实现及延迟上下文切换等内容放入该专用中断中即可。当其他所有中断运行完毕后,该中断即会自动运行。PendSV即是基于此思路在硬件层面专门优化来的专用中断。
- PendSV是CPU专门为SVC中断的后半、系统调用的后端实现及延迟上下文切换特殊优化而来的一个专用中断。该中断的优先级通常配置为最低,以方便让上述操作在其他所有中断运行结束后自动运行。该特性基于中断嵌套机制。
- PendSV的中断优先级需要配置为最低。
- 可以在Systick等中断中触发。