windowsCE异常和中断服务程序初探(-)

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中LR=LR-4,DataAbort下LR=LR-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_KPAGE+0x380 
    ;INTERLOCKED_END EQU USER_KPAGE+0x400 
        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. It's 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 OEM's interrupt handler code. It is up to them to 
        ; enable interrupts if they so desire. We can't do it for them since 
        ; there's only on interrupt and they haven't 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|(1<<InterruptNO); 
        ; 
        ; mark reschedule needed 
                            ;情况1:r0=SYSINTR_RESCHED=1 
                            ;情况2: r0 =r0-SYSINTR_DEVICES>=SYSINTR_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}^          ; can't 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 Passing@msdn。下面是函数原形。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为8+16号,这个在编写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服务程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windowsCE异常和中断服务程序初探(=)

继续上次的内容&#xff0c;在上次的分析中我们已经对SWI,FIQ,IRQ的流程有了一个大概的认识&#xff0c;下面继续对DataAbort和PrefetchAbort以及公共分发程序CommonHandler进行一下认识&#xff0c;完整异常处理的流程。 2-4 DataAbort服务程序 由数据异常触发&…

【转】Linux中tty、pty和pts概念及区别

转自&#xff1a;Linux中tty、pty和pts概念及区别 - 知乎 基本概念 ①tty(终端设备的统称): tty一词源于Teletypes&#xff0c;或者teletypewriters&#xff0c;原来指的是电传打字机&#xff0c;是一种通过串行线连接键盘和打印机进行发送、阅读信息的设备&#xff0c;后来…

Microsoft Jet SQL 参考在线手册

http://www.weste.net/book/sql/转载于:https://www.cnblogs.com/cwfsoft/archive/2010/06/19/1760961.html

Windows CE下驱动程序开发基础

我想即使读者看过微软的关于驱动开发的培训教材和CE帮助文档中的驱动部分&#xff0c;头脑中仍然一片茫然。要想真正了解驱动程序必须结合一些驱动程序源码&#xff0c;在此我以串口驱动程序&#xff08;COM16550&#xff09;中初始化过程为线索简单讲一讲驱动开发的基础知识。…

【转】高端球管使用了哪些高科技?

转自&#xff1a;高端球管使用了哪些高科技&#xff1f; 本文来源&#xff1a;第三方维修平台 本文作者&#xff1a;RepairCT 随着人类发现X射线&#xff0c;这项技术不断应用到医学领域&#xff0c;比如X光机、DR、CT、乳腺钼靶等医疗设备&#xff0c;它们的主要核心均是利用…

关于代码组织的一些看法(上)

今天看了一个篇关于架构的文章&#xff0c;略有所感&#xff0c;记录一下。 软件的架构基本是从一个原始需求出发&#xff0c;逐步构建可维护、更灵活的开发框架的过程&#xff0c;在这个构建过程中可能会逐渐的增加代码的复杂度来满足灵活性的要求&#xff0c;从这个层面来讲&…

CE下基于Zylonite硬件平台的SD卡驱动开发

摘要&#xff1a;本文结合实际项目&#xff08;一款以WINCE为操作系统内核的GSM/PHS双模智能手机&#xff09;对嵌入式系统Windows CE5.0的底层驱动&#xff08;SD卡&#xff09;的架构进行了分析和研究&#xff0c;以MARVELL公司提供的基于INTEL Zylonite硬件平台的BSP为基础&…

【转】svn详解

转自&#xff1a;svn status详解 - 世界&#xff0c;太精彩 - 博客园 svn 是在提交前查看本地文本和版本库里面的文件的区别。返回值有许多种具体含义如下&#xff1a; L abc.c # svn已经在.svn目录锁定了abc.c M bar.c # bar.c的内…

outofmemory异常如何解决?

一年多来打交道最多的就是WinForm&#xff0c;界面设计确实比MFC容易多了&#xff0c;但是问题出的也更隐晦&#xff0c;要想完全解决还是离不开框架底层的知识。 现在又遇到了一个麻烦的问题&#xff1a;切换界面时&#xff0c;有时GroupBox&#xff08;里面嵌有ListView&…

