三读内核中断处理(3):中断处理流程

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

ADSP-BF561

优视BF561EVB开发板

uclinux-2008r1.5-rc3(smp patch)

Visual DSP++5.0(update 5)

欢迎转载,但请保留作者信息

1.1 evt_nmi

这个代码是用汇编写的,其实现在arch/blackfin/mach-common/interrupt.s中,用于处理nmi中断:

/* Interrupt routine for evt2 (NMI).

* We don't actually use this, so just return.

* For inner circle type details, please see:

* http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi

*/

ENTRY(_evt_nmi)

.weak _evt_nmi

rtn;

ENDPROC(_evt_nmi)

空语句,没什么可说的。

1.2 trap

这部分代码用于处理Exception中断,对于内核而言是相当重要的,其实现在arch\blackfin\mach-common\entry.S文件中

ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/

/* Since the kernel stack can be anywhere, it's not guaranteed to be

* covered by a CPLB. Switch to an exception stack; use RETN as a

* scratch register (for want of a better option).

*/

EX_SCRATCH_REG = sp;

//GET_PDA_SAFE(sp);

sp.l = lo(DSPID);

sp.h = hi(DSPID);

sp = [sp];

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

sp = sp << 2;

if cc jump _trap_3;

cc = sp == 0x0;

if !cc jump _trap_4;

_trap_1:

/* sp = 0x0; */

cc = !cc; /* restore cc to 0 */

_trap_2:

sp.l = lo(L1_SCRATCH_COREA);

sp.h = hi(L1_SCRATCH_COREA);

jump _trap_5;

_trap_3:

cc = sp == 0x0;

if cc jump _trap_2;

/* sp = 0x1000000; */

cc = !cc; /* restore cc to 1 */

_trap_4:

sp.l = lo(L1_SCRATCH_COREB);

sp.h = hi(L1_SCRATCH_COREB);

_trap_5:

//GET_PDA_SAFE(sp); end

sp = [sp + PDA_EXSTACK];

/* Try to deal with syscalls quickly. */

[--sp] = ASTAT;

[--sp] = (R7:6, P5:4);

DEBUG_STOP_HWTRACE(p5, r7)

r7 = SEQSTAT; /* reason code is in bit 5:0 */

r6.l = lo(SEQSTAT_EXCAUSE);

r6.h = hi(SEQSTAT_EXCAUSE);

r7 = r7 & r6;

p5.h = _ex_table;

p5.l = _ex_table;

p4 = r7;

p5 = p5 + (p4 << 2);

p4 = [p5];

jump (p4);

.Lbadsys:

r7 = -ENOSYS; /* signextending enough */

[sp + PT_R0] = r7; /* return value from system call */

jump .Lsyscall_really_exit;

ENDPROC(_trap)

在这里EX_SCRATCH_REG定义成RETN这个寄存器。

SMP版本中,每个核都使用了自身的scratch pad sram做为其私有数据区,因而在这段代码的开头就判断DSPID并设置正确的SP指针,使其指向各自内部的SCRATCH PAD SRAM在原有的代码中,使用了GET_SAFE_PDA(sp)这个宏来达到目的,但移植到VDSP时,由于汇编语法方面的差异,将这个宏展开并进行了适当修改。

_ex_table是在本文件中定义的函数指针的数组,它指明了所有可能的64种异常的入口:

ENTRY(_ex_table)

/* entry for each EXCAUSE[5:0]

* This table must be in sync with the table in ./kernel/traps.c

* EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined

*/

.long _ex_syscall /* 0x00 - User Defined - Linux Syscall */

.long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */

.long _ex_replaceable /* 0x02 - User Defined */

.long _ex_trap_c /* 0x03 - User Defined - userspace stack overflow */

.long _ex_spinlock /* 0x04 - User Defined - dump trace buffer */

.long _ex_replaceable /* 0x05 - User Defined */

.long _ex_replaceable /* 0x06 - User Defined */

.long _ex_replaceable /* 0x07 - User Defined */

.long _ex_replaceable /* 0x08 - User Defined */

.long _ex_replaceable /* 0x09 - User Defined */

.long _ex_replaceable /* 0x0A - User Defined */

