NXP

PowerPC基于vxWorks的中断初始化分析

2019-07-12 12:26发布

1. 本文简介

      本文主要介绍P2020芯片中vxWorks中断初始化过程(部分讲解是以linux为例)。P2020属于PPC85XX系列,内核为e500v2,它是PowerPC体系结构中主要应用于通信领域的片子,PowerPC体系结构规范发布于1993年,它是一个64位规范(也包含32位子集)。但几乎所有常规的PowerPC的芯片都是32位的,除了部分新型高端芯片(eg:IBM RS/6000等)。       本文主要章节如下:        2 参考书籍介绍        3 OEA相关寄存器(中断相关)        4 PowerPC架构异常处理机制(P2020为代表)          5 vxWorks中断初始化过程        6 总结

 2.参考书籍

      (1) IBM官方文档,关于PowerPC Architecture Boook I II III ,其中Book III 主要讲解与操作系统相关的寄存器。             下载链接: https://www.ibm.com/developerworks/systems/library/es-archguide-v2.html.              (2)  <> 该手册描述的是e500核的工作过程以及Reg详细描述,包括电源管理,中断处理,Cache,MMU.        (3)  <> 该手册主要描述的是芯片与外设相关的控制器,但很少介绍到CPU通用寄存器,特殊寄存器等.        (4)  <<821INSTSET.pdf>> PowerPC 汇编指令集介绍        (5)   PowerPC 汇编指令简单介绍     (2.3.4)都可以在NXP官网中下载

 3 OEA相关寄存器(中断相关)

     PowerPC 处理器有 32 个(32 位或 64 位)GPR(通用寄存器)以及诸如 PC(程序计数器,也称为 IAR/指令地址寄存器 或 NIP/下一指令指针)、LR(链接寄存器)、CR(条件寄存器)等各种其它寄存器。有些 PowerPC CPU 还有32个64位的FPR(浮点寄存器). 下图展示了Power ISA2.04寄存器模式,且值得注意的是 PowerPC有两种执行模式,分别为用户模式(UserMode) 和特权模式(SupervisorMode),MSR[PR]=0 表示特权模式。Linux内核运行在特权模式,而普通程序运行在用户模式。VxWorks全部运行在特权模式。    3.1 OEA寄存器集包括四类寄存器(具体介绍只涉及中断相关的,其它请参考下来的链接)     本小章节参考:32位PowerPC构架通用寄存器分析及总结     (1)配置寄存器(Configuration Registers)              MSR寄存器:(与中断息息相关)              定义处理器的状态,它可以被mtmsr, sc, rfi指令修改;可以被mfmsr读取; 详细说明:基于603E内核的PowerPC处理器,中断向量为一个固定的地址,可以通过设置MSR[IP]位来决定这个固定地址是0x0,还是0xfff0_0000;而E500内核在进入中断和异常处理程序时,不能关闭MMU,因此不能使用物理地址作为中断向量,而应使用IVPR和IVOR寄存器保存相应的中断向量(在下面中断机制章节详细介绍),下面为e500核的MSR:      中断的开关由寄存器MSR来控制的
     CE:if set 1,Critical input and watchdog timer interrupts are enabled.
     EE:if set 1,External input, decrementer, fixed-interval timer and performance monitor interrupts are enabled
     ME:if set 1, Machine check interrupts are enabled.
     DE:if set 1,Debug interrputs are enabled if DBCR0[IDM] = 1.

    MSR[EE]这个bit很重要,中断的使能要靠它。
    注意:当发生中断后,MSR[EE]会自动置0屏蔽所有其他的中。
      如果在MSR[EE]置1前,又来了一个中断
           1.此中断是边沿触发的,那么此中断丢失。此种中断就是电平变化,一次就没了
           2.此中断时水平触发的,此中断不会丢失。此种中断的电平会一直active,直到硬件处理它              PVR寄存器:               定义寄存器模型的版本和处理器的版  (2)内存管理寄存器(Memory Management Registers)              BAT寄存器:             OEA定义了四组BAT指令寄存器(IBAT0U-IBAT3U和IBAT0L-IBAT3L),也定义了四组BAT数据寄存器(DBAT0U-DBAT3U和DBAT0U-DBAT3U             SDR1寄存器             该寄存器定义了用于虚拟地址转换为物理地址所需要的页表基地址             SR寄存器:             OEA定义了16个32位的SR寄存器(SR0-SR15  (3)中断处理寄存器(Interrupt Handing Register)         详细介绍请看《E500CORE.pdf》2.7 Interrupt Registers  (4)多功能寄存器(Miscellaneous Registers)        TB(time base)寄存器:CPU时间片基准        DEC寄存器:这是一个32位的递减计数器        EAR(External Access Register)寄存器:用于访问外部设备        DABR(Data address breakpoint register):用来控制数据地址断点功能        PIR(Processor identification register):在多处理器的芯片上用来标识一个核,例如在MPC8641d芯片上有两个E600的core,就用PIR来定位其中的core。    3.3 通用寄存器与专用寄存器的用途    本小章节参考:PowerPC汇编指令以及通用与专用寄存器介绍    r3,r4-r10经常用于C,汇编的混合编程中 在targetharchppc oolPpc.h中有对以上寄存器的重定义

 

 4 PowerPC架构异常处理机制(P2020为代表)     

      4.1 PowerPC中断系统(P2020)          从CPU的角度来讲,中断源可以分为自己内核产生的异常和PIC提供的中断。          异常:是e500核产生的,它是同步产生(可以预知的),如非法指令,或访问存储器时出现TLB Miss(Data | Instruction )等.          <>5.11.1描述了PowerPC架构可能出现的全部异常(这里描述包括中断)           中断:是e500核外部引脚产生的,由PIC送到内核处理,它是异步产生的(无法预知的).大致分为一般中断(int)(包括内外部等),关键中断(cint)和机器检查中断(machine check). 下图为中断源架构图,其中Message数量应该是写错了(理论为4).          从图中可以看出PowerPC处理器中断系统由内核中断以及异常处理系统和PIC中断控制器构成.              4.2 中断向量        在E500内核中,使用IVPR和IVORx寄存器共同确定中断或者异常程序的入口地址。其中,IVPR寄存器提供中断程序入口地址的第0~15位,IVORx提供中断程序入口地址的第16~27位,而中断程序的入口地址的第28~31位为0。IVORx与异常的对应关系如下图所示:
       每类中断都有自己的中断向量,通过它能计算出中断handler的指令地址。
       指令地址的计算方法:
        IVPR[32-47] || IVORn[48-59] || 0b0000
       这样就得到一个32个bit地址 有2个中断向量对程序员来说比较亲切:
    一个是 IVOR4 用来处理外部中断和内部SOC中断
    一个是 IVOR8 用来处理系统调用

随便找一个Start.S进行简单的分析
    185 /* Setup interrupt vectors 设置IVPR寄存器*/
    186 lis r1,TEXT_BASE@h   /* load value to r1 */
    187 mtspr IVPR, r1  /* write r1 to IVPR */
    197 li r1,0x0500
    198 mtspr IVOR4,r1 /* 4: External interrupt */
     .......
    205 li r1,0x0900
    206 mtspr IVOR8,r1 /* 8: System call */
    207 /* 9: Auxiliary processor unavailable(unsupported) */
    208 li r1,0x0a00
    209 mtspr IVOR10,r1 /* 10: Decrementer */
    ......
看board/pq37pc/pq37pc_8560/config.mk 里有 
     TEXT_BASE = 0xFF800000
     所以 IVPR   = 0xFFF80000
     IVOR10 = 0x00000a00
     计算 IVPR[32-47] || IVPOR10[48-59] || 0b0000  得 0xFFF80a00 4.3 中断源寄存器  中断向量只能确定类型,里面保存了interrupt handler的地址。
 在interrupt handler里,需要根据中断源寄存器来进一步确定到底是哪里发生了中断
 E500内部中断源有64个(部分reserve),来自TSEC,LBC,DMA,CPM等  寄存器组 PIC_IIVPRn 与 P2020内部SOC中断一一对应(n取值 0~63)     E500外部中断源有12个,来自外部引脚 IRQ[0:11]
 寄存器组 EIVPRn 与 MPC8560 外部中断一一对应(n取值 0~11) 下面具体介绍外部源寄存器    MSK:  若置1,此中断源的中断被无视.
   A:    若置1,此中断源有中断发生
   P:    若置1, active-high; 若置0, active-low.
   S:    若置1,此中断是水平触发。若置0,此中断是边界触发
   PRIORITY: 优先级0-15。15是最高优先级,0时相当于无视此中断。
   VECTOR: 硬件中断号。中断发生后处于pengding时,此字段被写在寄存器IACK中   总结:处理内,外中断的handle都是同一个functions(流程),EntInt-->Handle-->ExitInt,在处理函数中读取IACK,就知道是哪个中断源触发了中断,然后做对应的处理 知道中断向量 和 中断源,系统处理中断的大致流程就能理出来了,以外部中断eg: 4.4 外部中断处理流程      1.首先E500内核清除在指令完成队列CQ中所有的执行,然后把正在执行的指令序列下一条指令地址保存到中断寄存器                     SRR0(Save/RestoreRegiser 0)      2.把当前 MSR 的内容保存到 SRR1      3.把 MSR 某些比特置为 0,如MSR[SPE,WE,EE,PR,FP,FE0,FE1,IS,DS]are 0 by all interrupts.    (E500内核将MSR寄存器的CE、ME、DE位保留,其他位全部清零。因此E500内核在进行外部中断处理程序时,仍然可以被Critical中断,Machine check中断和调试中断程序重入,但是不能被外部中断立即重入。在Linux PowerPC中,外部中断处理程序会选择合适时机使能MSR寄存器的EE位,以支持外部中断的重入)      4.在新的 MSR 状态下, E500内核将根据IVPR,IVOR4寄存器确定中断向量,从中断向量偏移处开始指令读取和执行     5. 在中断处理程序执行完毕后,使用rfi指令进行中断返回。rfi指令将从SRR1寄存器中恢复MSR寄存器的值,并从SRR0寄存器中获得程序返回地址。rfi指令在进行程序正文切换之前还会进行指令和数据的同步,还给被中断的程序一个“干净”的空间,之后E500内核进行中断返回。  

5.vxWorks中断初始化过程(跳过bootrom过程)

    usrInit(prjConfig.c)--> {sysStart(startType)-->intVecBaseSet ((FUNCPTR *) VEC_BASE_ADRS)}      -->excVecInit()  (1)sysStart (first C code executed from usrInit) 主要作用是清除BSS,以及设置中断向量的基地址 Code in argetconfigcompssrcusrStartup.c 中断向量的基地址一般设置为0x0000_0000 | 0xfff0_00000 macro in BSP/config.h #define VEC_BASE_ADRS LOCAL_MEM_LOCAL_ADRS #define LOCAL_MEM_LOCAL_ADRS 0x00000000 void sysStart(int startType){ #if (CPU_FAMILY == PPC) || (CPU_FAMILY == MIPS) /* * For PPC and MIPS, the call to vxSdaInit() must be the first operation * in sysStart(). This is because vxSdaInit() sets the SDA registers * (r2 and r13 on PPC, gp on MIPS) to the SDA base values. No C code * must be placed before this call. */ _WRS_ASM (""); /* code barrier to prevent compiler moving vxSdaInit() */ vxSdaInit (); /* this MUST be the first operation in usrInit() for PPC */ _WRS_ASM (""); /* code barrier to prevent compiler moving vxSdaInit() */ #endif /* (CPU_FAMILY == PPC) || (CPU_FAMILY == MIPS) */ ... #ifdef CLEAR_BSS bzero (edata, end - edata); #endif /* CLEAR_BSS */ sysStartType = startType; intVecBaseSet ((FUNCPTR *) VEC_BASE_ADRS); ... #ifdef _WRS_CONFIG_USE_MEMDESC sysMemDescInit (); #endif }    (2) intVecBaseSet Code in targetsrcarchppcintArchLib.c 说明:此阶段函数并未真正设置中断向量基地址到e500内核中,只是对_ppcExcIntVecBase赋值的 过程,实际设置的过程在excVecInit里面。 int (* _func_intLevelSetRtn) (int) = NULL; int (* _func_intEnableRtn) (int) = NULL; int (* _func_intDisableRtn) (int) = NULL; 上面的函数指针初始化在vxbEpicIntCtlr.c里面 int intEnable ( int intLevel /* interrupt level to enable */ ) { /* execute VxBus Legacy interrupt enable routine first if supported */ if ((_func_vxbIntEnable != NULL) && (_func_vxbIntEnable (intLevel) != ERROR)) return (OK); if (_func_intEnableRtn != NULL) return (_func_intEnableRtn (intLevel)); return (ERROR); } void intVecBaseSet(FUNCPTR * baseAddr){ /* 主要_func_intVecBaseSetRtn实际为空,在vxWorks目前阶段函数指针未赋值 ** 可在vxWorks shell 中 _func_intVecBaseSetRtn == 1 测试返回值 */ if (_func_intVecBaseSetRtn != NULL) _func_intVecBaseSetRtn (baseAddr); _ppcExcIntVecBase = baseAddr; _ppcAllocationQuantumSize = _CPU_ALLOC_ALIGN_SIZE; _ppcStackAlignSize = _CPU_STACK_ALIGN_SIZE; ... } FUNCPTR * intVecBaseGet (void) { if (_func_intVecBaseGetRtn == NULL) return (_ppcExcIntVecBase); return (_func_intVecBaseGetRtn ()); } (3)excVecInit Code in targetsrcarchppcexcArchLib.c STATUS excVecInit (void) { FAST int ix; #if !defined(_WRS_CONFIG_WRHV_GUEST) || defined(_VB_PISA_EHV) if (excExtendedVectors == TRUE) { entOffset = EXT_ENT_OFF; isrOffset = EXT_ISR_OFF; exitOffset = EXT_EXIT_OFF; #ifdef _EXC_OFF_CRTL ... #endif /* _EXC_OFF_CRTL */ } else { ... } excVecBaseSet(intVecBaseGet()); for (ix = 0; excBlTbl[ix].excHandler != (void (*)()) NULL; ix++) { excVecConnectCommon (excBlTbl[ix].vecOff, excBlTbl[ix].vType, excBlTbl[ix].excHandler, excBlTbl[ix].vecOffReloc); } #ifndef _WRS_CONFIG_WRHV_GUEST #ifdef IVOR0 excIvorInit(); #endif /* IVOR0 */ #endif /* _WRS_CONFIG_WRHV_GUEST */ ... /* * Now that the vectors are set up, and provided we can safely do * so prior to MMU setup, set the recoverability indicator if so * equipped. (If excVecBase and excVecBaseAltAdrs differ, * no exceptions can be handled until the MMU has been set up.) * We don't enable Machine Check exceptions here because excHandler * is not ready, i.e. taskIdCurrent is a meaningless value now. * We postpone it to usrRoot and use taskMsrDefault to enable it. */ if (excVecBaseAltAdrs == excVecBase) vxMsrSet (vxMsrGet() #ifdef _PPC_MSR_RI | _PPC_MSR_RI #endif /* _PPC_MSR_RI */ ); #ifndef _WRS_CONFIG_WRHV_GUEST /* Used for the generic layered exception handler */ hdlrBase = excVecBase + _EXC_OFF_END; /* save the Data and/or Instruction MMU selected */ hdlrCodeBase = excVecBaseAltAdrs + _EXC_OFF_END; #if (CPU==PPC85XX) # if !defined(PPC_e200) && !defined(PPC_e500mc) || defined(PPC_e6500) installE500ParityErrorRecovery(); # endif /* !PPC_e200 && !PPC_e500mc || PPC_e6500 */ #endif /* (CPU==PPC85XX) */ #endif /* _WRS_CONFIG_WRHV_GUEST */ #else /* _WRS_CONFIG_WRHV_GUEST && !_VB_PISA_EHV */ { char * addr; int excSize = (int)&_func_exc_handler_end - (int)&_func_exc_handler; int intSize = (int)&_func_int_handler_end - (int)&_func_int_handler; bzero ((void *)0, _EXC_OFF_END); for (addr = 0; addr < (char *)_EXC_OFF_END; addr+=0x100) { bcopy ((void *)&_func_exc_handler, (void *)addr, excSize); CACHE_TEXT_UPDATE ((void *)addr, excSize); } /* Set interrupt handlers */ bcopy ((void *)&_func_int_handler, (void *)_EXC_OFF_INTR, intSize); CACHE_TEXT_UPDATE ((void *)_EXC_OFF_INTR, intSize); #ifdef _EXC_OFF_DIRECT_INTR bcopy ((void *)&_func_int_handler, (void *)_EXC_OFF_DIRECT_INTR, intSize); CACHE_TEXT_UPDATE ((void *)_EXC_OFF_DIRECT_INTR, intSize); #endif /* _EXC_OFF_DIRECT_INTR */ #ifdef _EXC_OFF_DECR bcopy ((void *)&_func_int_handler, (void *)_EXC_OFF_DECR, intSize); CACHE_TEXT_UPDATE ((void *)_EXC_OFF_DECR, intSize); #endif /* _EXC_OFF_DECR */ } #endif /* _WRS_CONFIG_WRHV_GUEST && !_VB_PISA_EHV */ return (OK); }    下面按excVecInit里面函数的初始化顺序讲解: macro in targetharchppcprivateexArchLibP.h #   define    EXT_ENT_OFF     3     /* offset for ext intEnt/excEnt */ #   define    EXT_ISR_OFF     8     /* offset for ext ISR or exc handler */ #   define    EXT_EXIT_OFF     15    /* offset for ext intExit/excExit */ 描述的是在每类中断向量里面中断入口函数,处理函数,退出函数相对于这类向量地址的偏移量,目前我还没理解值为啥是这个数。 (1)excVecInit里面有: entOffset = EXT_ENT_OFF; isrOffset = EXT_ISR_OFF; exitOffset = EXT_EXIT_OFF; (2)excVecInit 调用 excVecBaseSet(intVecBaseGet()); 此时才真正设置了中断向量基地址 void excVecBaseSet(FUNCPTR * baseAddr){ ... excVecBase = (vectorBase)((uint32_t)baseAddr & 0x0ffff0000); vxIvprSet ((int) excVecBase); ... } /* code in vxALib.s */ FUNC_BEGIN(vxIvprGet) mfspr p0, IVPR blr FUNC_END(vxIvprGet) FUNC_BEGIN(vxIvprSet) mtspr IVPR, p0 blr FUNC_END(vxIvprSet) (3)excVecConnectCommon 该程序是安装所有中断默认处理的函数 函数涉及vxWorks中一个重要的数据结构异常向量表excBlTbl[] typedef struct excTbl { vecTblOffset vecOff; /* vector offset */ EXC_TYPE vType; /* exception type */ void (*excHandler) (); /* exception handler routine */ vecTblOffset vecOffReloc; /* relocated vector offset */ } EXC_TBL; vecTblOffset 为UINT32,在此代表的意义为相对于中断向量表基地址的偏移量(简单来说就是vecOff用来设置IVORs寄存器的,当然基地值为0的情况下) 异常向量表的表项数量和内容随CPU不同而不同,对于P2020处理器而言,其异常向量表中的表项如下: { {_EXC_OFF_CRTL, V_CRIT_INT, excIntHandle, 0}, /* critical int */ #ifdef _PPC_MSR_MCE {_EXC_OFF_MACH, V_MCHK_EXC, excExcHandle, 0}, /* machine chk */ #elif _PPC_MSR_CE {_EXC_OFF_MACH, V_CRIT_EXC, excExcHandle, 0}, /* machine chk */ #endif /* _PPC_MSR_MCE */ {_EXC_OFF_DATA, V_NORM_EXC, excExcHandle, 0}, /* data storage */ {_EXC_OFF_INST, V_NORM_EXC, excExcHandle, 0}, /* instr access */ {_EXC_OFF_INTR, V_NORM_INT, excIntHandle, 0}, /* ext int */ #ifdef _EXC_OFF_DIRECT_INTR {_EXC_OFF_DIRECT_INTR, V_NORM_INT, excIntHandle, 0}, /* ext int */ #endif /* _EXC_OFF_DIRECT_INTR */ {_EXC_OFF_ALIGN, V_NORM_EXC, excExcHandle, 0}, /* alignment */ {_EXC_OFF_PROG, V_NORM_EXC, excExcHandle, 0}, /* program */ {_EXC_OFF_FPU, V_NORM_EXC, excExcHandle, 0}, /* fp unavail */ {_EXC_OFF_SYSCALL, V_NORM_EXC, excExcHandle, 0}, /* syscall */ {_EXC_OFF_APU, V_NORM_EXC, excExcHandle, 0}, /* auxp unavail*/ {_EXC_OFF_DECR, V_NORM_INT, excDecrHandle, 0}, /* decrementer */ {_EXC_OFF_FIT, V_NORM_INT, excIntHandle, 0}, /* fixed timer */ {_EXC_OFF_WD, V_CRIT_INT, excIntHandle, 0}, /* watchdog */ {_EXC_OFF_DATA_MISS, V_NORM_EXC, excExcHandle, 0}, /* data TLB miss */ {_EXC_OFF_INST_MISS, V_NORM_EXC, excExcHandle, 0}, /* inst TLB miss */ {_EXC_OFF_DBG, V_CRIT_EXC, excExcHandle, 0}, /* debug events */ #ifdef _WRS_ALTIVEC_SUPPORT {_EXC_ALTIVEC_UNAVAILABLE, V_NORM_EXC,excExcHandle, 0}, /* altivec unav */ {_EXC_ALTIVEC_ASSIST, V_NORM_EXC, excExcHandle, 0}, /* altivec asst */ #endif /* _WRS_ALTIVEC_SUPPORT */ #ifdef _WRS_SPE_SUPPORT {_EXC_OFF_SPE, V_NORM_EXC, excExcHandle, 0}, /* SPE */ {_EXC_OFF_VEC_DATA, V_NORM_EXC, excExcHandle, 0}, /* vector data */ {_EXC_OFF_VEC_RND, V_NORM_EXC, excExcHandle, 0}, /* vector round */ #endif /* _WRS_SPE_SUPPORT */ {_EXC_OFF_PERF_MON, V_NORM_INT, excIntHandle, 0}, /* perf monitor */ } 表格中涉及的宏targetharchppcexcPpcLib.h macro in #define _EXC_OFF_CRTL 0x0100 /* Critical Input */ #define _EXC_OFF_MACH 0x0200 /* Machine Check */ #define _EXC_OFF_DATA 0x0300 /* Data Storage */ #define _EXC_OFF_INST 0x0400 /* Instruction Storage */ #define _EXC_OFF_INTR 0x0500 /* External Input */ #define _EXC_OFF_ALIGN 0x0600 /* Alignment */ #define _EXC_OFF_PROG 0x0700 /* Program */ #define _EXC_OFF_FPU 0x0800 /* Floating Point Unavailable */ #define _EXC_OFF_SYSCALL 0x0900 /* System Call */ #define _EXC_OFF_APU 0x0a00 /* Auxiliary Processor Unavailable */ #define _EXC_OFF_DECR 0x0b00 /* Decrementer */ #define _EXC_OFF_FIT 0x0c00 /* Fixed Interval Timer */ #define _EXC_OFF_WD 0x0d00 /* Watchdog Timer */ #define _EXC_OFF_DATA_MISS 0x0e00 /* Data TLB Error */ #define _EXC_OFF_INST_MISS 0x0f00 /* Instruction TLB Error */ #define _EXC_OFF_DBG 0x1000 /* Debug exception */ typedef enum excType { V_NORM_EXC = 0, V_NORM_INT /* 重点对象 */ #ifdef _PPC_MSR_CE ,V_CRIT_EXC ,V_CRIT_INT #ifdef _PPC_MSR_MCE ,V_MCHK_EXC #endif /* _PPC_MSR_MCE */ #endif /* _PPC_MSR_CE */ } EXC_TYPE; /* 中断的入口函数以及出口函数 */ LOCAL EXC_WRAPPERS excTypeRtnTbl[] = { {excEnt, excExit}, /* V_NORM_EXC */ {intEnt, intExit}, /* V_NORM_INT */ #ifndef _VB_PISA_EHV #ifdef _PPC_MSR_CE {excCrtEnt, excCrtExit}, /* V_CRIT_EXC */ {intCrtEnt, intCrtExit}, /* V_CRIT_INT */ #ifdef _PPC_MSR_MCE {excMchkEnt, excMchkExit} /* V_MCHK_EXC */ #endif /* _PPC_MSR_MCE */ #endif /* _PPC_MSR_CE */ #else /* _VB_PISA_EHV */ /* XXX need spurious exception handler */ # ifdef _PPC_MSR_CE {NULL, NULL}, /* V_CRIT_EXC */ {NULL, NULL}, /* V_CRIT_INT */ # ifdef _PPC_MSR_MCE {NULL, NULL} /* V_MCHK_EXC */ # endif /* _PPC_MSR_MCE */ # endif /* _PPC_MSR_CE */ #endif /* _VB_PISA_EHV */ }; 总的说来:excVecConnectCommon 是对中断向量表做处理,根据中断向量表第一个参数vecoff,计算该类中断的内存地址位置,然后将存根机器代码拷贝到该位置上,将xxEnt,xxExit,handler放置各自对应的位置中 /* copy the stub to the vector location */ bcopy((char *)stub, (char *)cVec, stubSize); (4)excIvorInit 设置IVOR寄存器 macro in excPpcLib.h /* Mappings between vector names and corresponding IVORs, for excALib.s */ #define IVOR0_VAL _EXC_OFF_CRTL /* Critical Input */ #if ((defined PPC_440x5) || (CPU == PPC465)) #define IVOR1_VAL _EXC_OFF_MCRECOV /* recoverable Machine Check */ #else /* PPC_440x5 || PPC465 */ #define IVOR1_VAL _EXC_OFF_MACH /* Machine Check */ #endif /* PPC_440x5 || PPC465 */ #define IVOR2_VAL _EXC_OFF_DATA /* Data Storage */ #define IVOR3_VAL _EXC_OFF_INST /* Instruction Storage */ #define IVOR4_VAL _EXC_OFF_INTR /* External Input */ #define IVOR5_VAL _EXC_OFF_ALIGN /* Alignment */ #define IVOR6_VAL _EXC_OFF_PROG /* Program */ #define IVOR7_VAL _EXC_OFF_FPU /* Floating Point Unavailable */ #define IVOR8_VAL _EXC_OFF_SYSCALL /* System Call */ #define IVOR9_VAL _EXC_OFF_APU /* Auxiliary Processor Unavailable */ #define IVOR10_VAL _EXC_OFF_DECR /* Decrementer */ #define IVOR11_VAL _EXC_OFF_FIT /* Fixed Interval Timer */ #define IVOR12_VAL _EXC_OFF_WD /* Watchdog Timer */ #define IVOR13_VAL _EXC_OFF_DATA_MISS /* Data TLB Error */ #define IVOR14_VAL _EXC_OFF_INST_MISS /* Instruction TLB Error */ #define IVOR15_VAL _EXC_OFF_DBG /* Debug exception */ code in . argetsrcarchppcexcALib.s FUNC_EXPORT(excIvorInit) FUNC_BEGIN(excIvorInit) li p0, IVOR0_VAL mtspr IVOR0, p0 li p0, IVOR1_VAL mtspr IVOR1, p0 li p0, IVOR2_VAL mtspr IVOR2, p0 li p0, IVOR3_VAL mtspr IVOR3, p0 li p0, IVOR4_VAL ... FUNC_END(excIvorInit)  存根代码表: LOCAL INSTR excConnectCode[]= { /* data word byte opcode operands */ 0x7c7343a6, /* 0 0x00 mtspr SPRG3, p0 */ #if defined(_EXC_OFF_CRTL) # if defined(T4_ERRATUM_CPU6198) && defined(_WRS_CONFIG_SMP) 0x7c6000a6, /* 1 0x04 mfmsr p0 */ 0x546303da, /* 2 0x08 rlwinm p0,p0,0,15,13 clear MSR[CE] */ 0x7c7b8ba6, /* 3 0x0c mtspr MCSRR1,p0 */ 0x3c600000, /* 4 0x10 lis p0,HI(mtmsrwa) */ 0x60630000, /* 5 0x14 ori p0,p0,LO(mtmsrwa) */ 0x7c7a8ba6, /* 6 0x18 mtspr MCSRR0,p0 */ 0x4c00004c, /* 7 0x1c rfmci */ # else 0x7c6000a6, /* 1 0x04 mfmsr p0 */ 0x546303da, /* 2 0x08 rlwinm p0,p0,0,15,13 clear MSR[CE] */ 0x7c600124, /* 3 0x0c mtmsr p0 */ 0x60000000, /* 4 0x10 nop */ # endif /* T4_ERRATUM_CPU6198 && _WRS_CONFIG_SMP */ #elif defined(_WRS_PPC_64BIT) 0x7c6000a6, /* 1 0x04 mfmsr p0 */ 0x786300c0, /* 2 0x08 clrldi p0,p0,3 clear MSR[SF] */ 0x7c600164, /* 3 0x0c mtmsrd p0 */ 0x4c00012c, /* 4 0x10 isync */ #endif /* _EXC_OFF_CRTL, _WRS_PPC_64BIT */ /* If either of the above, add 4 words/0x10 bytes to following offsets */ 0x7c6802a6, /* 1 0x04 mflr p0 */ 0x48000001, /* 2(6) 0x08/18 bl xxxEnt */ 0x38610000, /* 3 0x0c addi r3, sp, 0 */ 0x9421fff0, /* 4 0x10 stwu sp, -FRAMEBASESZ(sp) */ 0x48000001, /* 5(9) 0x14/24 bl xxxHandler */ 0x38210010, /* 6 0x18 addi sp, sp, FRAMEBASESZ */ 0x48000001 /* 7(11) 0x1c/2c bl xxxExit */ }; 系统起来后在vxWorks shell 中输入d 0x500 (外部中断的内存地址),可以看到数据和excConnectCode存根一致 中断向量内存图分析: P2020 BSP 中使用的中断向量内存分布图: ------------- | 0x0 | vector base address ------------- | 0x100 | Critical Input ------------- | 0x200 | Machine Check ------------- | 0x300 | Data Storage ------------- | 0x400 | Instruction Storage ------------- | 0x500 | External Input[0x500开始处存放excConnectCode存根] | cVec[3] | 存放c函数地址高16位 cVec = 0x500 [3] = EXT_ENT_OFF | cVec[4] | 存放entInt函数地址低16位 | cVec[8] | 存放&excHandlers[n]地址,其中excHandlers存放默认的ISR,该函数会读取IACK | cVec[9] | [8] = EXT_ISR_OFF,存放ISR函数的低16位 | cVec[15] | 存放exitInt函数地址高16位 [15] = EXT_EXIT_OFF | cVec[16] | 存放exitInt函数地址低16位 | ... | ------------- | 0x600 | Alignment ------------- | 0x700 | Program ------------- | ... | /* execPpcLib.h 有定义 */ ------------- 总的说来中断处理流程为:中断产生后,e500内核根据MSR,IVPR,IVORs等寄存器来确认异常类型, 以及该类中断向量地址,然后进行存根机器代码-->entInt(汇编)保存现场-->ISR(确认中断源, 处理的functions)-->exitInt(汇编)恢复现场,至于PC<-->SRR0 ,MSR<-->SRR1是在存根, 还是在entInt与exitInt中操作,有待细化...

6.总结

   参考文献:    1.POWERPC(e500) 基于linux 中断过程分析    2.PowrPC基于vxWorks异常堆栈切换分析    3.PowerPC汇编指令以及通用/专用寄存器介绍    4.PowerPC OEA寄存器集介绍