概论
- 事件与中断
- 发生硬件事件==>发生中断(广义)
- 寄存器组
- R0-R7为低组通用寄存器,R8-R12为高组通用寄存器
- R13为Banked堆栈指针(称为SP)
- CM3有两个堆栈,对应两个SP(不会同时使用),内核态堆栈使用MSP,用户态堆栈使用PSP
- 这两个堆栈又可以被N个进程瓜分(每个进程都有自己的小堆栈)(实际上其他段也是一样)
- R14为连接寄存器(称为LR)
- 存放嵌套函数中的最后一级返回地址
- R15为程序计数器(称为PC)
- 特殊寄存器
- PSRs:状态字寄存器(ALU标志、中断状态)
- MASKs:中断屏蔽寄存器
- CONTROL:控制寄存器(特权状态)
- 只能被MSR/MRS指令访问
- 只有ASPR可以在用户态/内核态访问,其他只能在内核态访问
- 总线与内存空间映像(见STM32架构笔记)
- 内存保护单元MPU
- 在内存的某些region上,给特权加访问限制,若犯规(violated),会产生fault异常
- Cortex-M3使用纯Thumb指令集:甚至乘法也是单周期的
指令系统
- 基础
- 标号、立即数(#)、注释(;)
- 常量(DCB、DCW、DCD)
- 编译器指示字(DCI)、宏定义(EQU)
- 比较与测试(CMP和TST)、加载与拷贝(MOV和CPY)、快速加载(=addr)
- 访存与访存偏移([R0],[R1, 常量偏移])
- 计算:数运算、布尔运算、REV、SXT和UXT
- 分支转移:CMP+B系列(等价于CB系列)、IT、TB系列(查switch表)
- 访存:LD系列、ST系列、POP、PUSH
- 注意LDR/ADR和STR、LDMIA和STMDB
- 高级技巧
- 指令的.W后缀:不加.W=可能16b或32b指令,加.W强制为32b指令
- 连续寄存器表示:R0-R7
- 寄存器列表:{R1-R3,R12,...}
- 预索引与后索引
- 指令Barrier
- 编译器屏障:阻止编译器重排指令(不会生成新指令)
- 重排原理:在单线程的语义不变的情况下,通过将耗时指令前移等方法,增加指令并行性等。但可能导致多线程时错误重排。
- 内存屏障:阻止cpu乱序访问内存(会生成新指令)
- 原理:访存完毕后才能通过barrier,实现内存访问的同步问题
- 用于实现锁的原子性、设备寄存器操作顺序、上下文切换时的寄存器操作顺序
中断与异常
- 1-15为内异常,16以后为外中断
- 异常包括Trap(即SVC)、Fault
- 中断包括Exception
-
中断服务程序也叫ISR
-
Fault强制提升(Escalation)
- 如果同级/高级的ISR触发了同级/低级的Fault,会强制提升为HardFault
- 因为同级及以下的ISR无法处理了,所以必须提升到最高级
- 强制锁定:在NMI/HardFault/复位中出现了任意Fault会立即锁定内核
总线Fault
- 取指(PrefetchAbort)、数据读写(DataAbort)、PUSH和POP错误
-
强制提升:读中断向量时出现总线Fault,会被立即强制提升为HardFault
-
调试方法
- 查看总线Fault状态寄存器BFSR:
- 确定是取指/数据读写/栈读写
- 确定该Fault地址是否精确,BFAR是否有效
- 查看总线Fault地址寄存器BFAR(BFARVALID=1时):确定错误地址
存储器Fault
- 读:访问MPU不允许的地址、访问不存在的地址、用户态访问了内核态区域
- 写:向只读存储器写、用户态访问了内核态区域
-
强制提升
-
调试方法:同理,看MFSR和MMAR
用法Fault
- 使用了未定义的指令(如协处理器指令)
- 可以利用这个中断来进行软件模拟,来实现指令行为
- 切入ARM状态(纯Thumb指令集不支持)
- 加载PC时使用了LSB为0的数(表示PC所指的指令为ARM指令,为1表示Thumb指令)
- 自定义用法Fault
- 可以在NVIC中设置除数为0/未对齐访问的中断标志,使它们也产生用法Fault
-
强制提升
-
调试方法:同理,看UFSR和MMAR
HardFault
- 调试方法:看HFSR
- 确定是否是强制提升得到的HardFault
- 确定是否由取向量时总线Fault
- 若为提升得到,但不是取向量导致的,则必须检查其他Fault,确定是由谁提升的
应对Fault(重要)
- 恢复:使用软件来解决问题(如协处理器导致的UsageFault)
- 中止任务:终止任务,若可能,就重新执行
- 复位内核:设置NVIC的VECT_RESET位,只复位内核,而不复位片上外设
SVC和PendSV
- SVC:不可挂起的系统调用,必须立即进行用户态->内核态
- 被嵌套:产生用法Fault
- 在NMI中调用:产生HardFault
- 若被挂起:产生强制提升的HardFault
- PendSV:可挂起的系统调用,一般用于进程的上下文切换
调试系统架构CoreSight
- 侵入式调试
- 单步执行、watchpoint
- 硬件断点、软件断点
- 调试监视器异常(DebugMon_Handler)
- 基于ROM的调试
- ST-LINK调试器
- 闪存地址重载(flash patching):使用FPB寄存器
- COMP:用于比较指令是否符合停止条件,并在停止时将原指令更换为断点指令
- REMAP:用于停止时将原指令写入指定的SRAM地址
- CTRL:控制FPB过程