CM3异常实现

异常类型
1-15 是系统异常,大于等于 16 是外部中断。
image

image

优先级的定义

  • 优先级的数值越小,则优先级越高。CM3 支持中断嵌套,使得高优先级异常会抢占(preempt)低优先级异常。
  • 3 个系统异常:复位,NMI 以及硬 fault。有固定的优先级,优先级号是负数,从而高于所有其它异常。且不可编程。除此之外其他的异常都是可编程的。
  • CM3 支持 3 个固定的高优先级和多达 256 级的可编程优先级支持 128级抢占
  • 只使用 3 个位来表达优先级的优先级配置如下图:
    image
    [4:0]没有被实现,所以读它们总是返回零。CM3 允许的最少使用位数为 3 个位,亦即至少要支持 8 级优先级。
  • 优先级号是以MSB 对齐的(左对齐,高位对齐)

支持 256 个优先级,为什么只有 128 个抢占级?

答:为了使抢占机能变得更可控,CM3 把 256 级优先级按位分成高低两段,分别是抢占优先级和亚优先级

  • 应用程序中断及复位控制寄存器:有一个位段名为“优先级组”。该位段的值对每一个优先级可配置的异常都有影响——把其优先级分为个位段:MSB 所在的位段(左边的)对应抢占优先级,而 LSB 所在的位段(右边的)对应亚优先级,如下图。
    image
    image
  • 抢占优先级分工: 当系统正在响应某异常 L 时,如果来了抢占优先级更高的异常 H,则 H 可以抢占 L
  • 亚优先级分工: 当抢占优先级相同的异常不止一个悬起时,就优先响应亚优先级最高的异常

规定:亚优先级至少是 1 个位。因此抢占优先级最多是 7 个位
image

  • 除能 CM3 的中断嵌套机制:CM3 允许从比特 7 处分组,此时所有的位都表达亚优先级,没有任何位表达抢占优先级,所有优先级可编程的异常之间就不会发生抢占,

  • 复位,NMI 和硬 fault。无论何时出现,都立即无条件抢占所有优先级

  • 如果优先级完全相同,则先响应异常编号最小的

  • 优先级的分组要预先经过计算论证,并且在开机初始化时一次性地设置好,以后再也不动它。

向量表

  • “(异常)向量表”存放CM3异常处理函数的入口地址。CM3 认为该表位于零地址处,且各向量占用 4 字节
    image

  • 地址 0 处存储引导代码,通常是 Flash 或者是 ROM 器件,它们的值不得在运行时改变

  • CM3 允许向量表重定位——从其它地址处开始定位各异常向量。其他地址包括:代码区、RAM区。

  • 动态地更改向量表,对于任何器件,向量表的起始处都必须包含以下向量:

    • 主堆栈指针(MSP)的初始值
    • 复位向量
    • NMI
    • 硬 fault 服务例程
  • “向量表偏移量寄存器”,实现在 RAM区修改向量的入口地址,修改它的值就能定位向量表。向量表的起始地址要求:先求出系统中共有多少个向量,再把这个数字向上增大到是 2 的整次幂,而起始地址必须对齐到后者的边界上。例如,如果一共有 32 个 中断,则共有 32+16(系统异常)=48 个向量,向上增大到 2 的整次幂后值为 64,因此地址 地址必须能被 64* 4=256 整除,从而合法的起始地址可以是:0x0, 0x100, 0x200 等。
    image

