• 首页
  • 中国
  • S3c2440ARM异常与中断体系详解4---_und异常模示程序示例

S3c2440ARM异常与中断体系详解4---_und异常模示程序示例

2023-11-01 67浏览
百检网是一家专业的第三方检测平台,汇聚众多拥有权威资质的第三方检测机构为你提供一站式的检测服务,做检测就上百检网。百检网让检测从此检测,一份报告全国通用,专业值得信赖。

1、异常向量表

/******下面这些就是异常向量表*****/

.globl _start

_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

_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

手册异常向量表定义

2、程序

.text

.global _start

_start:

b reset /*vector 0 一上电复位,是从0地址开始执行,跳到reset*/

b do_und /*vector 4 如果发生未定义指令异常,硬件就会在自动跳转0x04地址未定义指令异常处,执行do_und*/

/*假设一上电从0地址开始执行,reset,做一系列初始化之后

*故意加入一条未定义指令

*/

do_und:

/* 执行到这里之前:

* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR_und保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为11011, 进入到und模式

* 4. 跳到0x4的地方执行程序

*/

/*需要从新设置sp栈,指向某一块没有使用的地址*/

/* sp_und未设置, 先设置它 */

ldr sp,=0x34000000 /*指向SDRAM的一块内存上*/

/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

/* 发生异常时,当前被中断的地址会保存在lr寄存器中 先减后存*/

/* lr是异常处理完后的返回地址, 也要保存 */

stmdb sp!,{r0-r12,lr} /*先减后存*/

/* 1、保存现场 */

/* 2、处理und异常 */

mrs r0,cpsr

ldr r1,=und_string

bl printException

/* 3、恢复现场 */

ldmia sp!,{r0-r12,pc}^ /* ^ 会把und_spsr的值恢复到cpsr里 */

und_string:

.string "undefined instruction exception"

如何定义字符串,可以百度搜索 arm-linux-gcc 汇编 定义字符串

官方的说明文档

http://web.mit.edu/gnu/doc/html/as_7.html

.string "str" /*汇编代码定义字符串*/

und_string:

.string "undefined instruction exception"

reset:

/* 关闭看门狗 */

ldr r0, =0x53000000

ldr r1, =0

str r1, [r0]

/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

ldr r0, =0x4C000000

ldr r1, =0xFFFFFFFF

str r1, [r0]

/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */

ldr r0, =0x4C000014

ldr r1, =0x5

str r1, [r0]

/* 设置CPU工作于异步模式 */

mrc p15,0,r0,c1,c0,0

orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA

mcr p15,0,r0,c1,c0,0

/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)

* m = MDIV+8 = 92+8=100

* p = PDIV+2 = 1+2 = 3

* s = SDIV = 1

* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

*/

ldr r0, =0x4C000004

ldr r1, =(92<<12)|(1<<4)|(1<<0)

str r1, [r0]

/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

* 然后CPU工作于新的频率FCLK

*/

/* 设置内存: sp 栈 */

/* 分辨是nor/nand启动

* 写0到0地址, 再读出来

* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

* 否则就是nor启动

*/

mov r1, #0

ldr r0, [r1] /* 读出原来的值备份 */

str r1, [r1] /* 0->[0] */

ldr r2, [r1] /* r2=[0] */

cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */

ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

moveq sp, #4096 /* nand启动 */

streq r0, [r1] /* 恢复原来的值 */

/*初始化SDRAM*/

bl sdram_init

/*初始化UART0*/

bl uart0_init

/*重定位text rodata data段整个程序*/

bl copy2sdram

/*清除BSS段*/

bl clean_bss

bl print1

und_code:

.word 0xff123456 /*未定义指令*/

bl print2

//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main /* **跳转, 跳到SDRAM */

halt:

b halt

如何处理这个异常呢?

直接print打印一句话,新建一个exception.c文件

#include "uart.h"

void printException(unsigned int cpsr, char *str) //cpsr打印相应的寄存器,str打印一个字符串

{

puts("Exception! cpsr = ");\打印cpsr

printHex(cpsr);//输出cpsr的值

puts(" ");//输出空格

puts(str);//输出str值

puts("nr");//回车,换行

}

我们打开之前编译过的程序的反汇编文件

里面一定包含了保存恢复

30000084 :

30000084: e1a0c00d mov ip, sp

30000088: e92dd800 stmdb sp!, {fp, ip, lr, pc} //保存 d是减 b是存

3000008c: e24cb004 sub fp, ip, #4 ; 0x4

30000090: e24dd004 sub sp, sp, #4 ; 0x4

