ARM架构与编程——9.ARM架构中的异常与中断

ARM架构中的异常处理

一、不同架构的处理流程

处理流程是一样的。

  • 每执行完一条指令都会检查有无中断/异常产生
  • 发现有中断/异常产生,开始处理:
    • 保存现场
    • 分辨异常/中断,调用对应的异常/中断处理函数
    • 恢复现场

不同的芯片,不同的架构,在这方面的处理稍有差别:

  • CPU中止当前执行,跳转去执行处理异常的代码:也有差异

    • cortex M3/M4在向量表上放置的是函数地址
    • cortex A7在向量表上放置的是跳转指令
  • 保存/恢复现场:cortex M3/M4是硬件实现的,cortex A7是软件实现的

1.1 cortex M3/M4

参考资料:DDI0403E_B_armv7m_arm.pdfARM Cortex-M3与Cortex-M4权威指南.pdfPM0056.pdf
要想理解这个处理流程,需要从向量表说起。
向量,在数学定义里是有方向的量,在程序里可以认为向量就是一个数组,里面有多个项。
在ARM架构里,对于异常/中断,它们的处理入口会整齐地排放在一起。

1.1.1 M3/M4的向量表

M3/M4的向量表中,放置的是具体异常/中断的处理函数的地址
比如发生Reset异常时,CPU就会从向量表里找到第1项,得到Reset_Handler函数的地址,跳转去执行。
比如发生EXTI Line 0中断时,CPU就会从向量表里找到第22项,得到EXTI0_IRQHandler函数的地址,跳转去执行。

  • 跳转之前,硬件会保存现场
  • 函数执行完毕,返回之后,硬件会恢复现场

中断向量表如下:

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler            ; TIM2
                DCD     TIM3_IRQHandler            ; TIM3
                DCD     TIM4_IRQHandler            ; TIM4
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     SPI2_IRQHandler            ; SPI2
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     USART3_IRQHandler          ; USART3
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                DCD     ADC3_IRQHandler            ; ADC3
                DCD     FSMC_IRQHandler            ; FSMC
                DCD     SDIO_IRQHandler            ; SDIO
                DCD     TIM5_IRQHandler            ; TIM5
                DCD     SPI3_IRQHandler            ; SPI3
                DCD     UART4_IRQHandler           ; UART4
                DCD     UART5_IRQHandler           ; UART5
                DCD     TIM6_IRQHandler            ; TIM6
                DCD     TIM7_IRQHandler            ; TIM7
                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End
1.1.2 M3/M4的异常/中断处理流程

发生异常/中断时,硬件上实现了这些事情:

  • 保存现场:把被中断瞬间的寄存器的值保存进栈里

  • 根据异常/中断号,从向量表中得到函数地址,跳转过去执行

  • 函数执行完后,从栈中恢复现场

保存现场、分辨异常/中断、跳转执行,都是硬件实现的。
我们只需要在向量表中,把处理函数的地址填进去就可以了。

硬件承包了大部分的工作。

M3/M4的向量表中,存放的是函数地址
在这里插入图片描述

1.2 cortex A7

参考资料:ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf

实际上,以前的S3C2440属于ARM9处理器,它的异常/中断处理流程给cortex A7是一样的。

1.2.1 A7的向量表

A7的向量表中,放置的是某类异常的跳转指令
比如发生Reset异常时,CPU就会从向量表里找到第0项,得到b reset指令,执行后就跳转到reset函数。
比如发生任何的中断时,CPU就会从向量表里找到第6项,得到ldr pc, _irq指令,执行后就跳转到_irq函数。

  • 跳转之前,硬件只会保存CPSR寄存器
  • 跳转之后,软件要保存现场
  • 函数执行完毕,返回之前,软件恢复现场
_start: 
    b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
1.2.2 A7的异常/中断处理流程

发生异常/中断时,硬件上实现了这些事情:

  • CPU切换到对应的异常模式,比如IRQ模式、未定义模式、SVC模式

  • 保存被中断时的CPSR到SPSR

    • CPSR:current program status register,当前程序状态寄存器
    • SRSR:saved program status register,保存的程序状态寄存器
  • 跳到这个异常的入口地址去,执行指令,这通常是一条跳转指令

软件要做的事情就比较多了:

  • 保存现场
  • 分辨异常/中断
  • 调用对应的处理函数
  • 恢复现场

A7的向量表中,存放的是跳转指令
在这里插入图片描述

二、保存现场

2.1 回顾处理流程

CPU每执行完一条指令都会检查有无中断/异常产生,发现有中断/异常产生,开始处理:

  • 保存现场
  • 分辨异常/中断,调用对应的异常/中断处理函数
  • 恢复现场

对于不用的处理器,具体的处理工作有差别:

  • 保存现场:cortex M3/M4里是硬件完成,cortex A7等是软件实现
  • 分辨异常/中断:cortex M3/M4里是硬件完成,cortex A7等是软件实现
  • 调用处理函数:cortex M3/M4里是硬件来调用,cortex A7等是软件自己去调用
  • 恢复现场:cortex M3/M4里是软件触发、硬件实现,cortex A7等是软件实现

不管是硬件还是软件实现,第一步都是保存现场

2.2 为什么要保存现场

