目录
一、Reset 中断服务函数的实现步骤
二、汇编实现 Reset 中断服务函数
1、禁止/打开全局中断
2、设置SP指针
3、清除 .bss 段
4、完整 Reset 中断服务函数
一、Reset 中断服务函数的实现步骤
实现 Reset 中断服务函数的基本步骤如下:
- 设置各个模式下的SP指针。当中断发生后,会进入到对应的工作模式下,每个工作模式下要运行程序,肯定要用到栈,因此我们需要初始化不同模式下的栈指针。
- 清除 bss 段。
- 跳转到 main 函数。
有的时候我们为了防止执行中断服务函数的时候,不会被其他更高优先级的中断打断,我们可以在最开始禁止全局中断(禁止 IRQ、FIQ中断),然后在末尾打开全局中断。
- 禁止全局中断
- 设置各个模式下的SP指针。
- 清除 bss 段。
- 打开全局中断
- 跳转到 main 函数
二、汇编实现 Reset 中断服务函数
1、禁止/打开全局中断
这里我们可以操作 CPSR 寄存器来实现,但汇编给我们提供了简单快捷的指令来禁用/打开全局中断
指令 | 描述 |
cpsid i | 禁止IRQ中断 |
cpsie i | 使能IRQ中断 |
cpsid f | 禁止 FIQ 中断 |
cpsie f | 使能 FIQ 中断 |
2、设置SP指针
ARM 一共有九种工作模式,但是这里我们不打算一个个设置,只设置一些可能会用到的,比如 SVC、IRQ、USER、SYS 等。因为 SYS 和 USER 模式共用一个SP指针,即共用一个栈,所以二选一设置即可。(每种模式下的栈都给 2 M 大小)
每一种模式下的 SP 设置方式都类似:
- 修改 CPSR 寄存器切换到某一模式下
- 设置该模式下的SP指针(R13寄存器)
/* 切换到 SVC 模式 */
mrs r0, cpsr @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x13 @ 让 r0 的低五位或上 10011(0x13),结果保存到 r0
msr cpsr, r0 @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80200000 @ 设置栈指针
/* 切换到 SYS 模式 */
mrs r0, cpsr @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x1f @ 让 r0 的低五位或上 11111(0x1f),结果保存到 r0
msr cpsr, r0 @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80400000 @ 设置栈指针
/* 切换到 IRQ 模式 */
mrs r0, cpsr @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x12 @ 让 r0 的低五位或上 10010(0x12),结果保存到 r0
msr cpsr, r0 @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80600000 @ 设置栈指针
3、清除 .bss 段
4、完整 Reset 中断服务函数
/* 复位中断 */
Reset_Handler:
cpsid i /* 禁止IRQ */
cpsid f /* 禁止FIQ */
/* 切换到 SVC 模式 */
mrs r0, cpsr @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x13 @ 让 r0 的低五位或上 10011(0x13),结果保存到 r0
msr cpsr, r0 @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80200000 @ 设置栈指针
/* 切换到 SYS 模式 */
mrs r0, cpsr @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x1f @ 让 r0 的低五位或上 11111(0x1f),结果保存到 r0
msr cpsr, r0 @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80400000 @ 设置栈指针
/* 切换到 IRQ 模式 */
mrs r0, cpsr @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x12 @ 让 r0 的低五位或上 10010(0x12),结果保存到 r0
msr cpsr, r0 @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80600000 @ 设置栈指针
/* bss 段清零 */
ldr r0, =__bss_start
ldr r1, =__bss_end
mov r2, #0
bl bss_loop @ 跳转到 bss_loop,LR寄存器自动保存下一条指令地址
cpsie f /* 使能FIQ */
cpsie i /* 使能IRQ */
b main @ 跳转到 main 函数
bss_loop:
stmia, r0!, {0}
cmp r0, r1
bne bss_loop
mov pc, lr @ 清零完毕后回到原位置
跳转指令参考:b、bl 跳转指令