当前位置: 首页 > news >正文

广州市黄埔区建设局网站乐享视频在线下载免费

广州市黄埔区建设局网站,乐享视频在线下载免费,网页设计基础只是,网站免费服务器windowsCE异常和中断服务程序初探 ---------by nasiry 转载请说明出处 1。中断/异常相量的装入和执行方式。 中断和异常都是异步发生的事件#xff0c;当该事件发生#xff0c;系统将停止目前正在执行的代码转而执行事件响应的服务程序。而事件服务程序的入口点就…windowsCE异常和中断服务程序初探 ---------by nasiry 转载请说明出处 1。中断/异常相量的装入和执行方式。             中断和异常都是异步发生的事件当该事件发生系统将停止目前正在执行的代码转而执行事件响应的服务程序。而事件服务程序的入口点就是中断/异常向量所在的位置。arm的中断向量可以是0x0开始的低地址向量也可以是在FFFF0000位置的高向量地址。winCE下使用高地址作为trap区所以在CE下arm使用高地址向量。下面我们来了解一下中断/异常向量的安装和执行过程。  在kernelStart的过程中通过程序将如下代码复制到ffff0000的位置. VectorInstructions         ldr     pc, [pc, #0x3E0-8]              ; reset         ldr     pc, [pc, #0x3E0-8]              ; undefined instruction         ldr     pc, [pc, #0x3E0-8]              ; SVC         ldr     pc, [pc, #0x3E0-8]              ; Prefetch abort         ldr     pc, [pc, #0x3E0-8]              ; data abort         ldr     pc, [pc, #0x3E0-8]              ; unused vector location         ldr     pc, [pc, #0x3E0-8]              ; IRQ         ldr     pc, [pc, #0x3E0-8]              ; FIQ 而在ffff03e0的位置放上如下的数据每一项(32bit)对应一个异常的跳转地址也就是winCE的异常/中断向量跳转表。该表项的内容就是发生异常后将要执行的服务程序的入口地址。具体如下。 VectorTable         DCD     -1                              ; reset         DCD     UndefException                  ; undefined instruction         DCD     SWIHandler                      ; SVC         DCD     PrefetchAbort                   ; Prefetch abort IF :DEF:ARMV4T :LOR: :DEF:ARMV4I         DCD     OEMDataAbortHandler             ; data abort         ELSE         DCD     DataAbortHandler                ; data abort         ENDIF DCD     -1                              ; unused vector         DCD     IRQHandler                      ; IRQ         DCD     FIQHandler                      ; FIQ       在上面的这些代码/数据在内存空间上按照上述要求放置好以后每次触发一个异常就自动运行到相应跳转表项所对应的地址执行。   2.异常/中断服务程序   在arm下由于有7种异常状态包括reset、Undef exception、software interrupt(swi)、Prefech Abort、DataAbort、IRQ、FIQ七种异常/中断。reset仅在复位时发生其他6种都是在系统运行时发生。当任何一个异常发生并得到响应时ARM 内核自动完成以下动作  拷贝 CPSR 到 SPSR_mode  设置适当的 CPSR 位  改变处理器状态进入 ARM 状态  改变处理器模式进入相应的异常模式  设置中断禁止位禁止相应中断  更新 LR_mode  设置 PC 到相应的异常向量  同时不管异常发生在ARM 还是Thumb 状态下处理器都将自动进入ARM 状态。并且中断使能会自动被关闭。在这个时候由于部分通用寄存器是不同模式公用的所以还需要保存这些将会被破坏的寄存器待到处理完成的时候恢复这些寄存器被中断前的状态。另外在进入异常模式后lr的值不一定就是我们所需恢复执行的位置该位置受到异常类型和流水线误差的影响。在SWI模式下LR就是返回值。在IRQ和FIQ中LRLR-4,DataAbort下LRLR-8;具体原因我们就不讨论了有兴趣可以参看基于ARM 的嵌入式程序开发要点一文。下面分别对这些服务程序进行分析。    2-1.undef exception服务程序       undef exception在执行到过非法的指令时产生通常来模拟一些处理器不支持的功能如浮点运算。简单说一下undef exception的过程当当前指令为一条处理器不支持的指令时处理器会自动动将该指令送交各协处理器(如MMU、FPU)处理如果这些协处理器都无法识别这条指令的时候就产生该异常。下面开始看相应的代码。         NESTED_ENTRY    UndefException         sub     lr, lr, #4                      ; (lr) address of undefined instruction         stmdb   sp, {r0-r3, lr}         mov     r1, #ID_UNDEF_INSTR         b       CommonHandler         ENTRY_END UndefException 上面就是undef Exception的服务程序的入口处(已经将不参与编译和Thumb模式下的代码去掉)通过lr-4计算出触发异常前的指令地址同时保存r0-r3和lr入undef_exception stack用于最后恢复现场和取得异常指令本身随后进入分发程序CommonHandler.CommonHandler是一个公共的异常服务程序它通过不同的传入参数来进行处理在这里mov r1,#ID_UNDEF_INSTR就是指定异常模式为undef Exception.   2-2.swi服务程序             按在ARM处理器的设计意图系统软件的系统调用(SystemCalls)都是通过SWI指令完成。SWI相当于一个中断指令不同的是SWI不是由外部中断源产生的同时对应于SWI的异常向量位于0xc的位置或0xffff 000c的位置。也就是说当执行一个swi指令后当前程序流中断并转入0xc或0xffff000c执行同时将CPSR_mode(当前程序状态寄存器)复制入SPSR_svc转入SVC模式运行(使用特权模式的寄存器组)。也就是说系统通过执行SWI引发系统swi异常后切换入特权模式系统调用功能号由swi xx后的xx决定在运行完指定功能的代码后返回异常时的地址并恢复用户模式。我们看看Wince中这部分代码是如何实现的。         DCD     SWIHandler                      ; SVC--------------------------SWI入口点。               LEAF_ENTRY SWIHandler   IF {FALSE}                  ...   ENDIF         movs    pc, lr         ENTRY_END SWIHandler         上面IF {FALSE}到ENDIF之间的代码在编译的时候是得不到编译的(事实上这部分代码是用于开发中调试使用的针对特殊的硬件平台一般与我们使用的硬件平台无关。所以下面摘抄的代码都不将不参与编译的内容写入)因此SWI服务程序就是一句话。movs    pc, lr也就是直接回到SWI的地方同时将SPSR_svc恢复到CPSR_mode中。这个过程中并没有进行在系统态执行特定系统指令序的工作而仅仅是简单的返回所以这不是系统调用系统调用还需要根据调用号的不同运行指定的核心态代码。也就是说Wince的系统调用不是通过SWI来完成的而是通过其他的异常处理手段达成的。 2-3 中断服务程序 IRQ(大概是最熟悉的异常方式了)在外部中断源在需要向处理器请求服务时发生比如时钟、外围器件FIFO上/下溢出、按键等等。IRQHandler就是中断的处理句柄下面我们来具体看看。 ----------------------------------------------------------------------------------         NESTED_ENTRY IRQHandler         sub     lr, lr, #4                      ; fix return address         stmfd   sp!, {r0-r3, r12, lr}       保存将要用到的寄存器和lr压入stack_irq         PROLOG_END         和上面一样服务程序的入口处都是例行公事的计算返回位置以抵消流水线误差。再将要用到的寄存器压入STACK_IRQ这样准备工作就做完了。         ; Test interlocked API status.                ;INTERLOCKED_START EQU USER_KPAGE0x380     ;INTERLOCKED_END EQU USER_KPAGE0x400         sub     r0, lr, #INTERLOCKED_START         cmp     r0, #INTERLOCKED_END-INTERLOCKED_START         bllo    CheckInterlockedRestart         上面这部分的内容是关于互锁的检测由于如信号量这些同步手段都必须作为原子操作进行,不允许打断。所以如果中断发生在互锁API的执行过程中就需要专门的处理了。这些API都是放在INTERLOCKED_START和INTERLOCKED_END之间的通过LR很容易就检查出是否是INTERLOCKEDXXX的过程中。这里并不关心互锁的实现就绕开这部分代码继续往下看当作中断没有发生在interlock过程处理。         ;         ; CAREFUL! The stack frame is being altered here. Its ok since         ; the only routine relying on this was the Interlock Check. Note that         ; we re-push LR onto the stack so that the incoming argument area to         ; OEMInterruptHandler will be correct.         ;         mrs     r1, spsr                        ; (r1) saved status reg         stmfd   sp!, {r1}                       ; save SPSR onto the IRQ stack            mov     r0,lr                           ; parameter to OEMInterruptHandler      msr     cpsr_c, #SVC_MODE:OR:0x80       ; switch to supervisor mode w/IRQs disabled         stmfd   sp!, {lr}                       ; save LR onto the SVC stack                stmfd   sp!, {r0}                       ; save IRQ LR (in R0) onto the SVC stack (param)         ;         ; Now we call the OEMs interrupt handler code. It is up to them to         ; enable interrupts if they so desire. We cant do it for them since         ; theres only on interrupt and they havent yet defined their nesting.         ; CALL    OEMInterruptHandler         ldmfd   sp!, {r1}                       ; dummy pop (parameter)         ldmfd   sp!, {lr}                       ; restore SVC LR from the SVC stack         msr     cpsr_c, #IRQ_MODE:OR:0x80       ; switch back to IRQ mode w/IRQs disabled     ; Restore the saved program status register from the stack.         ;         ldmfd   sp!, {r1}                       ; restore IRQ SPSR from the IRQ stack         msr     spsr, r1                        ; (r1) saved status reg         ldr     lr, KData                      ; (lr) ptr to KDataStruct                         cmp     r0, #SYSINTR_RESCHED      ;-时间片已到进行调度         beq     %F10                    ;SYSINTR_DEVICES EQU 8         ;是否设备中断中断号是否有效     ;SYSINTR_MAX_DEVICES EQU 32            sub     r0, r0, #SYSINTR_DEVICES         cmp     r0, #SYSINTR_MAX_DEVICES                             ;由此可以看出windowsCE的系统中断号最大支持32种从9-40.                             ;其中第16号(24)被定义为SYSINTR_FIRMWARE         ; If not a device request (and not SYSINTR_RESCHED)                 ldrhsb  r0, [lr, #bResched]             ; (r0) reschedule flag         bhs     %F20                            ; not a device request                 ;PendEvents  EQU 0x340             ; offset 0x10*sizeof(DWORD) of aInfo                             ;device 中断         ldr     r2, [lr, #PendEvents]           ; (r2) pending interrupt event mask         mov     r1, #1         orr     r2, r2, r1, LSL r0              ; (r2) new pending mask         str     r2, [lr, #PendEvents]           ; save it     ;*PendEvents *PendEvents|(1InterruptNO);         ;         ; mark reschedule needed                             ;情况1r0SYSINTR_RESCHED1                             ;情况2: r0 r0-SYSINTR_DEVICESSYSINTR_MAX_DEVICES        10      ldrb    r0, [lr, #bResched]             ; (r0) reschedule flag         orr     r0, r0, #1                      ; set reschedule needed bit         strb    r0, [lr, #bResched]             ; update flag 20      mrs     r1, spsr                        ; (r1) saved status register value         and     r1, r1, #0x1F                   ; (r1) interrupted mode         cmp     r1, #USER_MODE                  ; previously in user mode?         cmpne   r1, #SYSTEM_MODE                ; if not, was it system mode?         cmpeq   r0, #1                          ; user or system: is resched 1         if(SytemMode(spsr)||UserMode(spsr))r0!1) return;         ldmnefd sp!, {r0-r3, r12, pc}^          ; cant reschedule right now so return   *************************************************************************************         sub     lr, lr, #4         ldmfd   sp!, {r0-r3, r12}         stmdb   lr, {r0-r3}         ldmfd   sp!, {r0}         str     r0, [lr]                        ; save resume address         mov     r1, #ID_RESCHEDULE              ; (r1) exception ID         b       CommonHandler         ENTRY_END IRQHandler     将spsr_irq压入IRQ堆栈保存。为调用OEMInterruptHandler作准备。(通常中断处理程序切换入系统态执行的目的在于避免使用终端模式下的寄存器以方便是实现终端套嵌这儿切入系统态时终端使能是关闭的对于模态切换的原因我很迷惑。)OEMInterrupt需要在特权模式下执行所以这里增加了切换入特权(SVC)模式的内容。紧接着将要用与传递参数的寄存器保存。设定传入参数r0就可以开始调用OEMInterruptHandler了这里的调用规则遵循windowsCE的规范而不是ATPCS的规范。具体过程参考ARM Parameter Passingmsdn。下面是函数原形。int OEMInterruptHandler(unsigned int ra);这里传入的参数就是上面的r0事实上r0代表的参数ra并没有实质的作用在这里仅仅是形式上的实现一下而已不过在这儿可以看到这个传入的ra实际上就是被中断的地址如果需要知道被中断的位置可以通过ra来查询而msdn里面说这个参数是保留的。返回的参数也是保存在r0中。其中返回值是系统中断类型。其中SYSINTR_RESCHED为系统时钟中断每次时间片用完该时钟便产生中断并设置kData结构的bResched位进入调度流程。如果中断类型是系统设备中断那就设置PendEvents待再次调度的时候处理中断。所以OEMInterruptHandler必须提前就要对中断进行响应对该中断源设置mask,防止在这过程中同一中断不停发生导致中断饱和影响程序流的执行,直道中断处理真正完成后再次开放该中断的mask。在这里还可以看到的是系统设备中断号的范围是从SYSINTR_DEVICES到SYSINTR_MAX_DEVICES也就是从9-40一共32个设备中断号其中SYSINTR_FIRMWARE为816号这个在编写OAL的中断服务程序时需要注意。如果当前的返回值既不是设备中断号又不是调度中断号,则读出当前调度标示,根据该标示进行判断是否调度/或返回.如果是进入调度流程则恢复初始的寄存器状态,再按CommonHandler的要求保存寄存器。进入CommonHandler等待分发。     2-3 FIQ服务程序         照例看看程序         NESTED_ENTRY FIQHandler         sub     lr, lr, #4                      ; fix return address         stmfd   sp!, {r0-r3, r12, lr}         PROLOG_END         CALL    OEMInterruptHandlerFIQ         ldmfd   sp!, {r0-r3, r12, pc}^          ; restore regs return for NOP         ENTRY_END FIQHandler         LTORG FIQ是arm体系下特有的异常方式其工作过程与IRQ类似都是由外部引脚触发但设计用途不同IRQ用于通常的外部中断源的处理是作为统一、通用的与外部器件交互的手段而IRQ仅仅用于处理周期短同时又需要快速处理的场合其触发的事件源通常也来此外部FIQ中断。如更换电池、数据传输这类工作。可想而知FIQ讲究的是快速精干。因此FIQ服务程序通常没有分发而仅仅是针对单一的工作进行处理保证处理的实时性。因此FIQ的处理相对IRQ就简单很多直接调用 OEMInterruptHandlerFIQ进行处理后返回就完成了整个 FIQ服务程序。 2-4 DataAbort服务程序        由数据异常触发通常有三种指令引发数据异常,这些指令都是访存操作而且都是由MMU的引入后才可能会发生的情况。1.LDR/STR指令.2.SWAP指令。3.LDM/STM指令。而MMU的失效类型又分为4种存储访问失效、地址对齐失效、地址变换失效、域控制器失效、访问控制权限失效.因此当异常发生后,需要通过访问CP15来获知异常的产生具体原因和情况。mfc是微软的asmarm宏汇编器专用的宏指令相当于mcr指令。数据异常和中断模式一样都有可能在互锁时发生所以同样需要对执行互锁的情形进行处理。正常的情况下在保存完相关的寄存器后就会读取CP15的c6,c5,c13三个寄存器。这三个寄存器分别是失效地址寄存器(FAR)、失效状态寄存器(FSR)、进程号寄存器(这个翻译得不好PCP15)然后根据具体的失效类型来进行处理。在ARM处理器中对于CP15有三种地址类型VA,PA,MVA。VA(virtual address)也就是我们通常说的虚拟地址或逻辑地址也就是通过CP15按照PT转换后的地址而PA(physical Address)则是对应于AMBA上的地址对应的是电气介质也就是物理地址。而MVA(Modified virtual address)则是对应于Cache和TLB中转换地址。         NESTED_ENTRY    DataAbortHandler         sub     lr, lr, #8                      ; repair continuation address         stmfd   sp!, {r0-r3, r12, lr}         PROLOG_END sub     r0, lr, #INTERLOCKED_START         cmp     r0, #INTERLOCKED_END-INTERLOCKED_START         bllo    CheckInterlockedRestart         mfc15   r0, c6                          ; (r0) FAR                mfc15   r1, c5                          ; (r1) FSR         mfc15   r2, c13                         ; (r2) process base address                 ;  FARFault address register     ;  CP 15: CRn 6, CRm 0, op_1 0, op_2 0         ;  FSRFault status register         ;  CP 15: CRn 5, CRm 0, op_1 0, op_2 0         ;  PCP15: PID  Process ID register     ;  CP 15: CRn 13, CRm 0, op_1 0, op_2 0                 tst     r0, #0xFE000000                 ; slot 0 reference?         orreq   r0, r0, r2                      ; (r0) process slot based address         and     r1, r1, #0x0D                   ; type of data abort         cmp     r1, #0x05                       ; translation error?         movne   r0, #0         CALLEQ  LoadPageTable                   ; (r0) !0 if entry loaded         tst     r0, r0         ldmnefd sp!, {r0-r3, r12, pc}^          ; restore regs continue         ;*********************************************************************         ldr     lr, KData-4         ldmfd   sp!, {r0-r3, r12}         stmdb   lr, {r0-r3}         ldmfd   sp!, {r0}         str     r0, [lr]                        ; save resume address         mov     r1, #ID_DATA_ABORT              ; (r1) exception ID         b       CommonHandler ENTRY_END DataAbortHandler 在DataAbort发生后c6中的数据保存的就是导致异常的MVA地址通过windowsCE memory layout可以了解到当前进程的运行空间是在slot0也就是0x0-0x1fffffff的位置事实上这个slot上的数据仅仅是实际进程的一个副本所以如果数据异常发生在slot0就需要去找到进程所在的实际slot的存放地址然后尝试将内核的页表复制到硬件实际使用的页表以达到恢复的目的。如果复制动作成功则返回否则进入异常分发程序CommonHandler。 2-5 PrefetchAbort服务程序    对于ARM处理器来说由于其内部使用了哈佛结构---独立的数据的指令总线因此在数据/指令的读取过程中产生的异常也就很自然地可以区分开来本质上而言这些异常都是同属于存储访问失败产生的异常因此这些异常都由MMU相关在ARM手册中DataAbort和PrefetchAbort都称为Memory abort。Prefetch也就是在预取指令的动作后产生的当处理器运行到这个无效的指令时(这个无效与undefined exception中的不可识别不同是指不存在或是无法得到)就触发该异常。所以不是所有的指令无效都产生异常例如一个分支程序指向一个不可访问的区域而之前的分支指向另一个可访问区域时。后一个区域尽管预取无效但是由于该分支并不执行所以并不产生异常。所以prefetch的准确定义应该是prefetch and executes Abort:).在ARMV5指令集中BKPT也可以产生预取无效但由于这儿的ARM通常都是ARM9的也就是使用ARMV4指令所以不讨论BKPT的情形。由于数据异常和指令异常同属存储异常而且两个异常不可能会相互中断所以在ARM的设计上这两个异常使用同一组寄存器abort组。   ALTERNATE_ENTRY PrefetchAbort sub     lr, lr, #0xF0000004  ;考察产生异常的地址是否在0xf0000000-0xf0010400           cmp     lr, #0x00010400    ;之间,如果是进入系统调用处理         bhs     ProcessPrefAbort      ;-正常的预取异常 执行ProcessPrefAbort     ...       ProcessPrefAbort         add     lr, lr, #0xF0000000             ; repair continuation address         stmfd   sp!, {r0-r3, r12, lr}           mov     r0, lr                          ; (r0) faulting address         mfc15   r2, c13                         ; (r2) process base address         tst     r0, #0xFE000000                 ; slot 0 reference?         orreq   r0, r0, r2                      ; (r0) process slot based address         CALL    LoadPageTable                   ; (r0) !0 if entry loaded         tst     r0, r0         ldmnefd sp!, {r0-r3, r12, pc}^          ; restore regs continue         ldmfd   sp!, {r0-r3, r12}         ldr     lr, KData-4         stmdb   lr, {r0-r3}         ldmfd   sp!, {r0}         str     r0, [lr]                        ; save resume address         mov     r1, #ID_PREFETCH_ABORT          ; (r1) exception ID         b       CommonHandler 下面来结合windowsCE的情形。PrefetchAbort就是该服务程序的入口在程序的一开始将lr也就是产生异常的地址4(流水线导致)的地址减掉0xf000 0004并比较是否在0-0x10400之间这是为什么呢原来windowsCE除了使用PrefetchAbort服务程序作为正常的异常处理以外还使用这个异常作为系统调用的手段。通过0xf0000000-0xf0010400这段地址的预取异常来进行系统调用。我们下面看处理预取失败的情况绕开系统调用的先不管。也就是ProcessPrefAbort的分支。 这个分支的内容就与上面DataAbort的内容一样了我就不再重复了。  2-6异常分发 CommonHandler 到此为止我们已经了解了windowsCE对各个异常/中断模式下的处理情况已经基本做了一个了解但是仍然有一些情况是送到CommonHandler来处理的下面就对这个分发程序进行分析完整windowsCE对整个异常流程的处理。           ALTERNATE_ENTRY CommonHandler         mrs     r2, spsr         msr     cpsr_c, #SVC_MODE:OR:0x80       ; switch to Supervisor mode w/IRQs disabled         ldr     r3, KData                      ; (r3) ptr to KData page 在CommonHandler开始系统就转入Supervisor态来执行。      ; Save the processor state into a thread structure. If the previous state was ; User or System and the kernel isnt busy, then save the state into the current ; thread. Otherwise, create a temporary thread structure on the kernel stack. ; ;       (r1) exception ID ;       (r2) SPSR ;       (r3) ptr to KData page ;       Interrupted r0-r3, and Pc saved at (r3-0x14) ;       In Supervisor Mode.         ALTERNATE_ENTRY SaveAndReschedule and     r0, r2, #0x1f                   ; (r0) previous mode         cmp     r0, #USER_MODE                  ; Z set if from user mode         cmpne   r0, #SYSTEM_MODE                ; Z set if from System mode         bne     %F50                            ; reentering kernel, save state on stack                         ; 现场保护分支                         发生异常前模态是否是用户态和系统态。FIQ/IRQ/SVC/Abort/Undef         ldr     r0, [r3,#pCurThd]               ; (r0) ptr to current thread                             ; r0 kDatapCurThd                                   add     r0, r0, #TcxR4                  ; (r0) ptr to r4 save                             ; r0 kDatapCurThdTcxR4                             ;THREAD_CONTEXT_OFFSET后的0x44bytes用于备份寄存器的内容         stmia   r0, {r4-r14}^                   ; save User bank registers                         ****************************************************         ; Save registers for fault from a non-preemptible state. 50      sub     sp, sp, #TcxSizeof              ; allocate space for temp. thread structure         cmp     r0, #SVC_MODE         bne     %F55                            ; must mode switch to save state         add     r0, sp, #TcxR4                  ; (r0) ptr to r4 save area         stmia   r0, {r4-r14}                    ; save SVC state registers         add     r4, sp, #TcxSizeof              ; (r4) old SVC stack pointer         str     r4, [r0, #TcxSp-TcxR4]          ; update stack pointer value         b       %B10 55         msr     cpsr, r2                        ; switch to mode exception came from add     r0, sp, #TcxR4                  ; (r0) ptr to r4 save area         stmia   r0, {r4-r14}                    ; save modes register state         msr     cpsr_c, #SVC_MODE:OR:0x80       ; back to supervisor mode         b       %B10                            ; go save remaining state 在进行统一的处理之前需要保存前态寄存器组的状态以便后面恢复在用户态和系统态的情况下直接保存用户态的寄存器。同时上面可以看到到达50的条件是前一状态为FIQ/IRQ/SVC/Abort/Undef也就是说为异常套嵌的情况系统套嵌的情形前面已经处理过了。这里首先处理的是SVC下被套嵌的情形上面可以看到SVC模式都是用于异常/中断后的具体事件处理(eg: HandleException)所以这个流程并不是独立存在的因此当前寄存器就是前态寄存器所以到这里需要重新计算stack指针的位置。而另外的FIQ/IRQ/Abort/Undef模式下的寄存器的保存则需要切换当前状态来进行所以在进入真正的处理程序之前需要不同的分支来保存前态寄存器状态。可为什么前后都看不到System模式下的寄存器保存呢这是因为系统态和用户态使用同一组寄存器所以保存用户态寄存器组就达到了现场保护了。这种设计完全是因为ARM分组寄存器的架构决定的所以需要不同的处理。通过上面的处理所有的情况都已经统一的完成了现场保护的动作下面就需要进一步处理这些异常了。 10      ldmdb   r3, {r3-r7}                     ; load saved r0-r3 Pc                         ;KData之前的16byte用作传递参数用                         ;所以每个异常句柄最后都由将r0-r3和PC送到这个位置。                        stmdb   r0!, {r2-r6}                    ; save Psr, r0-r3         sub     r0, r0, #THREAD_CONTEXT_OFFSET  ; (r0) ptr to Thread struct         str     r7, [r0,#TcxPc]                 ; save Pc         mfc15   r2, c6                          ; (r2) fault address         mfc15   r3, c5                          ; (r3) fault status     ;r0Kdata     ;r1exception ID     ;r2FAR     ;r3FSR    ; Process an exception or reschedule request. FirstSchedule 20      msr     cpsr_c, #SVC_MODE               ; enable interrupts CALL    HandleException         ldr     r2, [r0, #TcxPsr]               ; (r2) target status         and     r1, r2, #0x1f                   ; (r1) target mode         cmp     r1, #USER_MODE         cmpne   r1, #SYSTEM_MODE         bne     %F30                            ; not going back to user or system mode         ;System mode and user mode branch         add     r0, r0, #TcxR3         ldmia   r0, {r3-r14}^                   ; reload user/system mode registers         ldr     r1, KData         msr     cpsr_c, #SVC_MODE:OR:0x80       ; disable all interrupts         ldrb    r1, [r1, #bResched]             ; (r1) nest level reschedule flag         cmp     r1, #1         mov     r1, #ID_RESCHEDULE         beq     %B20                            ; interrupted, reschedule again         msr     spsr, r2         ldr     lr, [r0, #TcxPc-TcxR3]         ldmdb   r0, {r0-r2}         movs    pc, lr                          ; return to user or system mode HandleException是实际进行异常处理的函数针对上面没有处理完的异常进一步分析并进行处理。这个函数是没有公开代码的所以没有办法进一步深入下去。由于处理的异常类型比较多所以这个异常处理函数的代码量是相当大的因此会耗费相对比较多的时钟周期在之前的代码中我们都是在关闭中断的情况下进行异常处理如果在这里还不打开中断的话整个异常处理过程会相当的长这样会很大程度上影响系统的实时性所以在这里调用HandleException之前是将中断重新打开的待到处理完成再将中断关闭。对于这些异常如果不能处理就只有两种情况1.结束该进程/线程。2.挂起系统.第二种情况下挂起系统HandleException是不会返回的。因此只有异常处理正常流程和结束线程的可能。对于返回的情况这个时候如果返回触发异常的地址继续运行的话仍然会导致异常所以结束进程/线程都需要重新调度才能完成了。对于异常处理成功的情形就不必调度了直接就可以返回产生异常的地方继续执行。在这里还要考虑套嵌(这里仅仅是指系统模式和兼管模式的异常套嵌)的情形也就是中断/异常已经进入调度状态又再次产生中断/异常这个时候就强行取消上一次调度进而重新调度.这用于调度过程中遇到异常恢复和剥夺的情况如果不属于这种情况的话就直接恢复寄存器状态并且返回中断点继续执行。 ; Return to a non-preemptible privileged mode. ; ;       (r0) ptr to THREAD structure ;       (r2) target mode 30    msr     cpsr, r2                        ; switch to target mode         add     r0, r0, #TcxR0         ldmia   r0, {r0-r15}                    ; reload all registers return 通过HandleException处理以后已经完成了所有异常的处理所以这里只是考虑反回的情况,由于这里不包含用户模式下的处理所以这里处理的都是特权模式完全可以访问kdata区域这里就直接利用Kdata区域中的线程备份来完成恢复寄存器和返回。
http://www.pierceye.com/news/987123/

