先来看看异常向量表:
这个表格给出了当异常发生时候的程序将跳转到的地址 以及跳转到该地址的同时arm核所处的异常模式
以未定义异常为例当arm核执行时遇到未定义的指令时 程序将自动跳转到异常向量表中的0x00000004地址处执行 并将处理器切换为未定义模式 与此同时其实arm核还完成了cpsr到spsr_und的备份以及设置异常处理完毕的返回地址保存到lr_und
而复位异常的跳转地址为0x0 这是每次系统重新加电的时候arm核总是从0x0地址开始取指令指令 而系统上电时系统所处的模式总是svc模式
貌似有点忘了说了 异常向量表总共占用32个字节 总共有7个异常向量 0x00000014是保留的并未使用 所以是(4*7+4)BYTE
文字的说明貌似有点虚 看一下uboot中的第一阶段代码 也是uboot执行的入口:
看看这里的b start_code其实是处理复位异常因为异常向量表只有32字节大小,所以采用了跳转的方式来转到相应的异常处理函数。复位异常处理函数的代码如下采用B跳转 B指令跳转的空间为前后32MB范围内代码处于同一文件中几乎是紧挨在中断向量表之后 所以b指令跳转是无任何问题的:
其它的异常采用ldr pc,label lable分别是
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
以_irq label为例 ldr pc, _irq 执行的是将irq的值赋给pc irq的值为irq异常处理函数的地址
下面我们来实例解析一下未定义指令异常的处理机制先上代码:
第一步测试,主要做的是观察一下uboot下未定义指令执行时的情况:
makefile:
test.S:
这里0x77777777是一条未定义的指令 这个是别人测试的结果
下载并测试的结果如下:
当arm执行未定义指令的时候 板子重启了 这个是uboot设定的对异常的处理 不做多余的展开了 看看下面改进的测试代码二 应该就能清楚了。
下面是第二份的测试代码:
宿舍停电了 代码没法测试了 先贴上来 明天补全测试
makefile:
vector.S:
mov sp, #0x32000000@这里要设置堆栈寄存器 因为切换到未定义指令异常前,arm处于svc模式,执行到未定义指令时,arm切换到了未定义模式,svc模式下的堆栈由uboot已经设置好,但是未定义模式下的堆栈并未设置,printf函数又需要用到堆栈,如果少了这条语句的话调用printf函数将失败。
loop:
b loop
这里让开发板执行prinrf函数后停止 做个死循环
还有一点就是这段代码是与位置无关的代码 连接时随意指定text段的运行地址都可以。下载到开发板的时候只要下载到0x0处都可以执行。
test.S
测试的时候只要讲test.bin下载到0x30000000 vector.bin下载到0x0出 go 30000000 将会打印出 undefined instr.
附上下载测试结果: