Cortex-M3/M4的寄存器之CONTROL 寄存器
CONTROL 寄存器定义:栈指针的选择(主栈指针/进程栈指针)。线程模式的访问等级(特权/非特权)。另外,对于具有浮点单元的 Cortex-M4 处理器,CONTROL, 寄存器中有一位表示当前上下文(正在执行的代码)是否使用浮点单元。
注意 对于 ARMv6-M,nPRIV和非特权等级的实现是和设计实现相关的,而且在最初的Cortex-M0 和 Cortex-M1 产品上是不可用的,其在 Cortex-M0+上则是可选的。
CONTROL寄存器只能在特权访问等级进行修改操作,而读取操作则在特权和非特权访问等级都可以。
复位后,CONTROL寄存器默认为0,这也就意味着处理器此时处于线程模式、具有特权访问权限以及使用主栈指针。通过写 CONTROL寄存器,特权线程模式的程序可以切换栈指针的选择或进人非特权访问等级。不过,nPRIV(CONTROL的第0位)置位后,运行在线程模式的程序就不能访问CONTROL 寄存器了。
运行在非特权等级的程序无法再切换回特权访问等级,这样就提供了一个基本的安全模型。例如,嵌入式系统中可能会具有运行在非特权访问等级的不受信任的应用,这些应用的访问权限就需要受到限制,以免不可靠的程序引起整个系统的崩溃。
若有必要将处理器在线程模式切换回特权访问等级,则需要使用异常机制。在异常处理期间,处理程序可以清除 nPRIV 位。在返回到线程模式后,处理器就会进人特权访问等级。
若使用嵌入式 OS,每次上下文切换时都可以重新编程 CONTROL,寄存器,以满足应用间不同的特权访问等级需要。
nPRIV 和 SPSEL,的设置共有4种组合方式,其中3种在实际应用中较为常见。
对于未使用嵌入式 OS 的多数简单应用,无须修改 CONTROL寄存器的数值。整个应用可以运行在特权访问等级并且只使用 MSP。
要利用 C语言访问 CONTROL,寄存器,可以使用符合 CMSIS 的设备驱动库提供的以下函数:
x=_get_CONTROL();//读取 CONTROL 寄存器的当前值 _set_CONTROL(x);//设置 CONTROL 寄存器的数值为x
在修改 CONTROL 寄存器的值时需要注意以下两点::
- 对于具有浮点单元(FPU)的 Cortex-M4 处理器,或具有 FPU 的 ARMv7-M 处理器,由于浮点单元的存在,FPCA 位会自动置位。若程序中包含浮点运算但FPCA 位被意外清除,而且接下来产生了一个中断,那么浮点单元寄存器中的数据将不能在异常入口流程保存,且可能会被中断处理覆盖。在这种情况下,继续执行被中断的任务时,程序可能无法继续正确地处理。
- 在修改了 CONTROL, 寄存器后,从架构来看,应该使用指令同步屏障(ISB)指令(或符合 CMSIS的设备驱动库中的–ISB()函数),以确保本次修改对接下来的代码能起到作用。由于 Cortex-M3、Cortex-M4、Cortex-M0+、Cortex-M0 以及 Cortex-M1 的流水线非常简单,不使用 ISB 指令也不会引起什么问题。
要用汇编访问 CONTROL 寄存器,可以使用 MRS 和 MSR 指令:
MRS r0,CONTROL ;将 CONTROL 寄存器读入 RO MSR CONTROL,rO ;将 R0 写入 CONTROL 寄存器
可以通过检查 CONTROL 和 IPSR 的数值来确定当前是否为特权等级。
int in_privileged(void) { if( _get_IPSR()!=0) return 1;//True else if(( _get_CONTROL()&0x1)==0) return 1;//True else return 0; //False }