.long _ex_replaceable /* 0x0B - User Defined */

.long _ex_replaceable /* 0x0C - User Defined */

.long _ex_replaceable /* 0x0D - User Defined */

.long _ex_replaceable /* 0x0E - User Defined */

.long _ex_replaceable /* 0x0F - User Defined */

.long _ex_single_step /* 0x10 - HW Single step */

#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND

.long _ex_trace_buff_full /* 0x11 - Trace Buffer Full */

#else

.long _ex_trap_c /* 0x11 - Trace Buffer Full */

#endif

.long _ex_trap_c /* 0x12 - Reserved */

.long _ex_trap_c /* 0x13 - Reserved */

.long _ex_trap_c /* 0x14 - Reserved */

.long _ex_trap_c /* 0x15 - Reserved */

.long _ex_trap_c /* 0x16 - Reserved */

.long _ex_trap_c /* 0x17 - Reserved */

.long _ex_trap_c /* 0x18 - Reserved */

.long _ex_trap_c /* 0x19 - Reserved */

.long _ex_trap_c /* 0x1A - Reserved */

.long _ex_trap_c /* 0x1B - Reserved */

.long _ex_trap_c /* 0x1C - Reserved */

.long _ex_trap_c /* 0x1D - Reserved */

.long _ex_trap_c /* 0x1E - Reserved */

.long _ex_trap_c /* 0x1F - Reserved */

.long _ex_trap_c /* 0x20 - Reserved */

.long _ex_trap_c /* 0x21 - Undefined Instruction */

.long _ex_trap_c /* 0x22 - Illegal Instruction Combination */

.long _ex_dviol /* 0x23 - Data CPLB Protection Violation */

.long _ex_trap_c /* 0x24 - Data access misaligned */

.long _ex_trap_c /* 0x25 - Unrecoverable Event */

.long _ex_dmiss /* 0x26 - Data CPLB Miss */

.long _ex_dmult /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero */

.long _ex_trap_c /* 0x28 - Emulation Watchpoint */

.long _ex_trap_c /* 0x29 - Instruction fetch access error (535 only) */

.long _ex_trap_c /* 0x2A - Instruction fetch misaligned */

.long _ex_trap_c /* 0x2B - Instruction CPLB protection Violation */

.long _ex_icplb_miss /* 0x2C - Instruction CPLB miss */

.long _ex_trap_c /* 0x2D - Instruction CPLB Multiple Hits */

.long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */

.long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */

.long _ex_trap_c /* 0x2F - Reserved */

.long _ex_trap_c /* 0x30 - Reserved */

.long _ex_trap_c /* 0x31 - Reserved */

.long _ex_trap_c /* 0x32 - Reserved */

.long _ex_trap_c /* 0x33 - Reserved */

.long _ex_trap_c /* 0x34 - Reserved */

.long _ex_trap_c /* 0x35 - Reserved */

.long _ex_trap_c /* 0x36 - Reserved */

.long _ex_trap_c /* 0x37 - Reserved */

.long _ex_trap_c /* 0x38 - Reserved */

.long _ex_trap_c /* 0x39 - Reserved */

.long _ex_trap_c /* 0x3A - Reserved */

.long _ex_trap_c /* 0x3B - Reserved */

.long _ex_trap_c /* 0x3C - Reserved */

.long _ex_trap_c /* 0x3D - Reserved */

.long _ex_trap_c /* 0x3E - Reserved */

.long _ex_trap_c /* 0x3F - Reserved */

_ex_table.end:

//END(_ex_table)

因而,这一段程序就是根据不同的EXCEPTION的类型,调用相应的入口函数进行处理。可以看到,对于大部分的异常,都是通过ex_trap_c这个函数来处理的。

1.3 _evt_ivhw

这部分代码在arch\blackfin\mach-common\interrupt.S中,用于处理Hardware Error InterruptVDSP文档对此的解释是:

The Hardware Error Interrupt is generated by:

Bus parity errors

Internal error conditions within the core, such as Performance Monitor overflow

Peripheral errors

Bus timeout errors

看看uclinux的处理:

/* interrupt routine for ivhw - 5 */

