Blackfin: initial XIP support
[safe/jmp/linux-2.6] / arch / blackfin / mach-common / entry.S
index 3feca05..ccfa7c4 100644 (file)
@@ -1,62 +1,29 @@
 /*
- * File:         arch/blackfin/mach-common/entry.S
- * Based on:
- * Author:       Linus Torvalds
+ * Contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all
+ * interrupts and faults that can result in a task-switch.
  *
- * Created:      ?
- * Description:  contains the system-call and fault low-level handling routines.
- *               This also contains the timer-interrupt handler, as well as all
- *               interrupts and faults that can result in a task-switch.
+ * Copyright 2005-2009 Analog Devices Inc.
  *
- * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  */
 
-/*
- * 25-Dec-2004 - LG Soft India
- *     1. Fix in return_from_int, to make sure any pending
- *     system call 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.
- *     2. Removed Constant references for the following
- *             a.  IPEND
- *             b.  EXCAUSE mask
- *             c.  PAGE Mask
- */
-
-/*
- * NOTE: This code handles signal-recognition, which happens every time
+/* NOTE: This code handles signal-recognition, which happens every time
  * after a timer-interrupt and after each system call.
  */
 
-
+#include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/unistd.h>
 #include <asm/blackfin.h>
 #include <asm/errno.h>
+#include <asm/fixed_code.h>
 #include <asm/thread_info.h>  /* TIF_NEED_RESCHED */
 #include <asm/asm-offsets.h>
 #include <asm/trace.h>
+#include <asm/traps.h>
 
-#include <asm/mach-common/context.S>
+#include <asm/context.S>
 
 #if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
 # define EX_SCRATCH_REG RETN
  * This one does not lower the level to IRQ5, and thus can be used to
  * patch up CPLB misses on the kernel stack.
  */
-ENTRY(_ex_dcplb)
 #if ANOMALY_05000261
+#define _ex_dviol _ex_workaround_261
+#define _ex_dmiss _ex_workaround_261
+#define _ex_dmult _ex_workaround_261
+
+ENTRY(_ex_workaround_261)
        /*
         * Work around an anomaly: if we see a new DCPLB fault, return
         * without doing anything.  Then, if we get the same fault again,
         * handle it.
         */
-       p5.l = _last_cplb_fault_retx;
-       p5.h = _last_cplb_fault_retx;
-       r7 = [p5];
+       P4 = R7;        /* Store EXCAUSE */
+
+       GET_PDA(p5, r7);
+       r7 = [p5 + PDA_LFRETX];
        r6 = retx;
-       [p5] = r6;
+       [p5 + PDA_LFRETX] = r6;
        cc = r6 == r7;
-       if !cc jump _return_from_exception;
+       if !cc jump _bfin_return_from_exception;
        /* fall through */
+       R7 = P4;
+       R6 = VEC_CPLB_M;        /* Data CPLB Miss */
+       cc = R6 == R7;
+       if cc jump _ex_dcplb_miss (BP);
+#ifdef CONFIG_MPU
+       R6 = VEC_CPLB_VL;       /* Data CPLB Violation */
+       cc = R6 == R7;
+       if cc jump _ex_dcplb_viol (BP);
 #endif
-ENDPROC(_ex_dcplb)
+       /* Handle Data CPLB Protection Violation
+        * and Data CPLB Multiple Hits - Linux Trap Zero
+        */
+       jump _ex_trap_c;
+ENDPROC(_ex_workaround_261)
 
-ENTRY(_ex_icplb)
+#else
+#ifdef CONFIG_MPU
+#define _ex_dviol _ex_dcplb_viol
+#else
+#define _ex_dviol _ex_trap_c
+#endif
+#define _ex_dmiss _ex_dcplb_miss
+#define _ex_dmult _ex_trap_c
+#endif
+
+
+ENTRY(_ex_dcplb_viol)
+ENTRY(_ex_dcplb_miss)
+ENTRY(_ex_icplb_miss)
        (R7:6,P5:4) = [sp++];
-       ASTAT = [sp++];
-       SAVE_ALL_SYS
-       call __cplb_hdr;
-       DEBUG_START_HWTRACE(p5, r7)
-       RESTORE_ALL_SYS
+       /* We leave the previously pushed ASTAT on the stack.  */
+       SAVE_CONTEXT_CPLB
+
+       /* We must load R1 here, _before_ DEBUG_HWTRACE_SAVE, since that
+        * will change the stack pointer.  */
+       R0 = SEQSTAT;
+       R1 = SP;
+
+       DEBUG_HWTRACE_SAVE(p5, r7)
+
+       sp += -12;
+       call _cplb_hdr;
+       sp += 12;
+       CC = R0 == 0;
+       IF !CC JUMP _handle_bad_cplb;
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* While we were processing this, did we double fault? */
+       r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+       r6.l = lo(SEQSTAT_EXCAUSE);
+       r6.h = hi(SEQSTAT_EXCAUSE);
+       r7 = r7 & r6;
+       r6 = 0x25;
+       CC = R7 == R6;
+       if CC JUMP _double_fault;
+#endif
+
+       DEBUG_HWTRACE_RESTORE(p5, r7)
+       RESTORE_CONTEXT_CPLB
+       ASTAT = [SP++];
        SP = EX_SCRATCH_REG;
        rtx;
