S3C2440中断跳转分析
2440init.s中断跳转分析
最近准备自己写一个S3C2440的启动代码。参阅了一下2440init.s这一启动代码。发现有很多人对于这个启动代码中的异常,特别是像外部中断这样的异常,到底在2440init.s中是如何实现跳转的这一问题有很大的疑惑。现在就我的理解对这个过程做一下解说。说的不一定很好,呵呵,权当消遣吧。另外,这里面的错误肯定会有,大家尽管给我提吧。
首先要大家要明白,特别是初学者,当S3C2440发生异常时,其程序指针是会被强制转换的,这个是硬件自己完成的,不需要我们的干涉。下面这个表格就是具体的强制指针转化表。
地址 |
异常名称 |
2440init.s 中的指令 |
0x00 |
复位异常 |
b ResetHandler |
0x04 |
未定义指令异常 |
b HandlerUndef |
0x08 |
软件中断异常 |
b HandlerSWI |
0x0c |
指令预取异常 |
b HandlerPabort |
0x10 |
数据预取异常 |
b HandlerDabort |
0x14 |
保留 |
b . |
0x18 |
IRQ中断异常 |
b HandlerIRQ |
0x1c |
FIQ中断异常 |
b HandlerFIQ |
现在可以很清楚的知道了。如果S3C2440刚上电或者是复位,那么pc指针被硬件强制转换到0x00地址处,那么按照2440init.s中的指令“b ResetHandler”,pc会跳转到ResetHandler处继续执行程序。同样,当发生外部中断时,pc指针会被强制转换到0x18处,执行“b HandlerIRQ”这条指令。
接下去,便是讨论程序跳转之后如何运行的了。首先,我们做一个设想,假设S3C 2440只有一个中断(当然这是不可能的了,就连51也有5个中断源。),那么可想而知,程序跳转到HandlerIRQ处就应该执行中断处理函数了。也就是说,我们在C语言中写的中断处理函数的地址应该就是HandlerIRQ的内容了。虽然这个假设不可能,但它可以帮助我们理解。本质上其实就是类似于这样的一个过程,只不过因为S3C2440有那么多的中断源,所以不可能把中断函数的地址直接赋给HandlerIRQ就行了。这中间应该还有一个转换。就是根据不同的、具体的中断源,让HandlerIRQ对应于不同的中断处理函数的地址。
那么接下来看看HandlerIRQ标号后面的内容吧。
HandlerIRQ HANDLER HandleIRQ
很明显,这里还有一个宏定义在里面,要知道HANDLER的内容,我们可以在2440init.s中查到:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4
stmfd sp!,{r0}
ldr r0,=$HandleLabel
ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,pc}
MEND
下面对这个宏定义做一下说明。首先是MACRO表明了宏定义的开始,MEND则表示了宏定义的结束。这个宏的作用其实就是在不改变任何寄存器的前提下,把pc指针指向$HandleLabel。
明白了这个以后,我们就可以把这个宏去掉再来理解一遍:
首先是当S3C2440发生外部中断时,pc指针被强制指向了0x18处:
b HandlerIRQ
……
HandlerIRQ
sub sp,sp,#4
stmfd sp!,{r0}
ldr r0,=HandleIRQ
ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,pc}
经过上面的程序后,此时的pc指针已经指向了HandleIRQ处。呵呵,挺简单的吧。然后
呢。我们就得关注一下HandleIRQ这个标号了。它在2440init.s中设这样定义的:
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
……
很简单,这里定义了一个文字池,首地址:_ISR_STARTADDRESS代表了地址为0x33FF_FF00的内存区域,每隔4个字节,定义一个标号。很很容易就找到了 HandleIRQ这个我们需要找的标号。那么它所代表的内存区域自然就是0x33FF_FF00+0x04*6的内存地址了。那么接下来的工作就是要把真正的、具体的中断处理函数的地址赋给HandleIRQ了。这里大家先看一下下面的两端代码:
(1):
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]
(2):
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
首先我们来看一下第(1)段程序,前面已经提到,此时的的pc已经指向了HandeIRQ所表示的内存了,但是现在该内存还是空的,pc跳转到这里也不能接着往下运行了。所以才有了第1段代码,它的作用就是给HandleIRQ安装句柄了,把IsrIRQ的入口地址填充到了HandeIRQ里面了。所以程序接着就会跳转到IsrIRQ处执行。也就是上面的第(2)段程序了。这段程序具体讲解我就不说了,跟最上面的宏定义很类似,其实就是让PC跳转到另外一个地方(pc=HandleEINT0+INTOFFSET*4)。而那个地方正是真正的中断函数。那我们再来看看这个地址是怎么算出来的。首先HandleEINT0就是上面那个MAP定义里面的一个内存区域,有没有发现它是第一个中断源,紧接着它,就是其它各种类型的中断源了。而INTOFFSET则是S3C2440的一个特殊功能寄存器了,某个类型的中断发生了,它的值就会发生变化。而后面为什么要乘以4呢,因为文字池中定义的标号都是4字节的,其实是因为S3C2440中指针变量就是占据4个字节的,这个可以用sizeof(*p)来验证。所以此时pc指针就指向了另外一个地方,那就是刚才说的中断表了。而在c语言中,我们通常会有这样的中断函数句柄安装语句:pISR_EINTn = (unsigned int )key_interrupt;
这里的pISR_EINTn其实是有定义的,我们以pISR_EINT0为例,宏定义如下:
#define pISR_EINT0 _ISR_STARTADDRESS+0X20
看这个地址,其实就是上面那个中断表里面的:
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
……
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
……
大家发现了吧,HandleEINT0的地址是不是就是 _ISR_STARTADDRESS+0X20,所以说c语言中我们写的中断函数安装句柄,就是这个作用。
好的,现在让我们来总结一下吧。(以外部中断0为例)
首先是在c语言的函数中,我们已经执行了这样一条语句pISR_EINTn = (unsigned int )key_interrupt;它的作用是把中断处理函数key_interrupt的地址赋给了中断表中的HandleEINT0。
然后当某个时刻,发生了外部中断0,那么pc指针被强制指向了0x18处,执行指令:
b HandlerIRQ
跳转到HandlerIRQ之后,执行如下代码:(已经把宏定义屏蔽)
HandlerIRQ
sub sp,sp,#4
stmfd sp!,{r0}
ldr r0,=HandleIRQ
ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,pc}
然后pc之争有指向了HandleIRQ这个内存区域。而又由于HandlerIRQ已经被安装了IsrIRQ的句柄,所以紧接着pc又跳转到IsrIRQ处执行如下程序:
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
它的作用是让pc指针根据INTOFFSET的值跳转到中断向量表中的HandleEINT0处。而在此处已经被安装了c语言中的中断处理函数的句柄,所以pc又跳到了中断处理函数中区执行中断函数了。
S3C2440中断跳转分析相关推荐
- s3c2440启动文件详细分析
启动文件就是引导ARM启动,并进入我们熟悉的C语言程序.它主要完成了ARM最基本的硬件初始化工作.虽然启动文件的内容大同小异(就是设置系统时钟.内存.中断向量表.栈等内容),而且只要有一个现成的启动文 ...
- ARM中断返回地址详细分析
ARM中断返回地址详细分析 在ARM体系中,通常有以下3种方式控制程序的执行流程: 1.在正常执行过程中,每执行一条ARM指令,程序计数器PC的值加4个字节:每执行一条Thumb指令,程序计数器PC加 ...
- ARM Cortex-M3中断跳转过程
在学习CM3的时候,仔细学习了CM3的中断跳转过程,发现嵌入式的MCU在这一块基本上是一样的,当然不同架构的MCU也有自己的特性. 我来介绍下CM3的中断跳转过程,首先假设中断发生,CM3内核开始响应 ...
- Linux x86_64 APIC中断路由机制分析
不同CPU体系间的中断控制器工作原理有较大差异,本文是<Linux mips64r2 PCI中断路由机制分析>的姊妹篇,主要分析Broadwell-DE X86_64 APIC中断路由原理 ...
- 多线程环境下海量定时任务的定时器设计丨时间轮实现丨红黑树,跳表分析
多线程环境下海量定时任务定时器设计 1. 定时器分析 2. 红黑树,最小堆,跳表实现比较分析 3. 时间轮实现 [Linux后端开发系列]多线程环境下海量定时任务的定时器设计丨时间轮实现丨红黑树,跳表 ...
- 【转】三星三款主流处理器s3c2440\s3c6410\s5pv210对比分析
三星三款主流处理器s3c2440\s3c6410\s5pv210对比分析 对比1.ARM架构 ? S3C2440:属于ARM9架构 ? S3C6410:属于ARM11架构 ? S5PV210:属于Co ...
- S3C2440中断解析和基于WINCE操作系统的中断分析(整理于网络,用于按键中断使用)
在调试CAN总线的时候,遇到了操作系统的中断,为了彻底的弄清楚中断是怎么回事?我先从底层的中断开始研究,在这里我们只讨论外部中断,下面就结合S3C2440TEST测试程序来分析一下中断是怎么执行的:我 ...
- 2.6.18-2内核中对S3C2440的引导启动分析
这是以前玩Arm的时候写的~ 主要参考了xpl的arm linux kernel 从入口到start_kernel 的代码分析 http://linux.chinaunix.net/bbs/threa ...
- 64位多核 MIPS 异常和中断内核代码分析
http://hi.baidu.com/comcat/blog/item/3cff7bddec14a1f176c6388a.html 1. 概述 MIPS 统称异常(同步事件)和中断(异步事件)为例外 ...
最新文章
- PingCode Wiki 多人实时协同编辑功能发布
- RHEL5 下使用syslog-ng构建集中型日志服务器
- 每天一个linux命令(16):which命令
- mfc static 文本自适应宽度_基于单双词的自适应单调启发式搜索的文本攻击
- protoc.exe java_protobuf——使用protoc.exe生成message文件
- 1.1 torch_数据操作
- iOS 定位功能的实现
- 关于Activity的getReferrer():如何在Activity中获取调用者?
- JVM学习-分代收集算法
- 拓端tecdat|matlab使用长短期记忆(LSTM)神经网络对序列数据进行分类
- XSS漏洞扫描器(2种方法)
- 基于Packet Tracer的校园网络设计与规划
- Java项目:超市进销存管理系统(java+SpringBoot+Html+Layui+echarts+mysql)
- ACK Acknowledgement 确认 AES Advanced Encryption Standard 高级加密标准 ATM Asynchronous Transfer Mode异步传输模式
- python中如何查一个函数的用法_Python常见内置函数用法(三)
- Hadoop 表和字段
- 为什么GPU训练网络还不如CPU快
- 【数据结构与算法】冒泡排序算法(BubbleSort)
- 【C语言】重要函数atoi的使用
- u盘安装linux戴尔boot设置,戴尔台式机bios设置,详细教您如何安装U盘启动
热门文章
- 阿里员工都在用的知识管理工具,究竟有何特别?
- AssetBundle Workflow
- [Java] 实现多线程的两种方法
- android常用组件之RadioGroup
- [转]Could not load file or assembly 'XXX' or one of its dependencies.
- awk 实例练习 (三)
- 实现Profile购物车的匿名用户迁移
- in作为介词的用法_英语中in/on/at/to/from/by/with/for/about/after/before的用法
- linux显卡驱动版本最好,Linux 用户如何安装 Nvidia 331.67 显卡驱动稳定版本
- java set的first_Java TreeSet pollFirst()方法与示例