对ARM的异常处理

来源:互联网 发布:cad面积计算软件 编辑:程序博客网 时间:2024/05/21 19:29

ARM的异常处理

ARM异常处理的研究务必要弄清楚以下几个方面: 异常类型,异常类型及处理该异常时CPU的执行模式,异常向量地址,异常处理过程 。

1、异常类型
(1)
、复位RESET)
   a
当处理器复位引脚有效时,系统产生复位异常中断,程序跳转到复位异常中断处理程序处执行,包括系统加电和系统复位。
   
b
通过设置PC跳转到复位中断向量处执行称为软复位。

(2)、未定义的指令
   
ARM处理器或者是系统中的协处理器认为当前指令未定义时,产生未定义的指令异常中断,可以通过改异常中断机制仿真浮点向量运算。

(3)、软件中断(SWI)
   
这是一个由用户定义的中断指令(SWI)。可用于用户模式下的程序调用特权操作指令。在实时操作系统中可以通过该机制实现系统功能调用。

(4)、指令与取终止PrefechAbort)
   
如果处理器预取的指令的地址不存在,或者该地址不允许当前指令访问,当被预取的指令执行时,处理器产生指令预取终止异常中断。

(5)、数据访问终止DATAABORT
   
如果数据访问指令的目标地址不存在,或者该地址不允许当前指令访问,处理器产生数据访问终止异常中断。

(6)、外部中断请求(IRQ)
   
当处理器的外部中断请求引脚有效,而且CPSR的寄存器的I控制位被清除时,处理器产生外部中断请求异常中断。系统中个外设通过该异常中断请求处理服务。

(7)、快速中断请求FIQ
   
当处理器的外部快速中断请求引脚有效,而且CPSRF控制位被清除时,处理器产生外部中断请求异常中断。

2、执行模式及向量地址
  ARM
的异常向量地址可以处于4G物理空间的低端(0x00000000起),也可以处于高端(0xffff0000起),具体是哪种情况,根据具体的CPU及其配置而定。ARMv4及其以上的版本,ARM异常向量表的地址受协处理器CP15c1寄存器(controlregister)V位的控制,如果V=1,则异常向量表的地址为0x00000000~0x0000001c;如果V=0,则为:0xffff0000~0xffff001c。表17种异常的执行模式及向量地址:



1

异常类型

执行模式

向量地址

RESET异常

Supervisor模式

0x00000000 (0xffff0000)

未定义的指令

Undefined模式

0x00000004(0xffff0004)

软件中断

Supervisor模式

0x00000008(0xffff0008)

PrefechAbort

Abort模式

0x0000000c(0xffff000c)

DATA Abort

Abort模式

0x00000010(0xffff0010)

IRQ

IRQ模式

0x00000018(0xffff0018)

FIQ

FIQ模式

0x0000001c(0xffff001c)



3、处理过程
处理过程包括两个部分:
进入:这个过程由CPU负责
退出:这个过程由OS负责
在捕获到某个异常后,启动“进入”过程,该过程内CPU执行如下动作:
1将当前PC的值(或PC+ 4,或PC+ 8保存到R14的某个寄存器中。到底选择哪个寄存器由该异常的执行模式而定;另外R14影子寄存器的值同异常类型相关。比如DataAbort异常,对应的影子寄存器就是Abort模式的影子寄存器R14_abtR14_abt的值为异常产生时PC+ 8
2CPSR保存到CPSR的某个寄存器SPSR中,同样,具体选择哪个寄存器由该异常的执行模式而定。
3改写CPSR以切换到相应的异常模式和处理器状态ARM状态)
4禁止IRQ(如果进入FIQ则禁止FIQ);
5跳转到相应异常向量表入口(例如IRQ跳转到IRQ_Handler入口);