ENTRY(_evt_ivhw)

SAVE_ALL_SYS

#ifdef CONFIG_FRAME_POINTER

fp = 0;

#endif

#if ANOMALY_05000283

cc = r7 == r7;

p5.h = HI(CHIPID);

p5.l = LO(CHIPID);

if cc jump _evt_ivhw_1;

r7.l = W[p5];

_evt_ivhw_1:

#endif

#ifdef CONFIG_HARDWARE_PM

r7 = [sp + PT_SEQSTAT];

r7 = r7 >>> 0xe;

r6 = 0x1F;

r7 = r7 & r6;

r5 = 0x12;

cc = r7 == r5;

if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */

#endif

//# We are going to dump something out, so make sure we print IPEND properly

p2.l = lo(IPEND);

p2.h = hi(IPEND);

r0 = [p2];

[sp + PT_IPEND] = r0;

/* set the EXCAUSE to HWERR for trap_c */

r0 = [sp + PT_SEQSTAT];

R1.L = LO(VEC_HWERR);

R1.H = HI(VEC_HWERR);

R0 = R0 | R1;

[sp + PT_SEQSTAT] = R0;

r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */

SP += -12;

call _trap_c;

SP += 12;

call _ret_from_exception;

.Lcommon_restore_all_sys:

RESTORE_ALL_SYS

rti;

#ifdef CONFIG_HARDWARE_PM

.Lcall_do_ovf:

SP += -12;

call _pm_overflow;

SP += 12;

jump .Lcommon_restore_all_sys;

#endif

ENDPROC(_evt_ivhw)

在这里,SAVE_ALL_SYS将系统的大部分寄存器的值都压到栈中,且入栈的顺序是和pt_regs这个结构体的成员一一对应的,因此最后可以将此结构体的指针传给函数trap_c。需要注意的是,这个中断处理代码并未重新设置SP的值,也就是说它将使用发生错误的线程的SP

PT_IPENDPT_SEQSTAT分别定义了保存IPENDSEQSTAT这两个寄存器值的成员相应于pt_regs这个结构体的偏移量,因而使用[sp + PT_IPEND]这样的方式可以取得相应寄存器的值。

VEC_HWERR则是定义好的一个常数:

/* The hardware reserves (63) for future use - we use it to tell our

* normal exception handling code we have a hardware error

*/

#define VEC_HWERR (63)

因为出错的原因保存在SEQSTAT寄存器的低5位中,因此通过取或的方式将pt_regs->seqstat的值设置为EXCAUSE,而不是原来的32位整数。

然后调用trap_c进行处理,此函数将决定输出错误信息后返回原位置执行,或者中止执行。

1.4 _ret_from_exception

这个函数将由_evt_ivhw在返回时调用,其实现在arch\blackfin\mach-common\entry.S中:

ENTRY(_ret_from_exception)

p2.l = lo(IPEND);

p2.h = hi(IPEND);

csync;

r0 = [p2];

[sp + PT_IPEND] = r0;

_ret_from_exception_1:

r2 = LO(~0x37) (Z);

r0 = r2 & r0;

cc = r0 == 0;

if !cc jump _ret_from_exception_4; /* if not return to user mode, get out */

/* Make sure any pending system call or deferred exception

* return in ILAT for this process to get executed, otherwise

* in case context switch happens, system call of

* first process (i.e in ILAT) will be carried

* forward to the switched process

*/

p2.l = lo(ILAT);

p2.h = hi(ILAT);

r0 = [p2];

r1 = (EVT_IVG14 | EVT_IVG15) (z);

r0 = r0 & r1;

cc = r0 == 0;

if !cc jump _ret_from_exception_5;

/* Set the stack for the current process */

r7 = sp;

r4.l = lo(ALIGN_PAGE_MASK);

r4.h = hi(ALIGN_PAGE_MASK);

r7 = r7 & r4; /* thread_info->flags */

p5 = r7;

r7 = [p5 + TI_FLAGS];

r4.l = lo(_TIF_WORK_MASK);

r4.h = hi(_TIF_WORK_MASK);

r7 = </

你可能感兴趣的:(C++,c,linux,C#,FP)