其他分享
首页 > 其他分享> > 【裸机】浅分析 2440 中断是如何从0x18地址运行到0x30000000 + 0x18

【裸机】浅分析 2440 中断是如何从0x18地址运行到0x30000000 + 0x18

作者:互联网

此篇主要是分析裸机的,

后面会有一篇分析 linux下面的中断原理

总所周知,2440 启动后,都是从 0 地址开始,我们分析 nand flash 启动流程:

1、nand 启动,会拷贝 nand flash 的前面4k 到片内 ram 运行。

2、初始化 ram 后,从nand 中读取数据到 ram,再跳转到 ram 中运行

 

 

此时我们就有个疑问了?

如果后面我们的程序都是在 ram 空间(一般地址为 0x30000000)

那么我们的中断处理函数也应该是在 ( 0x30000000 + 0x18)

但是,我们中断、复位等发生,系统会自动跑到 0 地址中去执行,那岂不是找不到真正的中断函数了?

 

其实不然,我们来看下:

先说结论:

1、中断(或者复位)产生时,PC指针直接跳转到 0x18(或者0x0)位置运行

2、如果是中断,跳转到 0x18 后,会再次跳转到 相应的内存位置中运行

 

我们看下 head.S文件吧:

 

========================================

b Reset

@ 0x04: 未定义指令中止模式的向量地址

b HandleUndef

@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式

b HandleSWI

@ 0x0c: 指令预取终止导致的异常的向量地址

b HandlePrefetchAbort

@ 0x10: 数据访问终止导致的异常的向量地址

b HandleDataAbort

@ 0x14: 保留

b HandleNotUsed

@ 0x18: 中断模式的向量地址

b HandleIRQ

@ 0x1c: 快中断模式的向量地址、

b HandleFIQ

=========================================

这里我们可以看到,我们汇编出来之后的文件

============================================



30000000 <_start>:

30000000: ea000006 b 30000020 <Reset>



30000004 <HandleUndef>:

30000004: eafffffe b 30000004 <HandleUndef>



30000008 <HandleSWI>:

30000008: eafffffe b 30000008 <HandleSWI>



3000000c <HandlePrefetchAbort>:

3000000c: eafffffe b 3000000c <HandlePrefetchAbort>



30000010 <HandleDataAbort>:

30000010: eafffffe b 30000010 <HandleDataAbort>



30000014 <HandleNotUsed>:

30000014: eafffffe b 30000014 <HandleNotUsed>

30000018: ea000015 b 30000074 <HandleIRQ>

============================================

这里我们可以看到 b 指令跳转,可以看到 HandleIRQ

在 30000074 地址上,所以说,我们我们会跳转到 这个地址?

其实是错的。中断,还是复位之类的,都只会跳转到 0 地址等偏移

特别是最上面的 _start 指令为 b 30000020 ,实际上我们知道机器刚开机的时候,外部 ram 还没准备好,此时直接跳转到 30000020 会失败

事实上,b 是一个地址无关跳转码,我们可以看到 他的指令码实际是 ea000006

B跳转指令是一个32位的指令码:其中[31:28]位是条件码;[27:24]位为“1010”(0xeaffffff)时,表示B跳转指令,为“1011”时,表示BL跳转指令;[23:0]表示偏移地址。

机器码是eb000006 ,二进制为1110 1011000000000000000000000110。

其中1110表示无条件执行,接下的1011就是BL指令,如L==0则就表示B指令,剩下的Offset就是链接位。

BL指令的跳转地址计算:

1.如上图所示,先将24位Offset补码左移两位,得到000000000000000000000110 00 =0X18

2.由于ARM流水线,当前PC永远等于PC+8,所以PC=PC+0X28+8=0X30000000+0X18+8=0X30000020。

我们可以看到下面的 reset ,确实是在 0X30000020 的地方

==============================

30000020 <Reset>:

30000020: e3a0da01 mov sp, #4096 ; 0x1000

30000024: eb00001e bl 300000a4 <disable_watch_dog>

30000028: eb000021 bl 300000b4 <clock_init>

3000002c: eb00003a bl 3000011c <memsetup>

30000030: eb0000b5 bl 3000030c <nand_init>

30000034: e3a00203 mov r0, #805306368 ; 0x30000000

30000038: e3a01000 mov r1, #0 ; 0x0

==============================

自此,我们就明白了,实际上中断发生的时候,命令是

b 30000074

跳转到 0x74 位置运行(注意,不是 30000074 而是 0x74)

当时我们代码实际会被拷贝到 片内 ram 上,片内ram 的基地址是 0 ,而中断便宜是 0x74

 

那我们来看下 0x74 的代码内容:前面是汇编、后面是编译后dis文件


=====================================================

HandleIRQ:

sub lr, lr, #4 @ 计算返回地址

stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器

@ 注意,此时的sp是中断模式的sp

@ 初始值是上面设置的4096

ldr lr, =int_return @ 设置调用IRQ_Handle函数后的返回地址

ldr pc, =IRQ_Handle @ 调用中断分发函数,在interrupt.c中

int_return:

ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr

==========================================

30000074 <HandleIRQ>:

30000074: e24ee004 sub lr, lr, #4 ; 0x4

30000078: e92d5fff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}

3000007c: e59fe018 ldr lr, [pc, #24] ; 3000009c <.text+0x9c>

30000080: e59ff018 ldr pc, [pc, #24] ; 300000a0 <.text+0xa0>



30000084 <int_return>:

30000084: e8fd9fff ldmia sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}^

30000088: 30002bc0 andcc r2, r0, r0, asr #23

3000008c: 30000064 andcc r0, r0, r4, rrx

30000090: 300005d8 ldrccd r0, [r0], -r8

30000094: 30000070 andcc r0, r0, r0, ror r0

30000098: 300009f4 strccd r0, [r0], -r4

3000009c: 30000084 andcc r0, r0, r4, lsl #1

300000a0: 30000620 andcc r0, r0, r0, lsr #12

====================================================

我们可以看到 这里采用的是 ldr pc =IRQ_Handle

这里采用的是绝对地址了,而不是 b 指令的偏移地址,可以看到实际上它最终是跳转 30000620

地方,此时已经是内存所在的地方了。

我们来看下30000620

可以看到,这里正是我们的中断处理函数,自此,中断如何从 0x18 地址跳转到 0x30000018的流程分析到此结束

==============================================



30000620 <IRQ_Handle>:

30000620: e52de004 str lr, [sp, #-4]!

30000624: e3a0044a mov r0, #1241513984 ; 0x4a000000

30000628: e3a03001 mov r3, #1 ; 0x1

3000062c: e5901014 ldr r1, [r0, #20]

30000630: e3510004 cmp r1, #4 ; 0x4

30000634: e1a0c113 mov ip, r3, lsl r1

30000638: 03a02080 moveq r2, #128 ; 0x80

3000063c: 03a03456 moveq r3, #1442840576 ; 0x56000000

30000640: 058320a8 streq r2, [r3, #168]

30000644: e59f2014 ldr r2, [pc, #20] ; 30000660 <.text+0x660>

30000648: e580c000 str ip, [r0]

3000064c: e5903010 ldr r3, [r0, #16]

30000650: e5803010 str r3, [r0, #16]

30000654: e1a0e00f mov lr, pc

30000658: e792f101 ldr pc, [r2, r1, lsl #2]

3000065c: e49df004 ldr pc, [sp], #4

30000660: 300033f0 strccd r3, [r0], -r0

==============================================

 

标签:2440,r0,0x18,中断,裸机,pc,地址,lr,跳转
来源: https://blog.51cto.com/u_14640655/3024756