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中断跳转分析相关推荐

  1. s3c2440启动文件详细分析

    启动文件就是引导ARM启动,并进入我们熟悉的C语言程序.它主要完成了ARM最基本的硬件初始化工作.虽然启动文件的内容大同小异(就是设置系统时钟.内存.中断向量表.栈等内容),而且只要有一个现成的启动文 ...

  2. ARM中断返回地址详细分析

    ARM中断返回地址详细分析 在ARM体系中,通常有以下3种方式控制程序的执行流程: 1.在正常执行过程中,每执行一条ARM指令,程序计数器PC的值加4个字节:每执行一条Thumb指令,程序计数器PC加 ...

  3. ARM Cortex-M3中断跳转过程

    在学习CM3的时候,仔细学习了CM3的中断跳转过程,发现嵌入式的MCU在这一块基本上是一样的,当然不同架构的MCU也有自己的特性. 我来介绍下CM3的中断跳转过程,首先假设中断发生,CM3内核开始响应 ...

  4. Linux x86_64 APIC中断路由机制分析

    不同CPU体系间的中断控制器工作原理有较大差异,本文是<Linux mips64r2 PCI中断路由机制分析>的姊妹篇,主要分析Broadwell-DE X86_64 APIC中断路由原理 ...

  5. 多线程环境下海量定时任务的定时器设计丨时间轮实现丨红黑树,跳表分析

    多线程环境下海量定时任务定时器设计 1. 定时器分析 2. 红黑树,最小堆,跳表实现比较分析 3. 时间轮实现 [Linux后端开发系列]多线程环境下海量定时任务的定时器设计丨时间轮实现丨红黑树,跳表 ...

  6. 【转】三星三款主流处理器s3c2440\s3c6410\s5pv210对比分析

    三星三款主流处理器s3c2440\s3c6410\s5pv210对比分析 对比1.ARM架构 ? S3C2440:属于ARM9架构 ? S3C6410:属于ARM11架构 ? S5PV210:属于Co ...

  7. S3C2440中断解析和基于WINCE操作系统的中断分析(整理于网络,用于按键中断使用)

    在调试CAN总线的时候,遇到了操作系统的中断,为了彻底的弄清楚中断是怎么回事?我先从底层的中断开始研究,在这里我们只讨论外部中断,下面就结合S3C2440TEST测试程序来分析一下中断是怎么执行的:我 ...

  8. 2.6.18-2内核中对S3C2440的引导启动分析

    这是以前玩Arm的时候写的~ 主要参考了xpl的arm linux kernel 从入口到start_kernel 的代码分析 http://linux.chinaunix.net/bbs/threa ...

  9. 64位多核 MIPS 异常和中断内核代码分析

    http://hi.baidu.com/comcat/blog/item/3cff7bddec14a1f176c6388a.html 1. 概述 MIPS 统称异常(同步事件)和中断(异步事件)为例外 ...

最新文章

  1. PingCode Wiki 多人实时协同编辑功能发布
  2. RHEL5 下使用syslog-ng构建集中型日志服务器
  3. 每天一个linux命令(16):which命令
  4. mfc static 文本自适应宽度_基于单双词的自适应单调启发式搜索的文本攻击
  5. protoc.exe java_protobuf——使用protoc.exe生成message文件
  6. 1.1 torch_数据操作
  7. iOS 定位功能的实现
  8. 关于Activity的getReferrer():如何在Activity中获取调用者?
  9. JVM学习-分代收集算法
  10. 拓端tecdat|matlab使用长短期记忆(LSTM)神经网络对序列数据进行分类
  11. XSS漏洞扫描器(2种方法)
  12. 基于Packet Tracer的校园网络设计与规划
  13. Java项目:超市进销存管理系统(java+SpringBoot+Html+Layui+echarts+mysql)
  14. ACK Acknowledgement 确认 AES Advanced Encryption Standard 高级加密标准 ATM Asynchronous Transfer Mode异步传输模式
  15. python中如何查一个函数的用法_Python常见内置函数用法(三)
  16. Hadoop 表和字段
  17. 为什么GPU训练网络还不如CPU快
  18. 【数据结构与算法】冒泡排序算法(BubbleSort)
  19. 【C语言】重要函数atoi的使用
  20. u盘安装linux戴尔boot设置,戴尔台式机bios设置,详细教您如何安装U盘启动

热门文章

  1. 阿里员工都在用的知识管理工具,究竟有何特别?
  2. AssetBundle Workflow
  3. [Java] 实现多线程的两种方法
  4. android常用组件之RadioGroup
  5. [转]Could not load file or assembly 'XXX' or one of its dependencies.
  6. awk 实例练习 (三)
  7. 实现Profile购物车的匿名用户迁移
  8. in作为介词的用法_英语中in/on/at/to/from/by/with/for/about/after/before的用法
  9. linux显卡驱动版本最好,Linux 用户如何安装 Nvidia 331.67 显卡驱动稳定版本
  10. java set的first_Java TreeSet pollFirst()方法与示例