30000094: e50b0010 str r0, [fp, #-16]

30000098: e51b3010 ldr r3, [fp, #-16]

3000009c: e2433001 sub r3, r3, #1 ; 0x1

300000a0: e50b3010 str r3, [fp, #-16]

300000a4: e51b3010 ldr r3, [fp, #-16]

300000a8: e3730001 cmn r3, #1 ; 0x1

300000ac: 0a000000 beq 300000b4

300000b0: eafffff8 b 30000098

300000b4: e89da808 ldmia sp, {r3, fp, sp, pc}//恢复,先读后加

上传编译

修改makefile添加文件

objs := start.o led.o main.o uart.o init.o exception.o

all:$(objs)

arm-none-linux-gnueabi-ld -T sdram.lds $^ -o main.elf

arm-none-linux-gnueabi-objcopy -O binary -S main.elf main.bin

arm-none-linux-gnueabi-objdump -D main.elf > main.dis

%.o:%.c

arm-none-linux-gnueabi-gcc -g -nostdlib -c -o $@ $<

%.o:%.S

arm-none-linux-gnueabi-gcc -g -nostdlib -c -o $@ $<

clean:

rm *.bin *.o *.elf *.dis

编译成功烧写

没有输出我们想要的字符串

很多同学想学会如何调试程序

这里我们演示

sdram:

bl print1 //添加print1

/* 故意加入一条未定义指令 */

und_code:

.word 0xdeadc0de /* 未定义指令 */

bl print2 //添加print2,实现这两个函数,来打印

//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main /* **跳转, 跳到SDRAM */

halt:

b halt

实现print1 print2这两个打印函数,在uart.c这个文件里

void print1(void)

{

puts("abcnr");

}

void print2(void)

{

puts("123nr");

}

上传代码烧写,发现print1、print2并未执行成功

发现在start.S并未初始化 uart0_init(),删除main.c中的uart0_init()初始化函数

ldr pc, =sdram

sdram:

bl uart0_init /*串口初始化代码添加*/

bl print1

/* 故意加入一条未定义指令 */

und_code:

.word 0xff123456 /* 未定义指令 */

bl print2

//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main /* **跳转, 跳到SDRAM */

halt:

b halt

加上uart0_init,再次编译烧写

程序正常运行,print1 print2全部打印,表明未定义指令并未运行,难道这个地址是一个已经定义的地址

打开2440芯片手册,找到ARM指令集

发现竟然是SWI指令,CPU可以识别出来,他不是一条未定义指令

我们得找到一条CPU不能识别的指令,定义为0x03000000

ldr pc, =sdram

sdram:

bl uart0_init

bl print1

/* 故意加入一条未定义指令 */

und_code:

.word 0x03000000 /* 未定义指令 */

bl print2

//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main /* **跳转, 跳到SDRAM */

halt:

b halt

编译烧写执行

打印了未定义指令异常CPSR地址,打印了字符串,*后执行main函数

.word 0xdeadcode /* 也是一条未定义指令 只要指令地址对不上上表就是未定义指令*/

我们查看下cpsr是否处于未定义模式

bit[4:0]表示CPU模式 11011,果然处于und模式

我们看看这个程序做了什么事情

.text

.global _start

/*一上电复位,从0地址开始执行

跳到 reset:

做了一系列初始化

当执行到0xdeadc0de这条指令时候,CPU根本就不知道这条指令什么意思

und_code:

.word 0xdeadc0de /* 未定义指令 */

bl print2

让后就发生未定义指令异常,他会把下一条指令的地址保存到异常模式的LR寄存器

/* 执行到这里之前已经发生了很多事情

* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR_und保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为11011, 进入到und模式

* 4. 跳到0x4的地方执行程序

*

* 设置栈 sp是指und的地址

* sp_und未设置, 先设置它

* /* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

* lr是异常处理完后的返回地址, 也要保存 */

* 保存现场 */

* 处理und异常 */

* 恢复sp

* cpu就会切换到之前的模式

*/

*/

.text

.global _start

_start:

b reset /* vector 0 : reset */

b do_und /* vector 4 : und */

und_addr:

.word do_und

do_und:

/* 执行到这里之前:

* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR_und保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为11011, 进入到und模式

* 4. 跳到0x4的地方执行程序

*/

/* sp_und未设置, 先设置它 */

ldr sp, =0x34000000

/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

/* lr是异常处理完后的返回地址, 也要保存 */

stmdb sp!, {r0-r12, lr}

/* 保存现场 */

/* 处理und异常 */

mrs r0, cpsr

ldr r1, =und_string

bl printException

/* 恢复现场 */

ldmia sp!, {r0-r12, pc}^ /* ^会把spsr的值恢复到cpsr里 */

百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台