【注】复位异常处理会禁止所有中断,另外由于不用返回,因此不需要作1)(2步。

4示例异常处理程序

Example 4.1说明了一个自定义异常处理程序。假定将某些Fortran代码转换为C代码。Fortran数值标准要求0除以0 1,而IEEE754 规定 0 除以0 是“无效运算”,因此,缺省返回无提示NaNFortran代码可能会依赖于这种行为,让0除以0 返回1可能更方便一些,而不是对代码进行修改。

进行编译时,必须选择一种支持异常的浮点模型,例如--fpmode=ieee_full--fpmode=ieee_fixed

安装处理程序之后,0.0除以0.0返回1.0

Example 4.1. 自定义异常处理程序

#include<fenv.h>

#include<signal.h>

#include<stdio.h>

__softfp__ieee_value_t myhandler(__ieee_value_t op1, __ieee_value_t op2,

__ieee_edata_t edata)

{

__ieee_value_tret;

if((edata & FE_EX_FN_MASK) == FE_EX_FN_DIV)

    {

if((edata & FE_EX_INTYPE_MASK) == FE_EX_INTYPE_FLOAT)

         {

if(op1.f == 0.0 && op2.f == 0.0)

             {

ret.f= 1.0;

returnret;

}

}

if((edata&FE_EX_INTYPE_MASK)== FE_EX_INTYPE_DOUBLE)

         {

if(op1.d == 0.0 && op2.d == 0.0)

             {

ret.d= 1.0;

returnret;

}

}

}

/*For all other invalid operations, raise SIGFPE as usual */

raise(SIGFPE);

}

intmain(void)

{

floati, j, k;

fenv_tenv;

fegetenv(&env);

env.statusword|= FE_IEEE_MASK_INVALID;

env.invalid_handler= myhandler;

fesetenv(&env);

i= 0.0;

j= 0.0;

k= i/j;

printf(“kis %f\n“, k);

}

5.linux下的异常捕获和处理

清单 1.在异常对象构造函数中生成一个堆栈跟踪

//Sample Program:
// Compiler: gcc 3.2.3 20030502
// Linux:Red Hat

#include<execinfo.h>
#include <signal.h>

#include<exception>
#include <iostream>

usingnamespace std;

/////////////////////////////////////////////

classExceptionTracer
{
 public:
  ExceptionTracer()
  {
   void* array[25];
   intnSize = backtrace(array, 25);
   char** symbols = backtrace_symbols(array, nSize);
 
   for(int i = 0; i < nSize; i++)
   {
    cout<< symbols[i] << endl;
   }

  free(symbols);
 }
};

清单 2中定义的SignalExceptionClass,提供了表示内核可能发出信号的C++异常的抽象。SignalTranslator是一个基于SignalExceptionClass的模板类,它通常用来实现到C++异常的转换。在任何瞬间,只能有一个信号处理程序处理一个活动进程的一个信号。因此,SignalTranslator采用了singleton设计模式。整体概念通过用于SIGSEGVSegmentationFault类和用于SIGFPEFloatingPointException类得到了展示。

清单 2.将信号转换成异常

template<class SignalExceptionClass> classSignalTranslator
{
 private:
  classSingleTonTranslator
  {
   public:
    SingleTonTranslator()
    {
     signal(SignalExceptionClass::GetSignalNumber(),SignalHandler);
    }

    staticvoid SignalHandler(int)
    {
     throwSignalExceptionClass();
    }
   };

 public:
  SignalTranslator()
  {
   staticSingleTonTranslator s_objTranslator;
  }
};

//An example for SIGSEGV
class SegmentationFault : publicExceptionTracer, public exception
{
 public:
  staticint GetSignalNumber() {return SIGSEGV;}
};

SignalTranslator<SegmentationFault>g_objSegmentationFaultTranslator;

//An example for SIGFPE
class FloatingPointException : publicExceptionTracer, public exception
{
 public:
  staticint GetSignalNumber() {return SIGFPE;}
};

SignalTranslator<FloatingPointException>g_objFloatingPointExceptionTranslator

清单 3.处理构造函数中的异常

classExceptionHandler
{
 private:
  classSingleTonHandler
  {
   public:
    SingleTonHandler()
    {
     set_terminate(Handler);
    }

    staticvoid Handler()
    {
     //Exception from construction/destruction of globalvariables
     try
     {
      //re-throw
      throw;
     }
     catch(SegmentationFault &)
     {
      cout<< SegmentationFault << endl;
     }
     catch(FloatingPointException &)
     {
      cout<< FloatingPointException << endl;
     }
     catch(...)
     {
      cout<< Unknown Exception << endl;
     }

     //ifthis is a thread performing some coreactivity
     abort();
     //else if this is a thread used to service requests
     //pthread_exit();
    }
  };

  public:
   ExceptionHandler()
   {
    staticSingleTonHandler s_objHandler;
   }
  };

//////////////////////////////////////////////////////////////////////////

  classA
  {
   public:
    A()
    {
     //inti = 0, j = 1/i;
     *(int*)0 = 0;
    }
  };

  //Before defining any global variable, we define a dummyinstance
  //of ExceptionHandler object to make sure that
  //ExceptionHandler::SingleTonHandler::SingleTonHandler() isinvoked
  ExceptionHandlerg_objExceptionHandler;
  Ag_a;

  //////////////////////////////////////////////////////////////////////////

  intmain(int argc, char* argv[])
  {
   return0;
  }