转_arm中system模式的作用

本文探讨了ARM处理器中断可重入的问题,并介绍了如何利用System模式实现中断的可重入。文章提供了具体的汇编代码示例,展示了如何保护中断现场信息,确保在中断处理过程中进行函数调用时不会发生冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转_arm中system模式的作用
2010-10-20 16:44

这几天学了很多arm细节知识,个人平时实在没有深入进去
交了钱被人逼着学才会努力深究,真是贱

以前就知道arm有7种基本工作模式
FIQ 、IRQ由中断进入
UNDEF、ABORT 由程序异常进入
SVC由上电和软中断进入
user由SVC处理程序主动进入
但是还有一个system,使用和user相同的寄存器,但是又没有SPSR,同时还能执行特权指令
这么一个另类,OS把它当user用不安全,当异常和中断,又没有自动进入方式
怎么看怎么别扭,当然这也是领悟之后才意识到的,system是用来解决arm中中断可重入问题的

搜了一下,网上的关于arm可重入中断的解释只有1篇,而且没有考虑完全http://blog.chinaunix.net/u1/58640/showart_513501.html
默认的中断处理函数都会自己先主动把lr压栈先,此文没有考虑这一点,把破坏想的严重了

这样的理论知识实践中几乎没有用到,唯有追求专业的人士才会深究,这样就能满足特殊要求,做到一般人做不到的事情

首先,armcc关键字__irq不能用来编写可重入中断
当中断可重入时,在中断处理函数中使用 BL 调用子函数,这时候问题就来了,分两种情况
如果
子函数不是__irq 方式申明的,没有自己压栈lr的习惯,那么此时再来一个irq中断,lr_irq就被新值冲掉
,从此陷入一个死循环。
如果子函数是会主动压栈lr的好孩子,那么仅仅在执行压栈lr的这条指令时,发生irq中断才会导致上述问题,但是触发问题的条件就变得很苛刻了

所以,这时候就需要system模式来拯救世界了
编写可重入中断必须借助以下汇编代码

IRQHandler
        ;LR_IRQ ,SPSR_IRQ,r12压栈,避免下一个IRQ中断将其冲掉
        sub     lr,lr,#4
        stmfd   sp!,{lr}
        mrs     r14,spsr
        STMFD   sp!,{r12,r14}  

        ;读、清中断控制器中断源
        ;省略相关代码        
        mov     r12,#IntBase
        LDR     r12,[r12,#IntSource]

        ;切换到system模式,同时使能IRQ
        mrs     r14,cpsr
        bic     r14,r14,#0x9f
        orr     r14,r14,#0x1f
        msr     CPSR_c,r14

        ;保存r0-r3,LR_user到user栈中,然后调用c子程序,中断源r0最为一个参数传进c处理函数
        BL      C_irq_handler ;看名字,就知道这个c程序是__irq形式申明的
                                ;是一个会自己压栈LR的好孩子
        LDMFD   sp!,{r0-r3,lr}

        ;切换到IRQ模式同时禁止IRQ
        mrs     r12,cpsr
        bic     r12,r12,#0x1f
        orr     r12,r12,#0x92
        msr     CPSR_c,r12

        ;恢复LR_irq,SPSR_irq和工作寄存器r12,然后退出IRQ
        LDMFD   sp!,{r12,r14}
        msr     SPSR_csxf,r14
        LDMFD   sp!,{PC}^

 

 

可重入中断处理要点

缺省情况下ARM 中断是不可重入的,因为一旦进入异常响应状态,ARM 自动关闭中断使能。如果在异常处理过程中简单地打开中断使能而发生中断嵌套,显然新的异常处理将破坏原来的中断现场而导致出错。但有时候中断的可重入又是需要的,因此要能够通过程序设计来解决这个问题。其中有二点是这个问题的关键:

(a) 新中断使能之前必须要保护好前一个中断的现场信息,比如LR_irq 和SPSR_irq 等,这一点容易想到也容易做到。

(b) 中断处理过程中对BL 的保护

在中断处理函数中发生函数调用(BL)是很常见的,这个问题无法通过增加额外的现场保护指令来解决。一个巧妙的办法是在重新使能中断之前改变处理器的模式,也就是使上面程序中的“BL Foo”指令不要运行在IRQ 模式下。这样当新中断发生时就不会造成LR 寄存器的冲突了。考虑ARM 的所有运行模式,采用System 模式是最恰当的,因为它既是特权模式,又与中断响应无关。

下面是可重入代码(包括BL调用)的基本流程代码:

        ;/* @ Save return address */
        sub     lr, lr, #4
        stmfd   sp!, {lr}
       
        ;/* @@ Save spsr_fiq */
        mrs   r14, spsr
        stmfd sp!, {r14}
         
        ;/* here should disable the corresponding interrupt */
         
        ;/* @@@ Change to SYS mode and enable system FIQ */
        msr     cpsr_c, #0x1F
       
        ;/* @@@@ Save SYS mode registers which next C routine will use */
        stmfd sp!, {r0-r12, lr}
       
        ;/* @@@@@ Jump to C code */
        IMPORT C_Fiq_Handler
        bl   C_Fiq_Handler
       
        ;/* @@@@ Restore SYS mode registers */
        ldmfd sp!, {r0-r12, lr}
       
        ;/* @@@ Change mode back to FIQ mode and disable FIQ */
        msr   spsr_c, #(0x11 | Bit_FIQ)
       
        ;/* here should enable the corresponding interrupt */
       
        ;/* @@ restore spsr register */
        ldmfd sp!, {r14}
        msr   spsr_c, r14
       
        ;/* @ return */
        ldmfd sp!, {pc}^

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值