-ENDPROC(_ex_icplb)
+ENDPROC(_ex_icplb_miss)
 
 ENTRY(_ex_syscall)
-       DEBUG_START_HWTRACE(p5, r7)
-       (R7:6,P5:4) = [sp++];
-       ASTAT = [sp++];
        raise 15;               /* invoked by TRAP #0, for sys call */
-       sp = EX_SCRATCH_REG;
-       rtx
+       jump.s _bfin_return_from_exception;
 ENDPROC(_ex_syscall)
 
-ENTRY(_ex_soft_bp)
-       r7 = retx;
-       r7 += -2;
-       retx = r7;
-       jump.s _ex_trap_c;
-ENDPROC(_ex_soft_bp)
-
 ENTRY(_ex_single_step)
+       /* If we just returned from an interrupt, the single step event is
+          for the RTI instruction.  */
        r7 = retx;
        r6 = reti;
        cc = r7 == r6;
-       if cc jump _return_from_exception
-       r7 = syscfg;
-       bitclr (r7, 0);
-       syscfg = R7;
+       if cc jump _bfin_return_from_exception;
 
+#ifdef CONFIG_KGDB
+       /* Don't do single step in hardware exception handler */
+        p5.l = lo(IPEND);
+        p5.h = hi(IPEND);
+       r6 = [p5];
+       cc = bittst(r6, 4);
+       if cc jump _bfin_return_from_exception;
+       cc = bittst(r6, 5);
+       if cc jump _bfin_return_from_exception;
+
+       /* skip single step if current interrupt priority is higher than
+        * that of the first instruction, from which gdb starts single step */
+       r6 >>= 6;
+       r7 = 10;
+.Lfind_priority_start:
+       cc = bittst(r6, 0);
+       if cc jump .Lfind_priority_done;
+       r6 >>= 1;
+       r7 += -1;
+       cc = r7 == 0;
+       if cc jump .Lfind_priority_done;
+       jump.s .Lfind_priority_start;
+.Lfind_priority_done:
+       p4.l = _kgdb_single_step;
+       p4.h = _kgdb_single_step;
+       r6 = [p4];
+       cc = r6 == 0;
+       if cc jump .Ldo_single_step;
+       r6 += -1;
+       cc = r6 < r7;
+       if cc jump 1f;
+.Ldo_single_step:
+#else
+       /* If we were in user mode, do the single step normally.  */
        p5.l = lo(IPEND);
        p5.h = hi(IPEND);
        r6 = [p5];
-       cc = bittst(r6, 5);
-       if !cc jump _ex_trap_c;
-       p4.l = lo(EVT5);
-       p4.h = hi(EVT5);
-       r6.h = _exception_to_level5;
-       r6.l = _exception_to_level5;
-       r7 = [p4];
-       cc = r6 == r7;
-       if !cc jump _ex_trap_c;
+       r7 = 0xffe0 (z);
+       r7 = r7 & r6;
+       cc = r7 == 0;
+       if !cc jump 1f;
+#endif
+#ifdef CONFIG_EXACT_HWERR
+       /* Read the ILAT, and to check to see if the process we are
+        * single stepping caused a previous hardware error
+        * If so, do not single step, (which lowers to IRQ5, and makes
+        * us miss the error).
+        */
+       p5.l = lo(ILAT);
+       p5.h = hi(ILAT);
+       r7 = [p5];
+       cc = bittst(r7, EVT_IVHW_P);
+       if cc jump 1f;
+#endif
+       /* Single stepping only a single instruction, so clear the trace
+        * bit here.  */
+       r7 = syscfg;
+       bitclr (r7, SYSCFG_SSSTEP_P);
+       syscfg = R7;
+       jump _ex_trap_c;
+
+1:
+       /*
+        * We were in an interrupt handler.  By convention, all of them save
+        * SYSCFG with their first instruction, so by checking whether our
+        * RETX points at the entry point, we can determine whether to allow
+        * a single step, or whether to clear SYSCFG.
+        *
+        * First, find out the interrupt level and the event vector for it.
+        */
+       p5.l = lo(EVT0);
+       p5.h = hi(EVT0);
+       p5 += -4;
+2:
+       r7 = rot r7 by -1;
+       p5 += 4;
+       if !cc jump 2b;
+
+       /* What we actually do is test for the _second_ instruction in the
+        * IRQ handler.  That way, if there are insns following the restore
+        * of SYSCFG after leaving the handler, we will not turn off SYSCFG
+        * for them.  */
+
+       r7 = [p5];
+       r7 += 2;
+       r6 = RETX;
+       cc = R7 == R6;
+       if !cc jump _bfin_return_from_exception;
+
+       r7 = syscfg;
+       bitclr (r7, SYSCFG_SSSTEP_P);   /* Turn off single step */
+       syscfg = R7;
+
+       /* Fall through to _bfin_return_from_exception.  */
+ENDPROC(_ex_single_step)
 
