1. 简介
本文简要介绍了PowerPC体系结构下vxWorks操作系统的异常处理机制,指出当前机制存在的缺陷,即:中断级的异常处理在任务上下文中执行,异常处理堆栈基址依赖于当前任务的栈帧指针,如果传入堆帧异常会导致访问非法地址甚至系统死机。笔者结合当前的工作对异常处理的堆栈空间进行了优化,类似中断处理,将异常处理放在独立的堆栈空间,增强了系统的健壮性。主要章节如下:
2 PowerPC体系结构的异常机制
3 vxWorks的异常处理流程
4 异常切换的设计与实现
如果读者对异常机制比较熟悉,可以直接跳过2、3章节。如果有问题可与笔者联系,新浪微博帐号:@白银之手骑士团
2. PowerPC体系结构的异常机制
PowerPC体系结构中所有的异常可以分为由指令导致的异常以及由系统导致的异常。由系统导致的异常包括系统复位异常,机器检查异常,外部中断,DEC计数器异常。PowerPC异常分类如下:
当处理器判定异常可以被获取,并对其进行处理的时候,处理器进行如下的操作:
(1)将当前的PC指针保存到SRR0寄存器中;
(2)将当前的MSR寄存器的值保存到SRR1中;
(3)设置MSR的值,新的MSR值起作用的时间开始于从异常向量地址处取第一条指令;
(4)利用新的MSR值,从异常对应的异常向量处取指令和执行指令。注意异常向量在内存中的位置依赖于MSR的IP位。
下表列出了当发生了对应的异常后,MSR的值将被处理器如何设置,注意其中的几个位:EE,IR和DR位。这几位在发生异常后都将被处理器设置为0,也就是说处理器在获取异常之后禁止外部中断和DEC中断,并关闭MMU功能。
3. vxWorks的异常处理流程
我们知道,总的来说PowerPC的异常处理机制就是在发生异常时将当时关键的处理器状态(PC和MSR)保存到暂存寄存器SRR0和SRR1中,然后跳转到与所发生异常对应的异常向量地址处执行。
而vxWorks要做的工作,就是要在系统初始化的时候正确地安装好异常处理入口程序,异常处理程序以及异常退出程序,以便在发生异常时能够进一步将当前处理器的状态(LR寄存器,XER寄存器,通用寄存器等)保存到内存中,并调用恰当的函数来处理异常,在异常处理之后恢复被异常打断的任务,使之继续执行。
vxWorks的异常处理代码主要集中在文件excALib.s,excArchLib.c,intALib.s和intArchLib.c中,这几个文件位于vxWorks源代码的\target\src\arch\ppc目录下。3.1 异常处理的数据结构
异常向量表是vxWorks异常处理机制中的一个重要的数据结构,异常向量表的每个表项是一个类型为EXC_TBL的对象。该类型定义如下: typedef struct excTbl
{
UINT32 vecOff; /* vector offset*/
STATUS (*excCnctRtn) (); /* routine to connect the exception handler*/
void (*excHandler) (); /* exceptionhandler routine */
UINT32 vecOffReloc; /* vector offset relocation address */
} EXC_TBL;
异常向量表的表项数量和内容随CPU不同而不同,对于PPC603和PPCEC603处理器而言,其异常向量表中的表项如下:
{
{_EXC_OFF_RESET, excConnect, excExcHandle, 0}, /* system reset */
{_EXC_OFF_MACH, excConnect, excExcHandle, 0}, /* machine chk */
{_EXC_OFF_DATA, excConnect, excExcHandle, 0}, /* data access */
{_EXC_OFF_INST, excConnect, excExcHandle, 0}, /* instr access */
{_EXC_OFF_INTR, excIntConnect, excIntHandle, 0}, /* ext int */
{_EXC_OFF_ALIGN, excConnect, excExcHandle, 0}, /* alignment */
{_EXC_OFF_PROG, excConnect, excExcHandle, 0}, /* program */
{_EXC_OFF_FPU, excConnect, excExcHandle, 0}, /* fp unavail */
{_EXC_OFF_DECR, excIntConnect, excIntHandle, 0}, /* decrementer */
{_EXC_OFF_SYSCALL, excConnect, excExcHandle, 0}, /* system call */
{_EXC_OFF_TRACE, excConnect, excExcHandle, 0}, /* trace excepti */
{_EXC_OFF_INST_MISS,excConnect, excExcHandle, 0}, /* i-trsl miss */
{_EXC_OFF_LOAD_MISS,excConnect, excExcHandle, 0}, /*d-trsl miss */
{_EXC_OFF_STORE_MISS,excConnect, excExcHandle, 0}, /* d-trslmiss */
{_EXC_OFF_INST_BRK, excConnect, excExcHandle, 0}, /* instr BP */
{_EXC_OFF_SYS_MNG, excConnect, excExcHandle, 0}, /* sys mgt*/
{0, (STATUS (*)()) NULL, (void (*) ()) NULL, 0}, /* end of table */
}