快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
ADSP-BF561
uclinux-2008r1.5-rc3(smp patch)
Visual DSP++5.0(update 5)
欢迎转载,但请保留作者信息
这个代码是用汇编写的,其实现在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)
空语句,没什么可说的。
这部分代码用于处理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这个函数来处理的。
这部分代码在arch\blackfin\mach-common\interrupt.S中,用于处理Hardware Error Interrupt,VDSP文档对此的解释是:
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_IPEND和PT_SEQSTAT分别定义了保存IPEND和SEQSTAT这两个寄存器值的成员相应于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进行处理,此函数将决定输出错误信息后返回原位置执行,或者中止执行。
这个函数将由_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 = </