中断输入以及悬起行为

  • 当中断输入脚被 assert 后,该中断就被悬起。即使后来中断源取消了中断请求,已经被标记成悬起的中断也被记录下来。到了系统中它的优先级最高的时候,就会得到响应。
    image

  • 在某个中断得到响应之前,其悬起状态被清除(例如,在 PRIMASK 或FAULTMASK 置位的时候软件清除了悬起状态标志),则中断被取消。
    image

  • 当某中断的服务例程开始执行时,称此中断进入了“活跃”状态,其悬起位被硬件自动清除。在一个中断活跃后,直到其服务例程执行完毕,并且返回 (亦称为中断退出),才能对该中断的新请求予以响应(即单实例)。中断服务例程也可以在执行过程中把自己对应的中断重新悬起
    image

  • 中断源咬住请求信号不放,该中断会在其上次服务例程返回后再次被置为悬起状态
    image

  • 如果某个中断在得到响应之前,其请求信号以若干的脉冲的方式呈现,则被视为只有一次中断请求,多出的请求脉冲全部错失。
    image

  • 在服务例程执行时,中断请求被释放,但是在服务例程返回前又重新被置为有效, 则 CM3 会记住此动作,重新悬起该中断。
    image

Fault 异常

  • 专用于 fault 处理的若干个系统异常。CM3 中的 Faults 分类:
    • 总线 faults
    • 存储器管理 faults
    • 用法 faults
    • 硬 fault

总线 Faults

  • AHB 接口上正在传送数据时,如果回复一个错误信号(error response),则会产生总线 faults

  • 使能总线 fault 服务例程,在 NVIC的 “系统 Handler 控制及状态寄存器”中置位BUSFAULTENA 位。

  • 针对数据传输的场所:

    • 取指,通常被称作“预取流产”(prefetch abort)
    • 数据读/写,通常被称作“数据流产”(data abort)
  • 针对错误信号触发的动作

    • 中断处理起始阶段的堆栈 PUSH 动作。 称为“入栈错误”
    • 中断处理收尾阶段的堆栈 POP 动作。 称为“出栈错误”
    • 在处理器启动中断处理序列(sequence)后的向量读取时。是一种罕见的特殊情况,被归类为硬 fault

哪些因素会导致 AHB 回复一个错误信号?

  • 企图访问无效的存储器 region。常见于访问的地址没有相对应的存储器。
  • 设备还没有作好传送数据的准备。比如,在尚未初始化 SDRAM 控制器的 时候试图访问 SDRAM。
  • 在企图启动一次数据传送时,传送的尺寸不能为目标设备所支持。例如, 某设备只接受字型数据,却试图送给它字节型数据。
  • 因为某些原因,设备不能接受数据传送。例如,某些设备只有在特权级下 才允许访问,可当前却是用户级。

总线 fault悬起和硬fault

  • 在检测到总线 fault 时还检测到了更高优先级的异常,则先处理后者,而总线 fault 则被标记成悬起。
  • 如果总线fault被除能,或者总线 fault 发生时正在处理同级或更高优先级异常,则总线 fault 被迫成为“硬伤”——上访成硬 fault,使得最后执行的是硬 fault 的服务例程。在硬 fault 服务例程的执行中又产生了总线 fault(钻牛角尖),内核将进入锁定状态

发生总线 fault 后,如何找出该 fault 的事故原因?

  • NVIC 提供若干个 fault 状态寄存器

  • “总线 fault 状态寄存器”(BFSR),确定产生 fault 的场合:在数据访问时?在取指时?还是在中断的堆栈操作时?以字方式访问,地址是 0xE000_ED28,以字节方式访问,地址是0xE000_ED29
    image

  • 精确的总线 fault,肇事的指令的地址被压在堆栈中。如果 BFSR 中 的 BFARVALID 位为 1,还可以找出是在访问哪块存储器时产生该总线 fault ,该存储器的地址被放到“总线 fault 地址寄存器(BFAR)”。

  • 不精确的总线 fault,无从定位

精确的总线 fault vs. 不精确的总线 fault

  • 数据访问产生的总线 fault,被归类为精确总线 fault 和不精确总线 fault
  • 不精确的总线 faults 中,导致此 fault 的指令早已完成。例如,缓冲区写入。启动缓冲区写入的指令不知何时已经执行了,但是写到中途时才触发总线 fault。可见,这个操作是在若干个时钟周期前执行的,而且不能确定是具体几个周 期之前,也没有记录这期间的程序跳转动作,因此无法确认“肇事者”,故而是不精确的。
  • 精确的总线 fault 是被最后一个完成的操作触发的。例如,一个存储器读取导致的 fault总是精确的,因为该指令必须等全部读完时才算执行完成。这样,任何在读取过程中发生的 fault 总能落在该指令的头上。
  • 取指和堆栈操作产生的 fault 总是精确