相关文章:

  • 做网站可以不做后端吗渭南网站建设网站排名优化
  • 在线建站网页制作网站建设平台工商营业执照官网
  • 做网站用到的软件h5交互设计
  • 化工废料网站建设企业网站建设联系电话
  • 浙江高端网站建设公司什么是网页开发
  • 石碣网站仿做模具做外贸网站
  • 定制网站建设成本制作公司宣传片
  • 青岛低价网站建设达内it教育官网
  • 洛阳设计网站公司个人网站管理系统
  • 怎么可以预览自己做的网站天津市城乡建设网站
  • 本地网站开发宁夏建设工程招标投标信息网站
  • 网站建设服务费怎么记账维护一个网站一年多少钱
  • 电子商务网站建设定位设想我的网站为什么打不开
  • 旅游网站开发方案ppt移动商城积分和积分区别
  • 如何做网站推广自己的产品WordPress+百度+主动
  • 商丘网站建设推广公司赣州seo唐三
  • 产品网站设计计算机专业做网站运营
  • 做平台网站怎么做的wordpress获取当前分类下的子分类
  • 广州网站建设性价比长安高端装备网站设计公司
  • 电子商务网站推广计划沈阳建设工程造价
  • 网站备案接入商是什么网站语言版本
  • 个人做网站做什么样的话网站站点连接不安全
  • 响应式网站 外贸平顶山 网站设计
  • 手袋 东莞网站建设成都哪里好玩适合情侣
  • 苏州哪个公司做门户网站给学校建网站那个系统好
  • 现在网站都是拿什么软件做的wordpress 自动alt
  • 山东省住房和城乡建设部网站首页网站中的自助报价系统
  • 如何 网站收录软件开发大概需要多少钱
  • 网站建设微信端简洁型网页
  • 一般的网站开发语言用什么《网站开发实践》 实训报告