arm体系结构学习笔记 part3 -- 异常处理机制
2010-12-07 22:15
387 查看
先来看看异常向量表:
这个表格给出了当异常发生时候的程序将跳转到的地址 以及跳转到该地址的同时arm核所处的异常模式
以未定义异常为例当arm核执行时遇到未定义的指令时 程序将自动跳转到异常向量表中的0x00000004地址处执行 并将处理器切换为未定义模式 与此同时其实arm核还完成了cpsr到spsr_und的备份以及设置异常处理完毕的返回地址保存到lr_und
而复位异常的跳转地址为0x0 这是每次系统重新加电的时候arm核总是从0x0地址开始取指令指令 而系统上电时系统所处的模式总是svc模式
貌似有点忘了说了 异常向量表总共占用32个字节 总共有7个异常向量 0x00000014是保留的并未使用 所以是(4*7+4)BYTE
文字的说明貌似有点虚 看一下uboot中的第一阶段代码 也是uboot执行的入口:
[leftover-crazy@leftover-crazy ~]$ vi Downloads/u-boot201006/arch/arm/cpu/arm920t/start.S
.globl _start _start: b start_code 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 _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 .balignl 16,0xdeadbeef
看看这里的b start_code其实是处理复位异常因为异常向量表只有32字节大小,所以采用了跳转的方式来转到相应的异常处理函数。复位异常处理函数的代码如下采用B跳转 B指令跳转的空间为前后32MB范围内代码处于同一文件中几乎是紧挨在中断向量表之后 所以b指令跳转是无任何问题的:
start_code: /* * set the cpu to SVC32 mode */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0 bl coloured_LED_init bl red_LED_on #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) /* * relocate exception table */ ldr r0, =_start ldr r1, =0x0 mov r2, #16 copyex: subs r2, r2, #1 ldr r3, [r0], #4 str r3, [r1], #4 bne copyex #endif
其它的异常采用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.bin: test arm-2440-linux-gnueabi-objcopy -I elf32-littlearm test -O binary test.bin cp test.bin ../../ test : test.o arm-2440-linux-gnueabi-ld -Ttext=0x30000000 test.o -o test test.o :test.S arm-2440-linux-gnueabi-as test.S -o test.o clean: rm -f test.o test test.bin ../../test.bin d: arm-2440-linux-gnueabi-objdump -d test.o
test.S:
.section .text .global main main: mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 .word 0x77777777 sub sp, fp, #12 ldmfd sp, {fp, sp, pc}
这里0x77777777是一条未定义的指令 这个是别人测试的结果
下载并测试的结果如下:
Fantasy >tftp 30000000 test.bin ERROR: resetting DM9000 -> not responding dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b operating at 100M full duplex mode Using dm9000 device TFTP from server 192.168.1.10; our IP address is 192.168.1.11 Filename 'test.bin'. Load address: 0x30000000 Loading: # done Bytes transferred = 24 (18 hex) Fantasy >go 30000000 ## Starting application at 0x30000000 ... undefined instruction pc : [<30000010>] lr : [<33f8a408>] sp : 33f3fba8 ip : 33f3fbb8 fp : 33f3fbb4 r10: 33f3fcef r9 : 33faadac r8 : 33f3ffe0 r7 : 00000000 r6 : 00000002 r5 : 33f3fee8 r4 : 30000000 r3 : 30000000 r2 : 33f3fee8 r1 : 33f3fee8 r0 : 00000001 Flags: nZCv IRQs off FIQs off Mode SVC_32 Resetting CPU ... resetting ...
当arm执行未定义指令的时候 板子重启了 这个是uboot设定的对异常的处理 不做多余的展开了 看看下面改进的测试代码二 应该就能清楚了。
下面是第二份的测试代码:
宿舍停电了 代码没法测试了 先贴上来 明天补全测试makefile:
test.bin vector.bin: test vector arm-2440-linux-gnueabi-objcopy -I elf32-littlearm test -O binary test.bin arm-2440-linux-gnueabi-objcopy -I elf32-littlearm vector -O binary vector.bin cp test.bin vector.bin ../../ test : test.o arm-2440-linux-gnueabi-ld -Ttext=0x30000000 test.o -o test test.o :test.S arm-2440-linux-gnueabi-as test.S -o test.o vector : vector.o arm-2440-linux-gnueabi-ld -Ttext=0x0 vector.o -o vector vector.o : vector.S arm-2440-linux-gnueabi-as vector.S -o vector.o clean: rm -f test.o test test.bin vector vector.o vector.bin ../../test.bin ../../vector
vector.S:
.section .text .global _start _start: b reset b und b swi b abt_pre b abt_data b . b irq b fiq reset: und: mov sp, #0x32000000 adr r0,str ldr r3,show mov lr,pc mov pc,r3 loop: b loop swi: abt_pre: abt_data: irq: fiq: show: .word 0x33f9303c str: .asciz "undefined instr./n"
mov sp, #0x32000000@这里要设置堆栈寄存器 因为切换到未定义指令异常前,arm处于svc模式,执行到未定义指令时,arm切换到了未定义模式,svc模式下的堆栈由uboot已经设置好,但是未定义模式下的堆栈并未设置,printf函数又需要用到堆栈,如果少了这条语句的话调用printf函数将失败。
loop:
b loop
这里让开发板执行prinrf函数后停止 做个死循环
还有一点就是这段代码是与位置无关的代码 连接时随意指定text段的运行地址都可以。下载到开发板的时候只要下载到0x0处都可以执行。
test.S
.section .text .global main main: mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 .word 0x77777777 sub sp, fp, #12 ldmfd sp, {fp, sp, pc}
测试的时候只要讲test.bin下载到0x30000000 vector.bin下载到0x0出 go 30000000 将会打印出 undefined instr.
附上下载测试结果:
Fantasy >tftp 30000000 test.bin ERROR: resetting DM9000 -> not responding dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b operating at 100M full duplex mode Using dm9000 device TFTP from server 192.168.1.10; our IP address is 192.168.1.11 Filename 'test.bin'. Load address: 0x30000000 Loading: # done Bytes transferred = 24 (18 hex) Fantasy >tftp 0 vector.bin ERROR: resetting DM9000 -> not responding dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:5b operating at 100M full duplex mode Using dm9000 device TFTP from server 192.168.1.10; our IP address is 192.168.1.11 Filename 'vector.bin'. Load address: 0x0 Loading: T # done Bytes transferred = 80 (50 hex) Fantasy >go 30000000 ## Starting application at 0x30000000 ... undefined instr.
相关文章推荐
- arm体系结构学习笔记 part4 -- 异常处理的返回
- ARM裸机全集之ARM体系结构(学习笔记)
- ARM学习笔记--中断体系结构
- 一份好的ARM体系结构学习笔记
- arm体系结构学习笔记 part1--处理器模式与寄存器
- 一份好的ARM体系结构学习笔记
- ARM底层学习笔记-中断体系结构
- ARM学习笔记之一:ARM体系结构
- arm体系结构学习笔记 part2 -- 中断相关
- ARM&LINUX学习笔记(4)---ARM 体系结构
- Oracle10G学习笔记之一安装体系及结构
- 【数据结构与算法学习笔记】PART3 线性结构(除向量外,数组、栈、队列、链表)
- 深入JVM学习笔记-虚拟机体系结构
- ARM体系结构与编程学习(十三)
- WPF and Silverlight 学习笔记(三):WPF体系结构
- 【php学习笔记】Php 体系结构及其执行概述
- 数据结构基础学习笔记 part 2
- CCNA学习笔记之网络体系结构
- Mysql学习笔记:Mysql服务器体系结构(一)
- 《Spring技术内幕》学习笔记__IoC容器体系结构