pthread-win32在VC2005下的使用

pthread-win32是一个在Win32环境下的Unix POSIX线程库的移植. 有了它, 可以比较方便的移植Unix/Linux多线程程序到Windows下. 在VC2005下使用也很简单: 下载, 地址是 http://sourceware.org/pthreads-win32 里面include目录中是头文件, lib目录中是.lib和.dll文件. 在VC项目的属…

【转】apt命令

转自&#xff1a;apt命令详解 - 简书 apt命令可以说是Ubuntu系统下最为重要的命令&#xff0c;安装、更新、卸载软件&#xff0c;升级系统内核都离不开apt命令。 一、apt的简介 apt的全称是Advanced Packaging Tool是Linux系统下的一款安装包管理工具。 最初的时候&#xff…

asp.net 之高速缓存

一、输出高速缓存 页面顶部插入&#xff1a; <% OutputCache Duration"60" VaryByParam"None" %> <% OutputCache Duration"60" VaryByParam"id;page" %> 二、部分页面高速缓存 (UserControl) <% OutputCache Durati…

【转】在 Bash 中使用 -exec 选项和 find 命令搜索文件

转自&#xff1a;https://www.delftstack.com/zh/howto/linux/linux-find-exec/ 我们可以使用带有 -exec 选项的 find 命令来查找包含我们要搜索的文本的文件。 主要概念是使用 find 命令获取工作目录中的每个文件&#xff0c;并执行 grep 命令查找每个文件中的文本。 例子&…

SQL Server 相关create操作语句

创建数据库&#xff1a; create database jylton (namejylt,filenamee:\db\jylt.mdf,size4,filegrowth100%,maxsize1024 )log on(namejylt_log,filenamee:\db\jylt_log.ldf,size4,filegrowth100%)go 1&#xff0c;增&#xff1a;insert into t_user values(wangpeng,19);s 2&a…

【转】svn st 状态详解

转自&#xff1a;svn st 状态详解 - 小小平凡世界 - 博客园 svn st status (stat, st): 显示工作副本中目录与文件的状态。 用法: status [PATH...] 未指定参数时&#xff0c;只显示本地修改的条目(没有网络访问)。 使用 -q 时&#xff0c;只显示本地修改条目的摘要信息。…

linux C之access函数

access()&#xff1a;判断是否具有存取文件的权限 相关函数 stat&#xff0c;open&#xff0c;chmod&#xff0c;chown&#xff0c;setuid&#xff0c;setgid 表头文件 #include<unistd.h> 定义函数 int access(const char * pathname, int mode); 函数说明…

gridview 强制过长数据进行换行

有时候设置gridview的列宽后&#xff0c;因为该列的内容为连续的数字或字母&#xff0c;不会自动换行。导致列宽不可控&#xff0c;可以通过以下方法设置列宽强制换行在绑定数据前添加一行 gv.Attributes.Add("style", "word-break:break-all;word-wrap:brea…

【转】string,wstring,cout,wcout 与中文字符的输入输出

转自&#xff1a;string,wstring,cout,wcout 与中文字符的输入输出 首先说明是什么string与wstring 在C标准里定义了两个字符串string和wstring typedef basic_string<char> string; typedef basic_string<wchar_t> wstring; 前者string是常用类型&#xff…

autoconf常用宏

AC_INIT (unique-file-in-source-dir)处理所有命令行参数并且寻找源代码目录。unique-file-in-source-dir是一些在包的源代码目录中文件&#xff1b; configure在目录中检查这些文件是否存在以确定该目录是否包含源代码。人们可能偶尔会用--srcdir给出错误的目录&#xff1b;这…

maple 2018 窗口关闭提示乱码_如果解决SOLIDWORKS工程图转CAD字体出现乱码的问题_SolidWorks生信科技...

操作SOLIDWORKS工程图转CAD时&#xff0c;由于SOLIDWORKS使用的是Windows字体&#xff0c;而CAD使用的是线性字体&#xff0c;字体就容易出现乱码的苦恼。一般出现乱码是因为字体映射里面没有中文&#xff0c;所以会导致乱码。遇到这种情况&#xff0c;只需找到字体映射文件&am…