在这里插入图片描述
任何程序,最终都会转换为机器码,上述C代码可以转换为右边的汇编指令。
对于这4条指令,它们可能随时被异常打断,怎么保证异常处理完后,被打断的程序还能正确运行?

  • 这4条指令涉及R0、R1寄存器,程序被打断时、恢复运行时,R0、R1要保持不变

  • 执行完第3条指令时,比较结果保存在程序状态寄存器(PSR)里,程序被打断时、恢复运行时,程序状态寄存器保持不变

  • 这4条指令,读取a、b内存,程序被打断时、恢复运行时,a、b内存保持不变

内存保持不变,这很容易实现,程序不越界就可以。
所以,关键在于R0、R1、程序状态寄存器要保持不变(当然不止这些寄存器):

  • 在处理异常前,把这些寄存器保存在栈中,这称为保存现场
  • 在处理完异常后,从栈中恢复这些寄存器,这称为恢复现场

2.3 保存现场

ARM处理器中有这些寄存器:
在这里插入图片描述
在arm中有个ATPCS规则(ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)。
约定R0-R15寄存器的用途:

  • R0-R3
    调用者和被调用者之间传参数

  • R4-R11
    函数可能被使用,所以在函数的入口保存它们,在函数的出口恢复它们。

    R0-R15寄存器介绍如下:在这里插入图片描述

还有一个程序状态寄存器,对于M3/M4它被称为XPSR,对于A7它被称为CPSR,我们简称为PSR。
R0-R15、PSR,就是所谓的现场
发生异常/中断后,在处理异常/中断前,需要保存现场,难道需要保存所有这些寄存器吗?
不需要!
在C函数中,可以修改R0-R3、R12、R14(LR)以及PSR。如果C函数要用到这些寄存器,就要把它们保存到栈里,在函数结束前在从栈中恢复它们。
这些寄存器被拆分成2部分:调用者保存的寄存器(R0-R3,R12,LR,PSR)被调用者保存的寄存器(R4-R11)
比如函数A调用函数B,函数A应该知道:

  • R0-R3是用来传参数给函数B的
  • 函数B可以肆意修改R0-R3
  • 函数A不要指望函数B帮你保存R0-R3
  • 保存R0-R3,是函数A的事情
  • 对于LR、PSR也是同样的道理,保存它们是函数A的责任

对于函数B:

  • 我用到R4-R11中的某一个,我都会在函数入口保存、在函数返回前恢复
  • 保证在B函数调用前后,函数A看到的R4-R11保存不变

假设函数B就是异常/中断处理函数,函数B本身能保证R4-R11不变,那么保存现场时,只需要保存这些:

  • 调用者保存的寄存器(R0-R3,R12,LR,PSR)
  • PC

2.4 对于M3/M4

参考资料:DDI0403E_B_armv7m_arm.pdfARM Cortex-M3与Cortex-M4权威指南.pdfPM0056.pdf
1.先硬件保存现场
在这里插入图片描述
2.然后调用C函数
C函数执行完后,它返回LR所指示的位置。
难道把LR设置为被中断的程序的地址就行了吗?
如果只是返回LR所指示的地方,硬件帮我们保存在栈里的寄存器,怎么恢复?
M3/M4在调用异常处理函数前,把LR设置为一个特殊的值,这个特殊的值被称为EXC_RETURN
当PC寄存器的值等于EXC_RETURN时,会触发异常返回机制,简单地说:会从栈里恢复R0-R3,R12,LR,PC,PSR等寄存器。
EXC_RETURN的值,请参考ARM Cortex-M3与Cortex-M4权威指南.pdf,截图如下:
在这里插入图片描述
补充2个知识点:

  • 操作模式:M3/M4有两个操作模式

    • 处理模式:执行中断服务程序等异常处理时,处于处理模式
    • 线程模式:执行普通应用程序代码时,处于线程模式
  • M3/M4有两个SP寄存器:SP_process、SP_main

    • 有些RTOS在运行用户程序时会使用SP_process,默认使用SP_main。

2.4 对于A7

它寄存器如下:
在这里插入图片描述
处理器有9中模式:User、Sys、FIQ、IRQ、ABT、SVC、UND、MON、HYP。
上图中深色的寄存器,表示该模式下的"Banked"寄存器,比如SPSR寄存器,在很多模式下都有自己的、单独的寄存器
比如IRQ模式下访问SPSR时,访问到的是IRQ模式下自己的SPSR_irq,别的模式下无法访问SPSR_irq。

比较值得关注的是FIQ模式,名为"快中断",它有很多"Banked"寄存器:R8-R12,SP,LR。
在FIQ模式下,它既然能使用自己的R8-R12,SP,LR,自然不需要去保存被中断的程序的"R8-R12,SP,LR"了。
省去保存这几个寄存器的时间,处理中断时自然就快很多,所以被称为"FIQ"。

从上图也看到,几乎每个模式下都有自己是SP寄存器,意味着这些模式下有自己的栈。

当发生异常时,以IRQ为例:

  • CPU会自动切换进入对应的模式,比如进入IRQ模式
  • 并且会把被中断是的CPSR保存到SPSR_irq里

所以发生异常/中断时,在保存现场时,只需要保存:

  • 调用者保存的寄存器(R0-R3,R12,LR)
  • PC
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值