Arm系统异常向量表
VectorTable
DCD -1 ; 复位异常
DCD UndefException ; 未定义指令异常
DCD SWIHandler ; 软中断
DCD PrefetchAbort ; 预取指令异常
DCD DataAbortHandler ; Data Abort异常
DCD -1 ; unused vector
DCD IRQHandler ; IRQ
DCD FIQHandler ; FIQ
END
在armtrap.s中提供了这些异常的服务函数。下面是伪代码:
UndefException()
{
CommonHandler(ID_UNDEF_INSTR);
}
SWIHandler()
{
}//所以对于arm系统, 系统调用并不是软中断来实现的。
PrefetchAbort()
{
// process something...
CommonHandler(ID_PREFETCH_ABORT);
}
DataAbortHandler()
{
CommonHandler(ID_DATA_ABORT);
}
IRQHandler()
{
ULONG sysintr = OEMInterruptHandler();
OEMNotifyIntrOccurs();
if (sysintr == SYSINTR_RESCHED)
CommonHandler(ID_RESCHEDULE);
}
FIQHandler()
{
OEMInterruptHandlerFIQ();
}
前面这个模型结构里,所有异常都立刻处理完毕或者呼叫CommonHandler这个公共异常函数如下:
CommonHandler(int id)
{
HandleException(, id, ... );
}
下面给出完整的HandleException的代码:
PTHREAD
HandleException(
PTHREAD pth,
int id,
ulong addr,
ushort info
)
{
if (ID_RESCHEDULE != id) {
KCALLPROFON(0);
// encode THUMB state in PC
if (pth->ctx.Psr & THUMB_STATE) {
THRD_CTX_TO_PC (pth) |= 1;
} else {
THRD_CTX_TO_PC (pth) &= ~1;
}
if (!KC_CommonHandleException (pth, id, addr, info)) {
// handle exception failed - reschedule
id = ID_RESCHEDULE;
}
KCALLPROFOFF(0);
}
if (ID_RESCHEDULE == id) {
do {
if (ReschedFlag) {
ReschedFlag = 0;
NextThread();
}
if (KCResched) {
KCResched = 0;
KCNextThread();
}
if (!RunList.pth) {
INTERRUPTS_OFF();
if (!ReschedFlag && !KCResched) {
OEMIdle (g_pNKGlobal->dwNextReschedTime - g_pNKGlobal->dwCurMSec);
ReschedFlag = 1;
}
INTERRUPTS_ON();
}
} while (ReschedFlag || KCResched);
// save the exception state of the thread being preempted if fpu has been touched.
if (g_fVFPTouched) {
// read and clear is guaranteed not to generate an exception
g_pOemGlobal->pfnSaveVFPCtrlRegs (pCurThread->ctx.FpExtra, NUM_EXTRA_CONTROL_REGS);
pCurThread->ctx.FpExc = ReadAndSetFpexc (0);
g_fVFPTouched = FALSE;
}
pth = RunList.pth;
SetCPUASID (pth);
dwCurThId = pth->dwId;
pCurThread = pth;
KPlpvTls = pth->tlsPtr;
}
return pth;
}
从上面这个HandleException可以知道几个情况:
1. IRQ引起内核调度而不是SWI软中断trap。具体是哪一个IRQ由OEM决定, 比如三星的arm9系列, 一般用Timer4的IRQ作为系统时钟中断。
2. 线程调度室2个阶段, NextThread 和KCNextThread。 如果没有线程要执行,则调用OEMIdle进入idle状态。
3. 对于其他引起的异常, 这里有 DataAbort , PrefetchAbort , UndefException ,则使用 KC_CommonHandleException ()处理, 很大可能导致系统 Halt ,我们经常在调试口看到的异常就是这里输出的。如果没有 halt , 则继续调度。