1.中断
中断/异常入口基址ebase设置并不在0x80000000,而是其它地址。
中断配制成矢量模式,vector offset配置成0x100。Int0~int7(int0/int1:sw;int2~int7:hw;int7-count/compare)
Ebase:0x8045f000;Int0 entry:0x8045f200;Int2 entry:0x8045f200+(2*0x100)
a)矢量中断入口注册
set_vi_handler(2, mips_int2_handler);
void *set_vi_handler(int n, vi_handler_t addr)
{
return set_vi_srs_handler(n, addr, 0);
}
static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
{
extern char except_vec_vi, except_vec_vi_lui;
extern char except_vec_vi_ori, except_vec_vi_end;
extern char rollback_except_vec_vi;
char *vec_start = (cpu_wait == r4k_wait) ?
&rollback_except_vec_vi : &except_vec_vi;
const int handler_len = &except_vec_vi_end - vec_start;
const int lui_offset = &except_vec_vi_lui - vec_start;
const int ori_offset = &except_vec_vi_ori - vec_start;
if (handler_len > VECTORSPACING) {
/*
* Sigh... panicing won't help as the console
* is probably not configured :(
*/
panic("VECTORSPACING too small");
}
memcpy(b, vec_start, handler_len);//拷贝一段公用的中断处理入口代码片段
w = (u32 *)(b + lui_offset);//修改中断处理函数的地址
*w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff);
w = (u32 *)(b + ori_offset);//修改中断处理函数的地址
*w = (*w & 0xffff0000) | ((u32)handler & 0xffff);
local_flush_icache_range((unsigned long)b,
(unsigned long)(b+handler_len));//刷icache
}
b)中断处理服务程序注册
setup_irq(MIPS_CPU_IRQ_BASE + 2, &cascade_irqaction);
setup_irq(MIPS_CPU_IRQ_BASE + 3, &dma_irqaction);
setup_irq(ASOC_IRQ_BASE + DMA_INT, &cascade_irqaction);
setup_irq(ASOC_IRQ_BASE + PC_INT, &cascade_irqaction);
#define IRQ_TIMER0 (ASOC_IRQ_BASE+10)//对应irq分配策略
request_irq(IRQ_TIMER0, mips_timer_interrupt, 0, "timer", (void *)0);
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
…
setup_irq(irq, action);
…
}
c)setup_irq的参数irq与irq分配策略有关。
原则上是任意一个硬件中断源可以随意配置到任意一个中断信号上(int0~int7)。每一个中断信号上也都可以挂多个中断源。从实现和效率角度看,将一些优先级高的中断源独立的挂在一个中断信号上,其它都挂载一个公用的中断上是比较合理的。下图是一种分配方式。
d)中断服务程序执行流程
Int2_handler
8045f400:401a7000mfc0k0,c0_epc
8045f404:3c1b8010luik1,0x8010
8045f408:277b0640addiuk1,k1,1600
8045f40c:375a001forik0,k0,0x1f
8045f410:3b5a001fxorik0,k0,0x1f
8045f414:175b0002bnek0,k1,8045f420
8045f418:00000000nop
8045f41c:409a7000mtc0k0,c0_epc
8045f420:401a6000mfc0k0,c0_status
8045f424:001ad0c0sllk0,k0,0x3
8045f428:07400003bltzk0,8045f438
8045f42c:03a0d821movek1,sp
8045f430:3c1b8041luik1,0x8041
8045f434:8f7be938lwk1,-5832(k1)
8045f438:03a0d021movek0,sp
8045f43c:277dff50addiusp,k1,-176
8045f440:afba008cswk0,140(sp)
8045f444:afa30024swv1,36(sp)
8045f448:afa00018swzero,24(sp)
8045f44c:40036000mfc0v1,c0_status
8045f450:afa20020swv0,32(sp)
8045f454:afa30098swv1,152(sp)
8045f458:afa40028swa0,40(sp)
8045f45c:40036800mfc0v1,c0_cause
8045f460:afa5002cswa1,44(sp)
8045f464:afa300a8swv1,168(sp)
8045f468:afa60030swa2,48(sp)
8045f46c:40037000mfc0v1,c0_epc
8045f470:afa70034swa3,52(sp)
8045f474:afa300acswv1,172(sp)
8045f478:afb9007cswt9,124(sp)
8045f47c:afbc0088swgp,136(sp)
8045f480:afbf0094swra,148(sp)
8045f484:37bc1ffforigp,sp,0x1fff
8045f488:3b9c1fffxorigp,gp,0x1fff
8045f48c:afa1001cswat,28(sp)
8045f490:3c028010luiv0,0x8010//对应set_vi_srs_handler中的地址修改(lui)
8045f494:0804020dj80100834//except_vec_vi_handler
8045f498:34428278oriv0,v0,0x8278//对应set_vi_srs_handler中的地址修改(ori)
except_vec_vi_handler
NESTED(except_vec_vi_handler, 0, sp)
SAVE_TEMP
SAVE_STATIC
CLI
LONG_Ls0, TI_REGS($28)
LONG_Ssp, TI_REGS($28)
PTR_LAra, ret_from_irq//中断总出口
jrv0// mips_int2_handler
END(except_vec_vi_handler)
asmlinkage void mips_int2_handler(void)
{
xxx_irqdispatch();
}
static void xxx_irqdispatch(void)
{
int irq;
u32 intc0_pending = readl(IC0_PD);
u32 intc0_mask = readl(IC0_MASK);
u32 intc0_req0 = intc0_pending & intc0_mask;
u32 intc0_ext_int = 0;
if (!intc0_req0) {
spurious_interrupt();
goto exit;
}
irq = ffs(intc0_req0) - 1;
if (irq != EXTERNAL_INT){
do_IRQ(ASOC_IRQ_BASE + irq);//对应irq分配策略
goto exit;
}
else
{
…
}
exit:
return;
}
2.异常
a)tlb_refill
8045f000: 3c1b8041 lui k1,0x80418045f004: 401a4000 mfc0 k0,c0_badvaddr8045f008: 8f7b3000 lw k1,12288(k1)//pgd_current8045f00c: 001ad582 srl k0,k0,0x168045f010: 001ad080 sll k0,k0,0x28045f014: 037ad821 addu k1,k1,k08045f018: 401a2000 mfc0 k0,c0_context8045f01c: 8f7b0000 lw k1,0(k1)8045f020: 001ad042 srl k0,k0,0x18045f024: 335a0ff8 andi k0,k0,0xff88045f028: 037ad821 addu k1,k1,k08045f02c: 8f7a0000 lw k0,0(k1)8045f030: 8f7b0004 lw k1,4(k1)8045f034: 001ad182 srl k0,k0,0x68045f038: 409a1000 mtc0 k0,c0_entrylo08045f03c: 001bd982 srl k1,k1,0x68045f040: 409b1800 mtc0 k1,c0_entrylo18045f044: 000000c0 ehb8045f048: 42000006 tlbwr8045f04c: 42000018 eret8045f050: 00000000 nop
b)general_exception
8045f180:401b6800mfc0k1,c0_cause
8045f184:337b007candik1,k1,0x7c
8045f188:3c1a8041luik0,0x8041
8045f18c:035bd021adduk0,k0,k1
8045f190:8f5aeac0lwk0,-5440(k0)//exception_handlers[i]
8045f194:03400008jrk0
8045f198:00000000nop
c)设置异常处理函数入口
void *set_except_vector(int n, void *addr)
set_except_vector(0, rollback ? rollback_handle_int : handle_int);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
set_except_vector(6, handle_ibe);
set_except_vector(7, handle_dbe);
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
set_except_vector(10, rdhwr_noopt ? handle_ri :(cpu_has_vtag_icache ? handle_ri_rdhwr_vivt : handle_ri_rdhwr));
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
set_except_vector(14, handle_mc);
set_except_vector(15, handle_ndc);
set_except_vector(15, handle_fpe);
set_except_vector(22, handle_mdmx);
set_except_vector(24, handle_mcheck);
set_except_vector(25, handle_mt);
set_except_vector(26, handle_dsp);