-ENTRY(_return_from_exception)
-       DEBUG_START_HWTRACE(p5, r7)
+ENTRY(_bfin_return_from_exception)
 #if ANOMALY_05000257
        R7=LC0;
        LC0=R7;
        R7=LC1;
        LC1=R7;
 #endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* While we were processing the current exception,
+        * did we cause another, and double fault?
+        */
+       r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+       r6.l = lo(SEQSTAT_EXCAUSE);
+       r6.h = hi(SEQSTAT_EXCAUSE);
+       r7 = r7 & r6;
+       r6 = VEC_UNCOV;
+       CC = R7 == R6;
+       if CC JUMP _double_fault;
+#endif
+
        (R7:6,P5:4) = [sp++];
        ASTAT = [sp++];
        sp = EX_SCRATCH_REG;
        rtx;
-ENDPROC(_ex_soft_bp)
+ENDPROC(_bfin_return_from_exception)
 
 ENTRY(_handle_bad_cplb)
+       DEBUG_HWTRACE_RESTORE(p5, r7)
        /* To get here, we just tried and failed to change a CPLB
         * so, handle things in trap_c (C code), by lowering to
         * IRQ5, just like we normally do. Since this is not a
@@ -165,120 +272,198 @@ ENTRY(_handle_bad_cplb)
         * the stack to get ready so, we can fall through - we
         * need to make a CPLB exception look like a normal exception
         */
-
-       DEBUG_START_HWTRACE(p5, r7)
-       RESTORE_ALL_SYS
-       [--sp] = ASTAT;
-       [--sp] = (R7:6, P5:4);
+       RESTORE_CONTEXT_CPLB
+       /* ASTAT is still on the stack, where it is needed.  */
+       [--sp] = (R7:6,P5:4);
 
 ENTRY(_ex_replaceable)
        nop;
 
 ENTRY(_ex_trap_c)
+       /* The only thing that has been saved in this context is
+        * (R7:6,P5:4), ASTAT & SP - don't use anything else
+        */
+
+       GET_PDA(p5, r6);
+
+       /* Make sure we are not in a double fault */
+       p4.l = lo(IPEND);
+       p4.h = hi(IPEND);
+       r7 = [p4];
+       CC = BITTST (r7, 5);
+       if CC jump _double_fault;
+       [p5 + PDA_EXIPEND] = r7;
+
        /* Call C code (trap_c) to handle the exception, which most
         * likely involves sending a signal to the current process.
         * To avoid double faults, lower our priority to IRQ5 first.
         */
-       P5.h = _exception_to_level5;
-       P5.l = _exception_to_level5;
+       r7.h = _exception_to_level5;
+       r7.l = _exception_to_level5;
        p4.l = lo(EVT5);
        p4.h = hi(EVT5);
-       [p4] = p5;
+       [p4] = r7;
        csync;
 
-       /* Disable all interrupts, but make sure level 5 is enabled so
-        * we can switch to that level.  Save the old mask.  */
+       /*
+        * Save these registers, as they are only valid in exception context
+        *  (where we are now - as soon as we defer to IRQ5, they can change)
+        * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+        * but they are not very interesting, so don't save them
+        */
+
+       p4.l = lo(DCPLB_FAULT_ADDR);
+       p4.h = hi(DCPLB_FAULT_ADDR);
+       r7 = [p4];
+       [p5 + PDA_DCPLB] = r7;
+
+       p4.l = lo(ICPLB_FAULT_ADDR);
+       p4.h = hi(ICPLB_FAULT_ADDR);
+       r6 = [p4];
+       [p5 + PDA_ICPLB] = r6;
+
+       r6 = retx;
+       [p5 + PDA_RETX] = r6;
+
+       r6 = SEQSTAT;
+       [p5 + PDA_SEQSTAT] = r6;
+
+       /* Save the state of single stepping */
+       r6 = SYSCFG;
+       [p5 + PDA_SYSCFG] = r6;
+       /* Clear it while we handle the exception in IRQ5 mode */
+       BITCLR(r6, SYSCFG_SSSTEP_P);
+       SYSCFG = r6;
+
+       /* Save the current IMASK, since we change in order to jump to level 5 */
        cli r6;
-       p4.l = _excpt_saved_imask;
-       p4.h = _excpt_saved_imask;
-       [p4] = r6;
+       [p5 + PDA_EXIMASK] = 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.
+        */
        r6 = 0x3f;
        sti r6;
 
-       /* Save the excause into a circular buffer, in case the instruction
-        * which caused this excecptions causes others.
+       /* In case interrupts are disabled IPEND[4] (global interrupt disable bit)
+        * clear it (re-enabling interrupts again) by the special sequence of pushing
+        * RETI onto the stack.  This way we can lower ourselves to IVG5 even if the
+        * exception was taken after the interrupt handler was called but before it
+        * got a chance to enable global interrupts itself.
         */
