历史上的今天
今天是:2025年07月28日(星期一)
2021年07月28日 | 浅分析 2440 中断是如何从0x18地址运行到0x30000000 + 0x18
2021-07-28 来源:eefocus
此篇主要是分析裸机的,
后面会有一篇分析 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 30000004 30000004: eafffffe b 30000004 30000008 30000008: eafffffe b 30000008 3000000c 3000000c: eafffffe b 3000000c 30000010 30000010: eafffffe b 30000010 30000014 30000014: eafffffe b 30000014 30000018: ea000015 b 30000074 ============================================ 这里我们可以看到 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 30000020: e3a0da01 mov sp, #4096 ; 0x1000 30000024: eb00001e bl 300000a4 30000028: eb000021 bl 300000b4 3000002c: eb00003a bl 3000011c 30000030: eb0000b5 bl 3000030c 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 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 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 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 ==============================================
史海拾趣
|
本帖最后由 paulhyde 于 2014-9-15 08:58 编辑 看着这几个题目。。。还不确定选哪个。。。(还是高职高专的好做) … 查看全部问答> |
|
以下转自 越测越开心 的博客,其原文地址如下: http://forum.eet-cn.com/BLOG_ARTICLE_2965.HTM 本系列博文由我们的老用户H3C北京公司常羽飞特别供稿 (4)——我的地盘我做主示波器这个玩意儿,虽说有明确的资产所有人,不过流动性实在太大 ...… 查看全部问答> |
|
盲人在美国研制的生活设备BrainPort帮助下,可以读书,辨别物体形状和独立行走,这可能彻底改变盲人的生活。 该设备将图形转换为脉冲电流并发送到使用者的舌头上从而引起刺痛感。不同强度的痛感可以被翻译成不同的信息,从而使失明者能够感知周围 ...… 查看全部问答> |
|
WDK+DDKWizard+vs2008环境,都设置好了却总是生成win7的sys,怎么回事 如题。ddkbuild.bat,cmd,拷到了winddk目录下,加了wxpbase环境变量,vc目录选好了。 用ddkwizard建一个driver,选winxp的驱动,生成工程。原封不动的编译,只能得到win7的驱动。 ddkwizard连win7都不支持,怎么会出现这种情况?! 高手帮忙看一 ...… 查看全部问答> |
|
我用ew430时,第一次,建了一个workspace 和 project.但下一次却打不开,提示是不存在.我用的是4k的试用版.请问各位大侠,这是什么原因? … 查看全部问答> |




