arm cortex-m架构 SVC指令详解以及其在freertos的应用
static void prvPortStartFirstTask( void )
{
__asm volatile (
/*
* - 0xE000ED08是 SCB 模块 VTOR 寄存器的地址
* - 这句汇编目的是把 0xE000ED08(VTOR的地址) 保存到 R0 寄存器
* - 执行完这句指令(伪指令),后 R0 寄存器保存的是 0xE000ED08(VTOR的地址)
*/
" ldr r0, =0xE000ED08 \n"
/*
* - 将 0xE000ED08 地址的值(中断向量表的地址) 放到 R0 寄存器中
* - 执行完这句指令,后 R0 寄存器保存的是 中断向量表的地址
*/
" ldr r0, [r0] \n"
/*
* - 将 中断向量表 第一项的值 放到 R0 寄存器中
* - 中断向量表第一个字保存的 是栈顶地址(cortex-m是满减栈,栈顶即栈的开始)
* - 初始转态下使用的是MSP
* - 执行完这句指令,后 R0 寄存器保存的是栈顶地址
*/
" ldr r0, [r0] \n"
/*
* - 将 R0的值写入 MSP 中。
* - 此时 R0 内存储的是 栈顶地址,这一步其实就是把 MSP 中已经存好的内容完全销毁。
* - 因为在这段代码中,在执行完SVC指令后,会由调度器完全接管代码,这里的SVC异常永远也不会返回
*/
" msr msp, r0 \n"
/*
* - 将 control 寄存器清零
* - control 寄存器有三位,分别是:
* . FPCA - 标志位,用于指示在前文中是否使用过 FPU(浮点运算单元),如果使用过,dang发生异常硬件压栈的时候,会基于此位决定是否保存浮点运算单元上下文,又此时使用的SVC异常是不会返回的,所以也不必保存,保存了也是浪费空间。
* 0:前文没有使用浮点运算单元,产生异常时硬件不用保存浮点上下文
* 1:前文使用了浮点运算单元,产生异常时硬件要保存浮点上下文
* . SPSEL - 控制位,控制在 Thread mode 下使用 MSP 还是 PSP , Handler mode 一定使用 PSP
* 0: MSP
* 1: PSP
* . nPRIV - 控制位,控制在 Thread mode 下是 Privileged(特权级) 还是 Unprivileged(非特权级) , Handler mode 下一定是 Privileged(特权级)
* 0: Privileged(特权级)
* 1: Unprivileged(非特权级)
*/
" mov r0, #0 \n"
" msr control, r0 \n"
/* 开启全局中断 */
" cpsie i \n"
/* 开启fpu */
" cpsie f \n"
/* 数据同步隔离,确保上面的配置生效 */
" dsb \n"
/* 指令同步隔离,清空流水线 */
" isb \n"
/* 触发0号系统调用,永远也不会返回, 从此处开始代码由freertos全面接管 */
" svc 0 \n"
/* svc 不会返回,永远也不会运行到这里 */
" nop \n"
/* 这是一条伪指令,由汇编器处理,目的是告诉汇编器,把字面量池(常量)放到这个位置, 避免字面量池离使用它的指令太远,超出了寻址范围而导致错误。ARM的ldr指令寻址范围有限*/
" .ltorg \n"
);
}