-       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;
-
-       DEBUG_START_HWTRACE(p5, r7)
+       [--sp] = reti;
+       sp += 4;
+
+       raise 5;
+       jump.s _bfin_return_from_exception;
+ENDPROC(_ex_trap_c)
+
+/* We just realized we got an exception, while we were processing a different
+ * exception. This is a unrecoverable event, so crash.
+ * Note: this cannot be ENTRY() as we jump here with "if cc jump" ...
+ */
+ENTRY(_double_fault)
+       /* Turn caches & protection off, to ensure we don't get any more
+        * double exceptions
+        */
+
+       P4.L = LO(IMEM_CONTROL);
+       P4.H = HI(IMEM_CONTROL);
+
+       R5 = [P4];              /* Control Register*/
+       BITCLR(R5,ENICPLB_P);
+       CSYNC;          /* Disabling of CPLBs should be proceeded by a CSYNC */
+       [P4] = R5;
+       SSYNC;
+
+       P4.L = LO(DMEM_CONTROL);
+       P4.H = HI(DMEM_CONTROL);
+       R5 = [P4];
+       BITCLR(R5,ENDCPLB_P);
+       CSYNC;          /* Disabling of CPLBs should be proceeded by a CSYNC */
+       [P4] = R5;
+       SSYNC;
+
+       /* Fix up the stack */
        (R7:6,P5:4) = [sp++];
        ASTAT = [sp++];
        SP = EX_SCRATCH_REG;
-       raise 5;
-       rtx;
-ENDPROC(_ex_trap_c)
+
+       /* We should be out of the exception stack, and back down into
+        * kernel or user space stack
+        */
+       SAVE_ALL_SYS
+
+       /* The dumping functions expect the return address in the RETI
+        * slot.  */
+       r6 = retx;
+       [sp + PT_PC] = r6;
+
+       r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
+       SP += -12;
+       pseudo_long_call _double_fault_c, p5;
+       SP += 12;
+.L_double_fault_panic:
+        JUMP .L_double_fault_panic
+
+ENDPROC(_double_fault)
 
 ENTRY(_exception_to_level5)
        SAVE_ALL_SYS
 
-       /* 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;
-       p4.h = _excpt_saved_imask;
-       r6 = [p4];
-       sti r6;
+       GET_PDA(p5, r7);        /* Fetch current PDA */
+       r6 = [p5 + PDA_RETX];
+       [sp + PT_PC] = r6;
+
+       r6 = [p5 + PDA_SYSCFG];
+       [sp + PT_SYSCFG] = r6;
+
+       r6 = [p5 + PDA_SEQSTAT]; /* Read back seqstat */
+       [sp + PT_SEQSTAT] = r6;
 
        /* Restore the hardware error vector.  */
-       P5.h = _evt_ivhw;
-       P5.l = _evt_ivhw;
+       r7.h = _evt_ivhw;
+       r7.l = _evt_ivhw;
        p4.l = lo(EVT5);
        p4.h = hi(EVT5);
-       [p4] = p5;
-       csync;
-
-       p2.l = lo(IPEND);
-       p2.h = hi(IPEND);
+       [p4] = r7;
        csync;
-       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.
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /* Now that we have the hardware error vector programmed properly
+        * we can re-enable interrupts (IPEND[4]), so if the _trap_c causes
+        * another hardware error, we can catch it (self-nesting).
         */
-.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 + 8] = r1;
+       [--sp] = reti;
+       sp += 4;
+#endif
+
+       r7 = [p5 + PDA_EXIPEND] /* Read the IPEND from the Exception state */
+       [sp + PT_IPEND] = r7;   /* Store IPEND onto the stack */
 
        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
        SP += -12;
-       call _trap_c;
+       pseudo_long_call _trap_c, p4;
        SP += 12;
 
-       /* See if anything else is in the exception buffer
-        * if there is, process it
+       /* If interrupts were off during the exception (IPEND[4] = 1), turn them off
+        * before we return.
+        */
+       CC = BITTST(r7, EVT_IRPTEN_P)
+       if !CC jump 1f;
+       /* this will load a random value into the reti register - but that is OK,
+        * since we do restore it to the correct value in the 'RESTORE_ALL_SYS' macro
         */
-       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
+       sp += -4;
+       reti = [sp++];
+1:
+       /* restore the interrupt mask (IMASK) */
+       r6 = [p5 + PDA_EXIMASK];
+       sti r6;
 
        call _ret_from_exception;
        RESTORE_ALL_SYS
@@ -291,13 +476,51 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
         * scratch register (for want of a better option).
         */
        EX_SCRATCH_REG = sp;
-       sp.l = _exception_stack_top;
-       sp.h = _exception_stack_top;
+       GET_PDA_SAFE(sp);
+       sp = [sp + PDA_EXSTACK];
        /* Try to deal with syscalls quickly.  */
        [--sp] = ASTAT;
