您的位置 首页 传感器

S3C2440中止代码的深层次剖析

在前一段时间分析了ARM异常处理机制的处理方式,分析了在异常产生以后CPU自动完成的相关处理以及程序员应该完成的基本操作。着重分析了异常

在前一段时间剖析了ARM反常处理机制的处理办法,剖析了在反常发生今后CPU主动完结的相关处理以及程序员应该完结的根本操作。侧重剖析了反常代码的回来地址剖析现已选用通用代码处理各种反常的可能性。

反常处理的根本进程如下:反常发生(在指令的临界中检测CPU的状况,一般本质在这条指令被履行完结,可是还没有履行下一条指令之前检测)——>保存状况寄存器,切换状况寄存器,保存LR=PC-4,强制PC跳转到对应反常向量(以上的进程都是CPU主动完结)——》调整回来地址,在栈中保存寄存器,便于康复寄存器的值——》反常处理函数——》退出反常。
中止处理机制的两种办法:
1、选用在中止向量中存储简略的跳转指令,跳转到反常处理函数中,可是这种办法存在的缺陷便是跳转指令的规模是有局限性的。
2、选用更新PC值的办法进行,详细的完成办法是在另一个固定地址处(handle_addr)保存对应反常处理函数的地址,然后选用LDR PC [PC, offset],其间offset = handle_addr – vect – 0x08;这种机制只需确保挑选的地址恰当就能完成不同间隔的跳转。
以上的剖析和处理在上一次中现已剖析,这次剖析中止的处理进程,中止仅仅反常的一种特别状况,对反常的处理得到了好的了解,那么对中止的处理也就比较方便了。
在ARM内核中只支撑IRQ和IFQ两种类型的中止,可是不同的厂商供给不同类型的中止控制器完成对中止的扩展,使得实践的芯片愈加合适咱们的运用。可是中止控制器的不同也使得不同厂商的中止处理也有不同,可是根本的思维是共同的。
S3C2440的中止控制器一个支撑60种中止源,根本的完成如上图所示。根本的寄存器包含SRCPND、INTPND(有且仅有1bit会被置位,能够经过这个寄存器判别中止源,找出那个IRQ源发生中止)、INTMOD、INTMSK、PRIORITY(用来改动中止的优先级次序,可是其间仍是存在一些固有的次序,详细的参看手册)、INTOFFSET(用来表明IRQ中INTPND的那个bit被置位,这样每一类的中止源都存在一个固定的偏移量,这个寄存器能够用来用来核算偏移量以及经过这个偏移量找到对应的中止处理函数地址存储方位等),当然也存在一些关于多个中止源构成的子中止寄存器,SUBSRCPND、INTSUBMSK。
在S3C2440的发动代码中描绘了关于中止处理进程的根本进程和原理。
首要需求搞清楚下面的一个宏界说:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
subsp,sp,#4;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
1、搞清楚ARM中的MACRO伪指令,这个伪指令便是咱们在汇编中的宏界说,咱们都知道宏的完成能够防止代码的重复型以及代码的可修复性。关于ARM汇编中的宏界说根本的办法如下:
MACRO
{$label} macroname {$parameter} {$parameter}…
Code
MEND
其间$label 宏指令被打开时,label可被替换为相应的符号,一般为一个标号
macroname所界说的宏的称号
$parameter宏指令的参数,当宏指令被打开时被替换成对应的值。
2、依据上面的界说咱们能够知道当时这段代码界说了一个宏指令,HANDLER,其间标号为$HandlerLabel,参数为$HandleLabel
根本的完成代码剖析如下:
subsp,sp,#4;在栈中预留一个区域,用来保存PC的值
stmfd sp!,{r0};因为r0还需求被运用,因而需求被压栈
ldr r0,=$HandleLabel ;这儿的ldr是一个伪指令,主要是将标号$HandleLabel的地址加载到r0中,这也是压栈r0的原因。
ldr r0,[r0] ;这是ARM的ldr指令,主要是将$HandleLabel对应地址中的内容加载到r0中。如果在$HandleLabel中保存的是一个中止处理函数的地址,那么只需求将这个值加载到PC即可完成了中止使命跳转,实践上这个进程便是选用了反常处理的第二种办法:
即加载PC的办法,而不是简略的跳转办法。
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
这两句代码正是这段代码的精华。根本办法如下:
str r0,[sp,#4],是指将r0的内容,也便是反常处理函数的地址保存到栈中的SP-4方位处,这个方位也刚好是之前sub sp,sp,#4;用来预留给保存PC值的方位,这时将反常处理函数的地址保存在这个地址处,接下来的ldmfd sp!,{r0,pc}刚好便是将栈中的内容加载到R0和PC中,这样也就完成了将反常处理函数地址加载到PC.完成了跳转进程。
高地址
SP_0/SP_3
SP_1
Handle_addr
SP_2
R0
低地址
从上面的剖析能够知道这种中止处理的办法,并不是中止处理中的简略跳转办法(因为跳转规模的局限性)而是选用更新PC值的办法完成的。
接下来剖析IRQ,这种在咱们实践开发中运用比较多的中止办法进行剖析。
首要能够发现存在:
1、b HandlerIRQ;handler for IRQ interrupt
这种状况下发生在中止发生进程中,是在IRQ向量中履行的,也便是在0x18处履行,其间HandlerIRQ本质上是一个标号,对应一个详细的地址。其间保存的内容便是对应IRQ处理函数的地址。可是在代码中只要一个HandlerIRQ,办法如下:
HandlerIRQHANDLER HandleIRQ
2、HandlerIRQ HANDLER HandleIRQ
依据上面的宏界说,能够将这句代码进行扩展,得到如下的办法:
HandlerIRQ
subsp,sp,#4
stmfd sp!,{r0}
ldr r0,= HandleIRQ
ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,pc}
3、关于HandleIRQ其间寄存的内容能够从下面的代码中得到。
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there is not subs pc,lr,#4 at 0x18, 0x1c
str r1,[r0]
其间能够看到,在HandleIRQ中保存的内容是IsrIRQ的地址,而IsrIRQ咱们能够知道是一个中止服务函数,因为在写代码的进程中进程会遇到这个特别字符__ISR,这段代码是在发动代码中履行的。
4、IsrIRQ完成问题
IsrIRQ
subsp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
addr8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
仍是一句一句的剖析:
subsp,sp,#4 ;为保存PC值预留一个栈区域,这个区域与上面的处理进程是殊途同归的。
stmfd sp!,{r8-r9} ;保存r8,r9中的值,因为接下来将运用这两个寄存器
ldr r9,=INTOFFSET;这是一个伪指令操作,本质上是将寄存器INTOFFSET的地址加载到r9中。
ldr r9,[r9];得到寄存器中的值,这个寄存器中的值刚好保存了当时最高优先级中止的中止号(优先级是能够调理的,而中止号是一个固定值,因而挑选中止号比较恰当),这样也就知道了详细是那个中止源发生了中止。
ldr r8,=HandleEINT0;这句的ldr是伪指令,意思是将标号的地址加载到r8中
addr8,r8,r9,lsl #2;从指令的含义剖析:r8 = r8 + r9>>2 = r8+r9*4;
其实这两句结合一下S3C2440的中止材料就不难剖析得出,因为HandleEINT0本质上是指存储外部中止0处理函数地址的当地,那么咱们能够将这一块内存地址看做是一个IRQISR中止向量表,而EINT0刚好是中止优先级最高的中止,那么能够将这个地址HandleEINT0作为IRQ中止向量表的进口地址,其他中止号的地址,只需求经过偏移地址就能得到,因为指针的巨细刚好为4个字节,因而得到的相应中止号的进口地址是
HandleEINT0 = HandleEINT0 + INTOFFSET*4,
这些地址中都保存了对应中止处理函数的函数地址。
ldr r8,[r8]是指将r8的内容加载到r8中,也便是将对应中止处理函数的地址加载到r8中。
str r8,[sp,#8];这句代码的效果本质上便是和上面的剖析相同,也便是将r8的值保存到之前为PC预留的区域中。
ldmfd sp!,{r8-r9,pc};这句也刚好验证了上面的剖析,PC中的值刚好便是之前的sp+8处的内容,这样中止处理函数的地址就到了PC中。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/317756.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部