From 5d750b9e4f6ca7d366b4954517ff8be9ee07e1bf Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Fri, 25 Apr 2008 05:02:33 +0800 Subject: [PATCH] [Blackfin] arch: Remove the circular buffering mechanism for exceptions Remove the circular buffering mechanism for exceptions. Instead, point RETX at a safe location from which to fetch three NOPs. This safe location is now in the fixed code area, and also used for certain anomaly workarounds, to ensure that user space can find a valid ICPLB when things are built with CONFIG_MPU. Also, save I/DCPLB_FAULT_ADDRESS when lowering to level 5, since the hardware reg is valid only at exception level. Signed-off-by: Bernd Schmidt Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 15 ++- arch/blackfin/mach-common/entry.S | 121 ++++++---------------- arch/blackfin/mach-common/ints-priority.c | 2 - 3 files changed, 40 insertions(+), 98 deletions(-) diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index d0f675422074..5b847070dae5 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -67,6 +67,8 @@ void __init trap_init(void) CSYNC(); } +void *saved_icplb_fault_addr, *saved_dcplb_fault_addr; + int kstack_depth_to_print = 48; static void decode_address(char *buf, unsigned long address) @@ -703,10 +705,7 @@ void dump_bfin_mem(struct pt_regs *fp) unsigned short *addr, *erraddr, val = 0, err = 0; char sti = 0, buf[6]; - if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)) - erraddr = (void *)fp->pc; - else - erraddr = (void *)fp->retx; + erraddr = (void *)fp->pc; printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr); @@ -830,9 +829,9 @@ void show_regs(struct pt_regs *fp) if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { - decode_address(buf, bfin_read_DCPLB_FAULT_ADDR()); + decode_address(buf, saved_dcplb_fault_addr); printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); - decode_address(buf, bfin_read_ICPLB_FAULT_ADDR()); + decode_address(buf, saved_icplb_fault_addr); printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); } @@ -940,8 +939,8 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp) oops_in_progress = 1; - printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR()); - printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR()); + printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", saved_dcplb_fault_addr); + printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", saved_icplb_fault_addr); dump_bfin_process(fp); dump_bfin_mem(fp); show_regs(fp); diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index a504c65d9990..f2fb87e9a46e 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -38,6 +38,7 @@ #include #include #include +#include #include /* TIF_NEED_RESCHED */ #include #include @@ -52,15 +53,6 @@ # define EX_SCRATCH_REG CYCLES #endif -#if ANOMALY_05000281 -ENTRY(_safe_speculative_execution) - NOP; - NOP; - NOP; - jump _safe_speculative_execution; -ENDPROC(_safe_speculative_execution) -#endif - #ifdef CONFIG_EXCPT_IRQ_SYSC_L1 .section .l1.text #else @@ -230,6 +222,26 @@ ENTRY(_ex_trap_c) [p4] = p5; csync; + p4.l = lo(DCPLB_FAULT_ADDR); + p4.h = hi(DCPLB_FAULT_ADDR); + r7 = [p4]; + p5.h = _saved_dcplb_fault_addr; + p5.l = _saved_dcplb_fault_addr; + [p5] = r7; + + r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; + p5.h = _saved_icplb_fault_addr; + p5.l = _saved_icplb_fault_addr; + [p5] = r7; + + p4.l = __retx; + p4.h = __retx; + r6 = retx; + [p4] = r6; + p4.l = lo(SAFE_USER_INSTRUCTION); + p4.h = hi(SAFE_USER_INSTRUCTION); + retx = p4; + /* Disable all interrupts, but make sure level 5 is enabled so * we can switch to that level. Save the old mask. */ cli r6; @@ -239,23 +251,6 @@ ENTRY(_ex_trap_c) r6 = 0x3f; sti r6; - /* Save the excause into a circular buffer, in case the instruction - * which caused this excecptions causes others. - */ - P5.l = _in_ptr_excause; - P5.h = _in_ptr_excause; - R7 = [P5]; - R7 += 4; - R6 = 0xF; - R7 = R7 & R6; - [P5] = R7; - R6.l = _excause_circ_buf; - R6.h = _excause_circ_buf; - R7 = R7 + R6; - p5 = R7; - R6 = SEQSTAT; - [P5] = R6; - (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; SP = EX_SCRATCH_REG; @@ -312,6 +307,11 @@ ENDPROC(_double_fault) ENTRY(_exception_to_level5) SAVE_ALL_SYS + p4.l = __retx; + p4.h = __retx; + r6 = [p4]; + [sp + PT_PC] = r6; + /* Restore interrupt mask. We haven't pushed RETI, so this * doesn't enable interrupts until we return from this handler. */ p4.l = _excpt_saved_imask; @@ -333,42 +333,11 @@ ENTRY(_exception_to_level5) r0 = [p2]; /* Read current IPEND */ [sp + PT_IPEND] = r0; /* Store IPEND */ - /* Pop the excause from the circular buffer and push it on the stack - * (in the right place - if you change the location of SEQSTAT, you - * must change this offset. - */ -.L_excep_to_5_again: - P5.l = _out_ptr_excause; - P5.h = _out_ptr_excause; - R7 = [P5]; - R7 += 4; - R6 = 0xF; - R7 = R7 & R6; - [P5] = R7; - R6.l = _excause_circ_buf; - R6.h = _excause_circ_buf; - R7 = R7 + R6; - P5 = R7; - R1 = [P5]; - [SP + PT_SEQSTAT] = r1; - r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; call _trap_c; SP += 12; - /* See if anything else is in the exception buffer - * if there is, process it - */ - P5.l = _out_ptr_excause; - P5.h = _out_ptr_excause; - P4.l = _in_ptr_excause; - P4.h = _in_ptr_excause; - R6 = [P5]; - R7 = [P4]; - CC = R6 == R7; - if ! CC JUMP .L_excep_to_5_again - call _ret_from_exception; RESTORE_ALL_SYS rti; @@ -732,8 +701,8 @@ ENTRY(_return_from_int) [p0] = p1; csync; #if ANOMALY_05000281 - r0.l = _safe_speculative_execution; - r0.h = _safe_speculative_execution; + r0.l = lo(SAFE_USER_INSTRUCTION); + r0.h = hi(SAFE_USER_INSTRUCTION); reti = r0; #endif r0 = 0x801f (z); @@ -746,8 +715,8 @@ ENDPROC(_return_from_int) ENTRY(_lower_to_irq14) #if ANOMALY_05000281 - r0.l = _safe_speculative_execution; - r0.h = _safe_speculative_execution; + r0.l = lo(SAFE_USER_INSTRUCTION); + r0.h = hi(SAFE_USER_INSTRUCTION); reti = r0; #endif r0 = 0x401f; @@ -814,20 +783,6 @@ _schedule_and_signal: rti; ENDPROC(_lower_to_irq14) -/* Make sure when we start, that the circular buffer is initialized properly - * R0 and P0 are call clobbered, so we can use them here. - */ -ENTRY(_init_exception_buff) - r0 = 0; - p0.h = _in_ptr_excause; - p0.l = _in_ptr_excause; - [p0] = r0; - p0.h = _out_ptr_excause; - p0.l = _out_ptr_excause; - [p0] = r0; - rts; -ENDPROC(_init_exception_buff) - /* We handle this 100% in exception space - to reduce overhead * Only potiential problem is if the software buffer gets swapped out of the * CPLB table - then double fault. - so we don't let this happen in other places @@ -1403,17 +1358,7 @@ _exception_stack_top: _last_cplb_fault_retx: .long 0; #endif -/* - * Single instructions can have multiple faults, which need to be - * handled by traps.c, in irq5. We store the exception cause to ensure - * we don't miss a double fault condition - */ -ENTRY(_in_ptr_excause) + /* Used to save the real RETX when temporarily storing a safe + * return address. */ +__retx: .long 0; -ENTRY(_out_ptr_excause) - .long 0; -ALIGN -ENTRY(_excause_circ_buf) - .rept 4 - .long 0 - .endr diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 5448230c0e95..f5fd768022ea 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -939,8 +939,6 @@ int __init init_arch_irq(void) local_irq_disable(); - init_exception_buff(); - #ifdef CONFIG_BF54x # ifdef CONFIG_PINTx_REASSIGN pint[0]->assign = CONFIG_PINT0_ASSIGN;