-       [--sp] = (R7:6, P5:4);
-       DEBUG_STOP_HWTRACE(p5, r7)
+       [--sp] = (R7:6,P5:4);
+
+#ifdef CONFIG_EXACT_HWERR
+       /* Make sure all pending read/writes complete. This will ensure any
+        * accesses which could cause hardware errors completes, and signal
+        * the the hardware before we do something silly, like crash the
+        * kernel. We don't need to work around anomaly 05000312, since
+        * we are already atomic
+        */
+       ssync;
+#endif
+
+       ANOMALY_283_315_WORKAROUND(p5, r7)
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+       /*
+        * Save these registers, as they are only valid in exception context
+        * (where we are now - as soon as we defer to IRQ5, they can change)
+        * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+        * but they are not very interesting, so don't save them
+        */
+
+       GET_PDA(p5, r7);
+       p4.l = lo(DCPLB_FAULT_ADDR);
+       p4.h = hi(DCPLB_FAULT_ADDR);
+       r7 = [p4];
+       [p5 + PDA_DF_DCPLB] = r7;
+
+       p4.l = lo(ICPLB_FAULT_ADDR);
+       p4.h = hi(ICPLB_FAULT_ADDR);
+       r7 = [p4];
+       [p5 + PDA_DF_ICPLB] = r7;
+
+       r7 = retx;
+       [p5 + PDA_DF_RETX] = r7;
+
        r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+       [p5 + PDA_DF_SEQSTAT] = r7;
+#else
+       r7 = SEQSTAT;           /* reason code is in bit 5:0 */
+#endif
        r6.l = lo(SEQSTAT_EXCAUSE);
        r6.h = hi(SEQSTAT_EXCAUSE);
        r7 = r7 & r6;
@@ -319,19 +542,19 @@ ENTRY(_kernel_execve)
        p0 = sp;
        r3 = SIZEOF_PTREGS / 4;
        r4 = 0(x);
-0:
+.Lclear_regs:
        [p0++] = r4;
        r3 += -1;
        cc = r3 == 0;
-       if !cc jump 0b (bp);
+       if !cc jump .Lclear_regs (bp);
 
        p0 = sp;
        sp += -16;
        [sp + 12] = p0;
-       call _do_execve;
+       pseudo_long_call _do_execve, p5;
        SP += 16;
        cc = r0 == 0;
-       if ! cc jump 1f;
+       if ! cc jump .Lexecve_failed;
        /* Success.  Copy our temporary pt_regs to the top of the kernel
         * stack and do a normal exception return.
         */
@@ -347,12 +570,12 @@ ENTRY(_kernel_execve)
        p0 = fp;
        r4 = [p0--];
        r3 = SIZEOF_PTREGS / 4;
-0:
+.Lcopy_regs:
        r4 = [p0--];
        [p1--] = r4;
        r3 += -1;
        cc = r3 == 0;
-       if ! cc jump 0b (bp);
+       if ! cc jump .Lcopy_regs (bp);
 
        r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
        p1 = r0;
@@ -364,7 +587,7 @@ ENTRY(_kernel_execve)
 
        RESTORE_CONTEXT;
        rti;
-1:
+.Lexecve_failed:
        unlink;
        rts;
 ENDPROC(_kernel_execve)
@@ -389,6 +612,19 @@ ENTRY(_system_call)
        p2 = [p2];
 
        [p2+(TASK_THREAD+THREAD_KSP)] = sp;
+#ifdef CONFIG_IPIPE
+       r0 = sp;
+       SP += -12;
+       call ___ipipe_syscall_root;
+       SP += 12;
+       cc = r0 == 1;
+       if cc jump .Lsyscall_really_exit;
+       cc = r0 == -1;
+       if cc jump .Lresume_userspace;
+       r3 = [sp + PT_R3];
+       r4 = [sp + PT_R4];
+       p0 = [sp + PT_ORIG_P0];
+#endif /* CONFIG_IPIPE */
 
        /* Check the System Call */
        r7 = __NR_syscall;
@@ -443,15 +679,32 @@ ENTRY(_system_call)
        r7 =  r7 & r4;
 
 .Lsyscall_resched:
+#ifdef CONFIG_IPIPE
+       cc = BITTST(r7, TIF_IRQ_SYNC);
+       if !cc jump .Lsyscall_no_irqsync;
+       /*
+        * Clear IPEND[4] manually to undo what resume_userspace_1 just did;
+        * we need this so that high priority domain interrupts may still
+        * preempt the current domain while the pipeline log is being played
+        * back.
+        */
+       [--sp] = reti;
+       SP += 4; /* don't merge with next insn to keep the pattern obvious */
+       SP += -12;
+       call ___ipipe_sync_root;
+       SP += 12;
+       jump .Lresume_userspace_1;
+.Lsyscall_no_irqsync:
+#endif
        cc = BITTST(r7, TIF_NEED_RESCHED);
        if !cc jump .Lsyscall_sigpending;
 
        /* Reenable interrupts.  */
        [--sp] = reti;
-       r0 = [sp++];
+       sp += 4;
 
        SP += -12;
-       call _schedule;
+       pseudo_long_call _schedule, p4;
        SP += 12;
 
        jump .Lresume_userspace_1;
@@ -460,15 +713,17 @@ ENTRY(_system_call)
        cc = BITTST(r7, TIF_RESTORE_SIGMASK);
        if cc jump .Lsyscall_do_signals;
        cc = BITTST(r7, TIF_SIGPENDING);
+       if cc jump .Lsyscall_do_signals;
+       cc = BITTST(r7, TIF_NOTIFY_RESUME);
        if !cc jump .Lsyscall_really_exit;
 .Lsyscall_do_signals:
        /* Reenable interrupts.  */
        [--sp] = reti;