image

  • BFSR 寄存器是一个 8 位的寄存器,可以使用字传送和字节传送来读取
  • 以字方式访问,地址是 0xE000_ED28,且第 2 个字节有效;
  • 以字节方式访问,地址是 0xE000_ED29

存储器管理 faults

  • 多与MPU有关,其诱因一是某次访问触犯了MPU设置的保护策略。二是某些非法访问。
  • MemManage faults 的常见诱因:
    • 访问了 MPU 设置区域覆盖范围之外的地址(越界)
    • 往只读 region 写数据(越权)
    • 用户级下访问了只允许在特权级下访问的地址(越权)
  • MemManage fault 发生后,其服务例程是使能的,则执行服务例程。如果同时还发生了其它高优先级异常,则优先处理这些高优先级的异常,MemManage 异常被悬起。如果此时处理器已经在处理同级或高优先级异常,或者 MemManage fault 服务例程被除能,则和总线 fault 一样:上访成硬 fault,最终执行的是硬 fault 的服务例程。如果硬 fault 服务例程或 NMI 服务例程的执行也导致了 MemManage fault,那就不可救要了——内核将被锁定。
  • 和总线 fault 一样,MemManage fault 必须被使能才能正常响应。
  • MemManage fault在 NVIC“系统 handler 控制及状态寄存器”中的使能位是 MEMFAULTENA
  • 存储器管理 fault 状态寄存器(MFSR”,调查 MemManage fault 的案发现场,指出导致 MemManage fault 的原因

image

  • 8 位的寄存器,可以使用字传送和字节传送来读取。
  • 两种访问方式的地址都是 0xE000_ED28,按字访问时第 1 个字节有效。

用法 faults

硬 fault

  • 硬 fault 是总线 fault、存储器管理 fault 以及用法 fault 上访的结果(非硬fault 的服务例程无法执行,它们就会成为“硬伤”——上访(escalation)成硬 fault。)
  • 取向量(异常处理是对异常向量表的读取)时产生的总线 fault 也按硬 fault 处理
  • 硬fault 状态寄存器(HFSR),指出产生硬 fault 的原因

image

应对 faults???

  • 根据各种 fault 状态寄存器的值来判定程序错误,并且改正它们
  • 应付 fault 的常用方法:
    • 复位。设置 NVIC“应用程序中断及复位控制寄存器”中的VECTRESET 位,将只复位处理器内核而不复位其它片上设施有些CM3 芯片可以使用该寄存器的 SYSRESETREQ 位来复位。这种只限于内核中的复位不会复位其它系统部件。
    • 恢复。如果程序尝试访问了协处理器,可以通过一个协处理器的软件模拟器来解决此问题(牺牲性能)
    • 中止相关任务。系统运行了一个 RTOS,则相关的任务可以被终结或者重新开始

SVC 和 PendSV

NVIC

中断配置基础

中断的使能与除能

中断的悬起与解悬

优先级

活动状态

PRIMASK 与 FAULTMASK 特殊功能寄存器

BASEPRI寄存器

异常的配置寄存器

中断建立全过程、

软件中断

SysTick定时器

中断的具体行为
中断/异常的响应序列

异常返回

嵌套的中断

咬尾中断

晚到(的高优先级)异常

异常返回值

中断延迟

异常响应期间的faults

使用异常系统
使用中断

异常/中断服务程序

软件触发中断

使用SVC

SVC示范:用于输出函数

在C中使用SVC

异常服务例程的范例

posted @ 2023-07-12 20:44  登云上人间  阅读(81)  评论(0编辑  收藏  举报