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

继续上次的内容,在上次的分析中我们已经对SWI,FIQ,IRQ的流程有了一个大概的认识,下面继续对DataAbort和PrefetchAbort以及公共分发程序CommonHandler进行一下认识,完整异常处理的流程。 

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 
        
        ;  FAR=Fault address register 
    ;  CP = 15: CRn = 6, CRm = 0, op_1 = 0, op_2 = 0 
        ;  FSR=Fault 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 isn't 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 =kData+pCurThd                           
        add     r0, r0, #TcxR4                  ; (r0) = ptr to r4 save 
                            ; r0 =kData+pCurThd+TcxR4 
                            ;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 mode's 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 
    ;r0=&Kdata 
    ;r1=exception ID 
    ;r2=FAR 
    ;r3=FSR    
; 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.mzph.cn/news/435540.shtml

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

相关文章

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

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

Microsoft Jet SQL 参考在线手册

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

Windows CE下驱动程序开发基础

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

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

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

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

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

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

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

【转】svn详解

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

outofmemory异常如何解决?

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

pthread-win32在VC2005下的使用

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

【转】apt命令

转自:apt命令详解 - 简书 apt命令可以说是Ubuntu系统下最为重要的命令,安装、更新、卸载软件,升级系统内核都离不开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…

解决firefox不能安装Flash插件

当你在浏览一个含有Flash的网页的时候&#xff0c;Firefox会提醒你正常浏览网页需要安装缺少的插件&#xff08;这个提醒通常在地址栏下方和Flash的占位区上&#xff09;&#xff0c;按照他的提示安装Flash插件即可。 另外你也可以手动安装&#xff0c;在Windows下, 可以在这里…