-       r0 = [sp++];
+       sp += 4;
 
        r0 = sp;
        SP += -12;
-       call _do_signal;
+       pseudo_long_call _do_notify_resume, p5;
        SP += 12;
 
 .Lsyscall_really_exit:
@@ -477,8 +732,11 @@ ENTRY(_system_call)
        rts;
 ENDPROC(_system_call)
 
+/* Do not mark as ENTRY() to avoid error in assembler ...
+ * this symbol need not be global anyways, so ...
+ */
 _sys_trace:
-       call _syscall_trace;
+       pseudo_long_call _syscall_trace, p5;
 
        /* Execute the appropriate system call */
 
@@ -502,7 +760,7 @@ _sys_trace:
        SP += 24;
        [sp + PT_R0] = r0;
 
-       call _syscall_trace;
+       pseudo_long_call _syscall_trace, p5;
        jump .Lresume_userspace;
 ENDPROC(_sys_trace)
 
@@ -557,6 +815,15 @@ _new_old_task:
 ENDPROC(_resume)
 
 ENTRY(_ret_from_exception)
+#ifdef CONFIG_IPIPE
+       p2.l = _ipipe_percpu_domain;
+       p2.h = _ipipe_percpu_domain;
+       r0.l = _ipipe_root;
+       r0.h = _ipipe_root;
+       r2 = [p2];
+       cc = r0 == r2;
+       if !cc jump 4f;  /* not on behalf of the root domain, get out */
+#endif /* CONFIG_IPIPE */
        p2.l = lo(IPEND);
        p2.h = hi(IPEND);
 
@@ -565,9 +832,7 @@ ENTRY(_ret_from_exception)
        [sp + PT_IPEND] = r0;
 
 1:
-       r1 = 0x37(Z);
-       r2 = ~r1;
-       r2.h = 0;
+       r2 = LO(~0x37) (Z);
        r0 = r2 & r0;
        cc = r0 == 0;
        if !cc jump 4f; /* if not return to user mode, get out */
@@ -606,15 +871,32 @@ ENTRY(_ret_from_exception)
        p1.h = _schedule_and_signal;
        [p0] = p1;
        csync;
-       raise 15;               /* raise evt14 to do signal or reschedule */
+       raise 15;               /* raise evt15 to do signal or reschedule */
 4:
        r0 = syscfg;
-       bitclr(r0, 0);
+       bitclr(r0, SYSCFG_SSSTEP_P);            /* Turn off single step */
        syscfg = r0;
 5:
        rts;
 ENDPROC(_ret_from_exception)
 
+#ifdef CONFIG_IPIPE
+
+_resume_kernel_from_int:
+       r0.l = ___ipipe_sync_root;
+       r0.h = ___ipipe_sync_root;
+       [--sp] = rets;
+       [--sp] = ( r7:4, p5:3 );
+       SP += -12;
+       call ___ipipe_call_irqtail
+       SP += 12;
+       ( r7:4, p5:3 ) = [sp++];
+       rets = [sp++];
+       rts
+#else
+#define _resume_kernel_from_int         2f
+#endif
+
 ENTRY(_return_from_int)
        /* If someone else already raised IRQ 15, do nothing.  */
        csync;
@@ -636,7 +918,7 @@ ENTRY(_return_from_int)
        r1 = r0 - r1;
        r2 = r0 & r1;
        cc = r2 == 0;
-       if !cc jump 2f;
+       if !cc jump _resume_kernel_from_int;
 
        /* Lower the interrupt level to 15.  */
        p0.l = lo(EVT15);
@@ -645,9 +927,9 @@ ENTRY(_return_from_int)
        p1.h = _schedule_and_signal_from_int;
        [p0] = p1;
        csync;
-#if ANOMALY_05000281
-       r0.l = lo(CONFIG_BOOT_LOAD);
-       r0.h = hi(CONFIG_BOOT_LOAD);
+#if ANOMALY_05000281 || ANOMALY_05000461
+       r0.l = lo(SAFE_USER_INSTRUCTION);
+       r0.h = hi(SAFE_USER_INSTRUCTION);
        reti = r0;
 #endif
        r0 = 0x801f (z);
@@ -659,18 +941,27 @@ ENTRY(_return_from_int)
 ENDPROC(_return_from_int)
 
 ENTRY(_lower_to_irq14)
-#if ANOMALY_05000281
-       r0.l = lo(CONFIG_BOOT_LOAD);
-       r0.h = hi(CONFIG_BOOT_LOAD);
+#if ANOMALY_05000281 || ANOMALY_05000461
+       r0.l = lo(SAFE_USER_INSTRUCTION);
+       r0.h = hi(SAFE_USER_INSTRUCTION);
        reti = r0;
 #endif
-       r0 = 0x401f;
+
+#ifdef CONFIG_DEBUG_HWERR
+       /* enable irq14 & hwerr interrupt, until we transition to _evt_evt14 */
+       r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#else
+       /* Only enable irq14 interrupt, until we transition to _evt_evt14 */
+       r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#endif
        sti r0;
        raise 14;
        rti;
