head.s分析(7):init_early_exception_vectors

快乐虾

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

[email protected]

本文适用于

ADI bf561 DSP

uclinux-2008r1.5-rc3 (移植到vdsp5)

Visual DSP++ 5.0(update 5)

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

#ifdef CONFIG_EARLY_PRINTK

SP += -12;

call.x _init_early_exception_vectors;

SP += 12;

#endif

所调用的这个函数将设置EVT2-EVT15的中断向量。同时将所有的返回地址也指向同一个位置。

/*

* Set up a temporary Event Vector Table, so if something bad happens before

* the kernel is fully started, it doesn't vector off into somewhere we don't

* know

*/

asmlinkage void __init init_early_exception_vectors(void)

{

SSYNC();

/* cannot program in software:

* evt0 - emulation (jtag)

* evt1 - reset

*/

bfin_write_EVT2(early_trap);

bfin_write_EVT3(early_trap);

bfin_write_EVT5(early_trap);

bfin_write_EVT6(early_trap);

bfin_write_EVT7(early_trap);

bfin_write_EVT8(early_trap);

bfin_write_EVT9(early_trap);

bfin_write_EVT10(early_trap);

bfin_write_EVT11(early_trap);

bfin_write_EVT12(early_trap);

bfin_write_EVT13(early_trap);

bfin_write_EVT14(early_trap);

bfin_write_EVT15(early_trap);

CSYNC();

/* Set all the return from interrupt, exception, NMI to a known place

* so if we do a RETI, RETX or RETN by mistake - we go somewhere known

* Note - don't change RETS - we are in a subroutine, or

* RETE - since it might screw up if emulator is attached

*/

asm("\tRETI = %0; RETX = %0; RETN = %0;\n"

: : "p"(early_trap));

}

其中RETI为中断服务的返回地址,RETX为异常中断的返回地址,RETN为不可屏蔽中断的返回地址。

early_trap这一中断入口的定义在linux-2.6.x\arch\blackfin\mach-common\entry.S中:

ENTRY(_early_trap)

SAVE_ALL_SYS

trace_buffer_stop(p0,r0)

/* Turn caches off, to ensure we don't get double exceptions */

P4.L = LO(IMEM_CONTROL);

P4.H = HI(IMEM_CONTROL);

R5 = [P4]; /* Control Register*/

BITCLR(R5,ENICPLB_P);

CLI R1;

SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */

.align 8;

[P4] = R5;

SSYNC;

P4.L = LO(DMEM_CONTROL);

P4.H = HI(DMEM_CONTROL);

R5 = [P4];

BITCLR(R5,ENDCPLB_P);

SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */

.align 8;

[P4] = R5;

SSYNC;

STI R1;

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

r1 = RETX;

SP += -12;

call.x _early_trap_c;

SP += 12;

ENDPROC(_early_trap)

这段代码功能比较简单,将寄存器入栈,关闭cache,然后调用c的函数early_trap_c,由于early_trap_c直接就panic,一旦进入这个中断入口就不会再退出,所有在这个中断服务中没有返回的指令。这里比较有意思的是调用early_trap_c时的参数传递。

early_trap_c的函数原型为:

asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)

它将接受一个结构体的指针和一个返回地址作为参数。在参数传递过程中,对于少于三个参数的函数调用,使用R0来传递第一个参数,使用R1来传递第二个参数。因此在上述汇编代码中,有

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

r1 = RETX;

那么结构体的内容来自于哪里呢?先看看pt_regs的定义:

/* this struct defines the way the registers are stored on the

stack during a system call. */

struct pt_regs {

long orig_pc;

long ipend;

long seqstat;

long rete;

long retn;

long retx;

long pc; /* PC == RETI */

long rets;

long reserved; /* Used as scratch during system calls */

long astat;

long lb1;

long lb0;

long lt1;

long lt0;

long lc1;

long lc0;

long a1w;

long a1x;

long a0w;

long a0x;

long b3;

long b2;

long b1;

long b0;

long l3;

long l2;

long l1;

long l0;

long m3;

long m2;

long m1;

long m0;

long i3;

long i2;

long i1;

long i0;

long usp;

long fp;

long p5;

long p4;

long p3;

long p2;

long p1;

long p0;

long r7;

long r6;

long r5;

long r4;

long r3;

long r2;

long r1;

long r0;

long orig_r0;

long orig_p0;

long syscfg;

};

再看看SAVE_ALL_SYS的定义:

#define SAVE_ALL_SYS save_context_no_interrupts

#define save_context_no_interrupts \

[--sp] = SYSCFG; \

[--sp] = P0; /* orig_p0 */ \

[--sp] = R0; /* orig_r0 */ \

[--sp] = ( R7:0, P5:0 ); \

[--sp] = fp; \

[--sp] = usp; \

\

[--sp] = i0; \

[--sp] = i1; \

[--sp] = i2; \

[--sp] = i3; \

\

[--sp] = m0; \

[--sp] = m1; \

[--sp] = m2; \

[--sp] = m3; \

\

[--sp] = l0; \

[--sp] = l1; \

[--sp] = l2; \

[--sp] = l3; \

\

[--sp] = b0; \

[--sp] = b1; \

[--sp] = b2; \

[--sp] = b3; \

[--sp] = a0.x; \

[--sp] = a0.w; \

[--sp] = a1.x; \

[--sp] = a1.w; \

\

[--sp] = LC0; \

[--sp] = LC1; \

[--sp] = LT0; \

[--sp] = LT1; \

[--sp] = LB0; \

[--sp] = LB1; \

\

[--sp] = ASTAT; \

\

[--sp] = r0; /* Skip reserved */ \

[--sp] = RETS; \

r0 = RETI; \

[--sp] = r0; \

[--sp] = RETX; \

[--sp] = RETN; \

[--sp] = RETE; \

[--sp] = SEQSTAT; \

[--sp] = r0; /* Skip IPEND as well. */ \

[--sp] = r0; /*orig_pc*/ \

/* Clear all L registers. */ \

r0 = 0 (x); \

l0 = r0; \

l1 = r0; \

l2 = r0; \

l3 = r0; \

//.endm

入栈顺序刚好和pt_regs结构体的成员次序相反,由于入栈操作时SP指针是向下增长的,而结构体成员的排列则是向上增长的,因此入栈操作即相当于对结构体的成员一一赋值。

最后看看early_trap_c的实现:

asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)

{

/* This can happen before the uart is initialized, so initialize

* the UART now

*/

if (likely(early_console == NULL))

setup_early_printk(DEFAULT_EARLY_PORT);

dump_bfin_mem(fp);

show_regs(fp);

dump_bfin_trace_buffer();

panic("Died early");

}

输出寄存器的内容,然后panic

1 参考资料

head.s分析(1):保存u-boot传递过来的指针(2009-1-19)

head.s分析(2)SYSCFG配置(2009-1-19)

head.s分析(3):数据及指针寄存器清0(2009-1-19)

head.s分析(4):关闭CACHE(2009-01-19)

head.s分析(5):关闭串口(2009-01-19)

head.s分析(6):栈指针初始化(2009-01-19)

你可能感兴趣的:(数据结构,C++,c,C#,FP)