arm cortex-m架构 SVC指令详解以及其在freertos的应用

时间:2024-06-03 08:54:38
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" ); }