-ENTRY(_evt14_softirq)
+ENDPROC(_lower_to_irq14)
+
+ENTRY(_evt_evt14)
 #ifdef CONFIG_DEBUG_HWERR
-       r0 = 0x3f;
+       r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
        sti r0;
 #else
        cli r0;
@@ -678,8 +969,9 @@ ENTRY(_evt14_softirq)
        [--sp] = RETI;
        SP += 4;
        rts;
+ENDPROC(_evt_evt14)
 
-_schedule_and_signal_from_int:
+ENTRY(_schedule_and_signal_from_int)
        /* To end up here, vector 15 was changed - so we have to change it
         * back.
         */
@@ -697,18 +989,31 @@ _schedule_and_signal_from_int:
        p1 = rets;
        [sp + PT_RESERVED] = p1;
 
-       p0.l = _irq_flags;
-       p0.h = _irq_flags;
+#ifdef CONFIG_SMP
+       GET_PDA(p0, r0);        /* Fetch current PDA (can't migrate to other CPU here) */
+       r0 = [p0 + PDA_IRQFLAGS];
+#else
+       p0.l = _bfin_irq_flags;
+       p0.h = _bfin_irq_flags;
        r0 = [p0];
+#endif
        sti r0;
 
+       /* finish the userspace "atomic" functions for it */
+       r1 = FIXED_CODE_END;
+       r2 = [sp + PT_PC];
+       cc = r1 <= r2;
+       if cc jump .Lresume_userspace (bp);
+
        r0 = sp;
        sp += -12;
-       call _finish_atomic_sections;
+
+       pseudo_long_call _finish_atomic_sections, p5;
        sp += 12;
        jump.s .Lresume_userspace;
+ENDPROC(_schedule_and_signal_from_int)
 
-_schedule_and_signal:
+ENTRY(_schedule_and_signal)
        SAVE_CONTEXT_SYSCALL
        /* To end up here, vector 15 was changed - so we have to change it
         * back.
@@ -726,21 +1031,7 @@ _schedule_and_signal:
 1:
        RESTORE_CONTEXT
        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)
+ENDPROC(_schedule_and_signal)
 
 /* We handle this 100% in exception space - to reduce overhead
  * Only potiential problem is if the software buffer gets swapped out of the
@@ -795,13 +1086,14 @@ ENTRY(_ex_trace_buff_full)
        LC0 = [sp++];
        P2 = [sp++];
        P3 = [sp++];
-       jump _return_from_exception;
+       jump _bfin_return_from_exception;
+ENDPROC(_ex_trace_buff_full)
 
 #if CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN == 4
 .data
 #else
 .section .l1.data.B
-#endif
+#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN */
 ENTRY(_trace_buff_offset)
         .long 0;
 ALIGN
@@ -809,7 +1101,44 @@ ENTRY(_software_trace_buff)
        .rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256);
        .long 0
        .endr
-#endif
+#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND */
+
+#if CONFIG_EARLY_PRINTK
+__INIT
+ENTRY(_early_trap)
+       SAVE_ALL_SYS
+       trace_buffer_stop(p0,r0);
+
+       ANOMALY_283_315_WORKAROUND(p4, r5)
+
+       /* 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);
+       CSYNC;          /* Disabling of CPLBs should be proceeded by a CSYNC */
+       [P4] = R5;
+       SSYNC;
+
+       P4.L = LO(DMEM_CONTROL);
+       P4.H = HI(DMEM_CONTROL);
+       R5 = [P4];
+       BITCLR(R5,ENDCPLB_P);
+       CSYNC;          /* Disabling of CPLBs should be proceeded by a CSYNC */
+       [P4] = R5;
+       SSYNC;
+
+       r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
+       r1 = RETX;
+
+       SP += -12;
+       call _early_trap_c;
+       SP += 12;
+ENDPROC(_early_trap)
+__FINIT
+#endif /* CONFIG_EARLY_PRINTK */
 
 /*
  * Put these in the kernel data section - that should always be covered by
@@ -821,16 +1150,22 @@ ENTRY(_software_trace_buff)
 #else
 .data
 #endif
+
 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_trap_c        /* 0x01 - User Defined - Software breakpoint */
+#ifdef CONFIG_KGDB
+       .long _ex_trap_c        /* 0x02 - User Defined - KGDB initial connection
+                                                        and break signal trap */
+#else
        .long _ex_replaceable   /* 0x02 - User Defined */
+#endif
        .long _ex_trap_c        /* 0x03 - User Defined - userspace stack overflow */
-       .long _ex_replaceable   /* 0x04 - User Defined */
+       .long _ex_trap_c        /* 0x04 - User Defined - dump trace buffer */
        .long _ex_replaceable   /* 0x05 - User Defined */
        .long _ex_replaceable   /* 0x06 - User Defined */
        .long _ex_replaceable   /* 0x07 - User Defined */
@@ -865,16 +1200,16 @@ ENTRY(_ex_table)
        .long _ex_trap_c        /* 0x20 - Reserved */
        .long _ex_trap_c        /* 0x21 - Undefined Instruction */
        .long _ex_trap_c        /* 0x22 - Illegal Instruction Combination */
-       .long _ex_dcplb         /* 0x23 - Data CPLB Protection Violation */
+       .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_dcplb         /* 0x26 - Data CPLB Miss */
-       .long _ex_trap_c        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero */
+       .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_icplb         /* 0x2B - Instruction CPLB protection Violation */
-       .long _ex_icplb         /* 0x2C - Instruction CPLB miss */
+       .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 */
@@ -1023,7 +1358,7 @@ ENTRY(_sys_call_table)
        .long _sys_newuname
        .long _sys_ni_syscall   /* old sys_modify_ldt */
        .long _sys_adjtimex
-       .long _sys_ni_syscall   /* 125 */ /* sys_mprotect */
+       .long _sys_mprotect     /* 125 */
        .long _sys_ni_syscall   /* old sys_sigprocmask */
        .long _sys_ni_syscall   /* old "creat_module" */
        .long _sys_init_module
@@ -1042,16 +1377,16 @@ ENTRY(_sys_call_table)
        .long _sys_getdents
        .long _sys_ni_syscall   /* sys_select */
        .long _sys_flock
-       .long _sys_ni_syscall   /* sys_msync */
+       .long _sys_msync
        .long _sys_readv                /* 145 */
        .long _sys_writev
        .long _sys_getsid
        .long _sys_fdatasync
        .long _sys_sysctl
-       .long _sys_ni_syscall   /* 150 */ /* sys_mlock */
-       .long _sys_ni_syscall   /* sys_munlock */
-       .long _sys_ni_syscall   /* sys_mlockall */
-       .long _sys_ni_syscall   /* sys_munlockall */
+       .long _sys_mlock        /* 150 */
+       .long _sys_munlock
+       .long _sys_mlockall
+       .long _sys_munlockall
        .long _sys_sched_setparam
        .long _sys_sched_getparam /* 155 */
        .long _sys_sched_setscheduler
@@ -1090,7 +1425,7 @@ ENTRY(_sys_call_table)
        .long _sys_ni_syscall   /* streams2 */
        .long _sys_vfork                /* 190 */
        .long _sys_getrlimit
-       .long _sys_mmap2
+       .long _sys_mmap_pgoff
        .long _sys_truncate64
        .long _sys_ftruncate64
        .long _sys_stat64       /* 195 */
@@ -1116,8 +1451,8 @@ ENTRY(_sys_call_table)
        .long _sys_setfsuid     /* 215 */
        .long _sys_setfsgid
        .long _sys_pivot_root
-       .long _sys_ni_syscall   /* sys_mincore */
-       .long _sys_ni_syscall   /* sys_madvise */
+       .long _sys_mincore
+       .long _sys_madvise
        .long _sys_getdents64   /* 220 */
        .long _sys_fcntl64
        .long _sys_ni_syscall   /* reserved for TUX */
@@ -1173,7 +1508,7 @@ ENTRY(_sys_call_table)
        .long _sys_utimes
        .long _sys_fadvise64_64
        .long _sys_ni_syscall /* vserver */
-       .long _sys_ni_syscall /* 275, mbind */
+       .long _sys_mbind        /* 275 */
        .long _sys_ni_syscall /* get_mempolicy */
        .long _sys_ni_syscall /* set_mempolicy */
        .long _sys_mq_open
@@ -1247,7 +1582,7 @@ ENTRY(_sys_call_table)
        .long _sys_epoll_pwait
        .long _sys_utimensat
        .long _sys_signalfd
-       .long _sys_timerfd
+       .long _sys_timerfd_create
        .long _sys_eventfd      /* 350 */
        .long _sys_pread64
        .long _sys_pwrite64
@@ -1255,34 +1590,22 @@ ENTRY(_sys_call_table)
        .long _sys_set_robust_list
        .long _sys_get_robust_list      /* 355 */
        .long _sys_fallocate
+       .long _sys_semtimedop
+       .long _sys_timerfd_settime
+       .long _sys_timerfd_gettime
+       .long _sys_signalfd4            /* 360 */
+       .long _sys_eventfd2
+       .long _sys_epoll_create1
+       .long _sys_dup3
+       .long _sys_pipe2
+       .long _sys_inotify_init1        /* 365 */
+       .long _sys_preadv
+       .long _sys_pwritev
+       .long _sys_rt_tgsigqueueinfo
+       .long _sys_perf_event_open
+       .long _sys_recvmmsg             /* 370 */
+
        .rept NR_syscalls-(.-_sys_call_table)/4
        .long _sys_ni_syscall
        .endr
-_excpt_saved_imask:
-       .long 0;
-
-_exception_stack:
-       .rept 1024
-       .long 0;
-       .endr
-_exception_stack_top:
-
-#if ANOMALY_05000261
-/* Used by the assembly entry point to work around an anomaly.  */
-_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)
-       .long 0;
-ENTRY(_out_ptr_excause)
-       .long 0;
-ALIGN
-ENTRY(_excause_circ_buf)
-       .rept 4
-       .long 0
-       .endr
+END(_sys_call_table)