Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[sfrench/cifs-2.6.git] / arch / microblaze / kernel / entry.S
index c0ede25c5b99ec305abd4d97fa774d249b36fda0..304882e56459b70d90b661622b54066452a38d74 100644 (file)
  */
 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
        .macro  clear_bip
-       msrclr  r11, MSR_BIP
-       nop
+       msrclr  r0, MSR_BIP
        .endm
 
        .macro  set_bip
-       msrset  r11, MSR_BIP
-       nop
+       msrset  r0, MSR_BIP
        .endm
 
        .macro  clear_eip
-       msrclr  r11, MSR_EIP
-       nop
+       msrclr  r0, MSR_EIP
        .endm
 
        .macro  set_ee
-       msrset  r11, MSR_EE
-       nop
+       msrset  r0, MSR_EE
        .endm
 
        .macro  disable_irq
-       msrclr  r11, MSR_IE
-       nop
+       msrclr  r0, MSR_IE
        .endm
 
        .macro  enable_irq
-       msrset  r11, MSR_IE
-       nop
+       msrset  r0, MSR_IE
        .endm
 
        .macro  set_ums
-       msrset  r11, MSR_UMS
-       nop
-       msrclr  r11, MSR_VMS
-       nop
+       msrset  r0, MSR_UMS
+       msrclr  r0, MSR_VMS
        .endm
 
        .macro  set_vms
-       msrclr  r11, MSR_UMS
-       nop
-       msrset  r11, MSR_VMS
-       nop
+       msrclr  r0, MSR_UMS
+       msrset  r0, MSR_VMS
+       .endm
+
+       .macro  clear_ums
+       msrclr  r0, MSR_UMS
        .endm
 
        .macro  clear_vms_ums
-       msrclr  r11, MSR_VMS
-       nop
-       msrclr  r11, MSR_UMS
-       nop
+       msrclr  r0, MSR_VMS | MSR_UMS
        .endm
 #else
        .macro  clear_bip
        mfs     r11, rmsr
-       nop
        andi    r11, r11, ~MSR_BIP
        mts     rmsr, r11
-       nop
        .endm
 
        .macro  set_bip
        mfs     r11, rmsr
-       nop
        ori     r11, r11, MSR_BIP
        mts     rmsr, r11
-       nop
        .endm
 
        .macro  clear_eip
        mfs     r11, rmsr
-       nop
        andi    r11, r11, ~MSR_EIP
        mts     rmsr, r11
-       nop
        .endm
 
        .macro  set_ee
        mfs     r11, rmsr
-       nop
        ori     r11, r11, MSR_EE
        mts     rmsr, r11
-       nop
        .endm
 
        .macro  disable_irq
        mfs     r11, rmsr
-       nop
        andi    r11, r11, ~MSR_IE
        mts     rmsr, r11
-       nop
        .endm
 
        .macro  enable_irq
        mfs     r11, rmsr
-       nop
        ori     r11, r11, MSR_IE
        mts     rmsr, r11
-       nop
        .endm
 
        .macro set_ums
        mfs     r11, rmsr
-       nop
        ori     r11, r11, MSR_VMS
        andni   r11, r11, MSR_UMS
        mts     rmsr, r11
-       nop
        .endm
 
        .macro  set_vms
        mfs     r11, rmsr
-       nop
        ori     r11, r11, MSR_VMS
        andni   r11, r11, MSR_UMS
        mts     rmsr, r11
-       nop
+       .endm
+
+       .macro  clear_ums
+       mfs     r11, rmsr
+       andni   r11, r11, MSR_UMS
+       mts     rmsr,r11
        .endm
 
        .macro  clear_vms_ums
        mfs     r11, rmsr
-       nop
        andni   r11, r11, (MSR_VMS|MSR_UMS)
        mts     rmsr,r11
-       nop
        .endm
 #endif
 
 
 /* turn on virtual protected mode save */
 #define VM_ON          \
-       set_ums;                \
+       set_ums;        \
        rted    r0, 2f; \
-2: nop;
+       nop; \
+2:
 
 /* turn off virtual protected mode save and user mode save*/
 #define VM_OFF                 \
-       clear_vms_ums;                  \
+       clear_vms_ums;          \
        rted    r0, TOPHYS(1f); \
-1: nop;
+       nop; \
+1:
 
 #define SAVE_REGS \
        swi     r2, r1, PTO+PT_R2;      /* Save SDA */                  \
+       swi     r3, r1, PTO+PT_R3;                                      \
+       swi     r4, r1, PTO+PT_R4;                                      \
        swi     r5, r1, PTO+PT_R5;                                      \
        swi     r6, r1, PTO+PT_R6;                                      \
        swi     r7, r1, PTO+PT_R7;                                      \
        swi     r30, r1, PTO+PT_R30;                                    \
        swi     r31, r1, PTO+PT_R31;    /* Save current task reg */     \
        mfs     r11, rmsr;              /* save MSR */                  \
-       nop;                                                            \
        swi     r11, r1, PTO+PT_MSR;
 
 #define RESTORE_REGS \
        lwi     r11, r1, PTO+PT_MSR;                                    \
        mts     rmsr , r11;                                             \
-       nop;                                                            \
        lwi     r2, r1, PTO+PT_R2;      /* restore SDA */               \
+       lwi     r3, r1, PTO+PT_R3;                                      \
+       lwi     r4, r1, PTO+PT_R4;                                      \
        lwi     r5, r1, PTO+PT_R5;                                      \
        lwi     r6, r1, PTO+PT_R6;                                      \
        lwi     r7, r1, PTO+PT_R7;                                      \
        lwi     r30, r1, PTO+PT_R30;                                    \
        lwi     r31, r1, PTO+PT_R31;    /* Restore cur task reg */
 
+#define SAVE_STATE     \
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */     \
+       /* See if already in kernel mode.*/                             \
+       mfs     r1, rmsr;                                               \
+       andi    r1, r1, MSR_UMS;                                        \
+       bnei    r1, 1f;                                         \
+       /* Kernel-mode state save.  */                                  \
+       /* Reload kernel stack-ptr. */                                  \
+       lwi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP));                      \
+       /* FIXME: I can add these two lines to one */                   \
+       /* tophys(r1,r1); */                                            \
+       /* addik        r1, r1, -STATE_SAVE_SIZE; */                    \
+       addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
+       SAVE_REGS                                                       \
+       brid    2f;                                                     \
+       swi     r1, r1, PTO+PT_MODE;                                    \
+1:     /* User-mode state save.  */                                    \
+       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+       tophys(r1,r1);                                                  \
+       lwi     r1, r1, TS_THREAD_INFO; /* get the thread info */       \
+       /* MS these three instructions can be added to one */           \
+       /* addik        r1, r1, THREAD_SIZE; */                         \
+       /* tophys(r1,r1); */                                            \
+       /* addik        r1, r1, -STATE_SAVE_SIZE; */                    \
+       addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
+       SAVE_REGS                                                       \
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));                     \
+       swi     r11, r1, PTO+PT_R1; /* Store user SP.  */               \
+       swi     r0, r1, PTO + PT_MODE; /* Was in user-mode.  */         \
+       /* MS: I am clearing UMS even in case when I come from kernel space */ \
+       clear_ums;                                                      \
+2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+
 .text
 
 /*
  * are masked. This is nice, means we don't have to CLI before state save
  */
 C_ENTRY(_user_exception):
-       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
        addi    r14, r14, 4     /* return address is 4 byte after call */
-       swi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
-
-       lwi     r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
-       beqi    r11, 1f;                /* Jump ahead if coming from user */
-/* Kernel-mode state save. */
-       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
-       tophys(r1,r11);
-       swi     r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
-       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
-
-       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */
-       SAVE_REGS
-
-       addi    r11, r0, 1;             /* Was in kernel-mode. */
-       swi     r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */
-       brid    2f;
-       nop;                            /* Fill delay slot */
+       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
 
-/* User-mode state save.  */
-1:
-       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
        lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
        tophys(r1,r1);
        lwi     r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
-/* calculate kernel stack pointer from task struct 8k */
-       addik   r1, r1, THREAD_SIZE;
-       tophys(r1,r1);
-
-       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+       /* MS these three instructions can be added to one */
+       /* addik        r1, r1, THREAD_SIZE; */
+       /* tophys(r1,r1); */
+       /* addik        r1, r1, -STATE_SAVE_SIZE; */
+       addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
        SAVE_REGS
 
-       swi     r0, r1, PTO+PT_MODE;                    /* Was in user-mode. */
        lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
        swi     r11, r1, PTO+PT_R1;             /* Store user SP.  */
-       addi    r11, r0, 1;
-       swi     r11, r0, TOPHYS(PER_CPU(KM));   /* Now we're in kernel-mode.  */
-2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+       clear_ums;
+       lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
        /* Save away the syscall number.  */
        swi     r12, r1, PTO+PT_R0;
        tovirt(r1,r1)
@@ -316,10 +310,8 @@ C_ENTRY(_user_exception):
  * register should point to the location where
  * the called function should return.  [note that MAKE_SYS_CALL uses label 1] */
 
-       # Step into virtual mode.
-       set_vms;
-       addik   r11, r0, 3f
-       rtid    r11, 0
+       /* Step into virtual mode */
+       rtbd    r0, 3f
        nop
 3:
        lwi     r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */
@@ -363,24 +355,17 @@ C_ENTRY(_user_exception):
        # Find and jump into the syscall handler.
        lwi     r12, r12, sys_call_table
        /* where the trap should return need -8 to adjust for rtsd r15, 8 */
-       la      r15, r0, ret_from_trap-8
+       addi    r15, r0, ret_from_trap-8
        bra     r12
 
        /* The syscall number is invalid, return an error.  */
 5:
+       rtsd    r15, 8;         /* looks like a normal subroutine return */
        addi    r3, r0, -ENOSYS;
-       rtsd    r15,8;          /* looks like a normal subroutine return */
-       or      r0, r0, r0
-
 
 /* Entry point used to return from a syscall/trap */
 /* We re-enable BIP bit before state restore */
 C_ENTRY(ret_from_trap):
-       set_bip;                        /*  Ints masked for state restore*/
-       lwi     r11, r1, PTO+PT_MODE;
-/* See if returning to kernel mode, if so, skip resched &c.  */
-       bnei    r11, 2f;
-
        swi     r3, r1, PTO + PT_R3
        swi     r4, r1, PTO + PT_R4
 
@@ -413,32 +398,19 @@ C_ENTRY(ret_from_trap):
        andi    r11, r11, _TIF_SIGPENDING;
        beqi    r11, 1f;                /* Signals to handle, handle them */
 
-       la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
+       addik   r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
        addi    r7, r0, 1;              /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
        add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
 
 /* Finally, return to user state.  */
-1:
-       lwi     r3, r1, PTO + PT_R3; /* restore syscall result */
-       lwi     r4, r1, PTO + PT_R4;
-
-       swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
+1:     set_bip;                        /*  Ints masked for state restore */
        swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
        RESTORE_REGS;
        addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
        lwi     r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
-       bri     6f;
-
-/* Return to kernel state.  */
-2:     VM_OFF;
-       tophys(r1,r1);
-       RESTORE_REGS;
-       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
-       tovirt(r1,r1);
-6:
 TRAP_return:           /* Make global symbol for debugging */
        rtbd    r14, 0; /* Instructions to return from an IRQ */
        nop;
@@ -450,12 +422,11 @@ TRAP_return:              /* Make global symbol for debugging */
 C_ENTRY(sys_fork_wrapper):
        addi    r5, r0, SIGCHLD                 /* Arg 0: flags */
        lwi     r6, r1, PTO+PT_R1       /* Arg 1: child SP (use parent's) */
-       la      r7, r1, PTO                     /* Arg 2: parent context */
+       addik   r7, r1, PTO                     /* Arg 2: parent context */
        add     r8. r0, r0                      /* Arg 3: (unused) */
        add     r9, r0, r0;                     /* Arg 4: (unused) */
-       add     r10, r0, r0;                    /* Arg 5: (unused) */
        brid    do_fork         /* Do real work (tail-call) */
-       nop;
+       add     r10, r0, r0;                    /* Arg 5: (unused) */
 
 /* This the initial entry point for a new child thread, with an appropriate
    stack in place that makes it look the the child is in the middle of an
@@ -466,35 +437,31 @@ C_ENTRY(ret_from_fork):
        bralid  r15, schedule_tail; /* ...which is schedule_tail's arg */
        add     r3, r5, r0;     /* switch_thread returns the prev task */
                                /* ( in the delay slot ) */
-       add     r3, r0, r0;     /* Child's fork call should return 0. */
        brid    ret_from_trap;  /* Do normal trap return */
-       nop;
+       add     r3, r0, r0;     /* Child's fork call should return 0. */
 
 C_ENTRY(sys_vfork):
        brid    microblaze_vfork        /* Do real work (tail-call) */
-       la      r5, r1, PTO
+       addik   r5, r1, PTO
 
 C_ENTRY(sys_clone):
        bnei    r6, 1f;                 /* See if child SP arg (arg 1) is 0. */
-       lwi     r6, r1, PTO+PT_R1;      /* If so, use paret's stack ptr */
-1:     la      r7, r1, PTO;                    /* Arg 2: parent context */
+       lwi     r6, r1, PTO + PT_R1;    /* If so, use paret's stack ptr */
+1:     addik   r7, r1, PTO;                    /* Arg 2: parent context */
        add     r8, r0, r0;                     /* Arg 3: (unused) */
        add     r9, r0, r0;                     /* Arg 4: (unused) */
-       add     r10, r0, r0;                    /* Arg 5: (unused) */
        brid    do_fork         /* Do real work (tail-call) */
-       nop;
+       add     r10, r0, r0;                    /* Arg 5: (unused) */
 
 C_ENTRY(sys_execve):
-       la      r8, r1, PTO;            /* add user context as 4th arg */
        brid    microblaze_execve;      /* Do real work (tail-call).*/
-       nop;
+       addik   r8, r1, PTO;            /* add user context as 4th arg */
 
 C_ENTRY(sys_rt_sigreturn_wrapper):
        swi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
        swi     r4, r1, PTO+PT_R4;
-       la      r5, r1, PTO;            /* add user context as 1st arg */
        brlid   r15, sys_rt_sigreturn   /* Do real work */
-       nop;
+       addik   r5, r1, PTO;            /* add user context as 1st arg */
        lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
        lwi     r4, r1, PTO+PT_R4;
        bri ret_from_trap /* fall through will not work here due to align */
@@ -503,83 +470,23 @@ C_ENTRY(sys_rt_sigreturn_wrapper):
 /*
  * HW EXCEPTION rutine start
  */
-
-#define SAVE_STATE     \
-       swi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */  \
-       set_bip;        /*equalize initial state for all possible entries*/\
-       clear_eip;                                                      \
-       enable_irq;                                                     \
-       set_ee;                                                         \
-       /* See if already in kernel mode.*/                             \
-       lwi     r11, r0, TOPHYS(PER_CPU(KM));                           \
-       beqi    r11, 1f;                /* Jump ahead if coming from user */\
-       /* Kernel-mode state save.  */                                  \
-       /* Reload kernel stack-ptr. */                                  \
-       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));                     \
-       tophys(r1,r11);                                                 \
-       swi     r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */       \
-       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
-       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */\
-       /* store return registers separately because                    \
-        * this macros is use for others exceptions */                  \
-       swi     r3, r1, PTO + PT_R3;                                    \
-       swi     r4, r1, PTO + PT_R4;                                    \
-       SAVE_REGS                                                       \
-       /* PC, before IRQ/trap - this is one instruction above */       \
-       swi     r17, r1, PTO+PT_PC;                                     \
-                                                                       \
-       addi    r11, r0, 1;             /* Was in kernel-mode.  */      \
-       swi     r11, r1, PTO+PT_MODE;                                   \
-       brid    2f;                                                     \
-       nop;                            /* Fill delay slot */           \
-1:     /* User-mode state save.  */                                    \
-       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\
-       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
-       tophys(r1,r1);                                                  \
-       lwi     r1, r1, TS_THREAD_INFO; /* get the thread info */       \
-       addik   r1, r1, THREAD_SIZE;    /* calculate kernel stack pointer */\
-       tophys(r1,r1);                                                  \
-                                                                       \
-       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */\
-       /* store return registers separately because this macros        \
-        * is use for others exceptions */                              \
-       swi     r3, r1, PTO + PT_R3;                                    \
-       swi     r4, r1, PTO + PT_R4;                                    \
-       SAVE_REGS                                                       \
-       /* PC, before IRQ/trap - this is one instruction above FIXME*/  \
-       swi     r17, r1, PTO+PT_PC;                                     \
-                                                                       \
-       swi     r0, r1, PTO+PT_MODE; /* Was in user-mode.  */           \
-       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));                     \
-       swi     r11, r1, PTO+PT_R1; /* Store user SP.  */               \
-       addi    r11, r0, 1;                                             \
-       swi     r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\
-2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));        \
-       /* Save away the syscall number.  */                            \
-       swi     r0, r1, PTO+PT_R0;                                      \
-       tovirt(r1,r1)
-
 C_ENTRY(full_exception_trap):
-       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
        /* adjust exception address for privileged instruction
         * for finding where is it */
        addik   r17, r17, -4
        SAVE_STATE /* Save registers */
+       /* PC, before IRQ/trap - this is one instruction above */
+       swi     r17, r1, PTO+PT_PC;
+       tovirt(r1,r1)
        /* FIXME this can be store directly in PT_ESR reg.
         * I tested it but there is a fault */
        /* where the trap should return need -8 to adjust for rtsd r15, 8 */
-       la      r15, r0, ret_from_exc - 8
-       la      r5, r1, PTO              /* parameter struct pt_regs * regs */
+       addik   r15, r0, ret_from_exc - 8
        mfs     r6, resr
-       nop
        mfs     r7, rfsr;               /* save FSR */
-       nop
        mts     rfsr, r0;       /* Clear sticky fsr */
-       nop
-       la      r12, r0, full_exception
-       set_vms;
-       rtbd    r12, 0;
-       nop;
+       rted    r0, full_exception
+       addik   r5, r1, PTO              /* parameter struct pt_regs * regs */
 
 /*
  * Unaligned data trap.
@@ -592,19 +499,27 @@ C_ENTRY(full_exception_trap):
  * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S"
  */
 C_ENTRY(unaligned_data_trap):
-       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
+       /* MS: I have to save r11 value and then restore it because
+        * set_bit, clear_eip, set_ee use r11 as temp register if MSR
+        * instructions are not used. We don't need to do if MSR instructions
+        * are used and they use r0 instead of r11.
+        * I am using ENTRY_SP which should be primary used only for stack
+        * pointer saving. */
+       swi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+       set_bip;        /* equalize initial state for all possible entries */
+       clear_eip;
+       set_ee;
+       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
        SAVE_STATE              /* Save registers.*/
+       /* PC, before IRQ/trap - this is one instruction above */
+       swi     r17, r1, PTO+PT_PC;
+       tovirt(r1,r1)
        /* where the trap should return need -8 to adjust for rtsd r15, 8 */
-       la      r15, r0, ret_from_exc-8
+       addik   r15, r0, ret_from_exc-8
        mfs     r3, resr                /* ESR */
-       nop
        mfs     r4, rear                /* EAR */
-       nop
-       la      r7, r1, PTO             /* parameter struct pt_regs * regs */
-       la      r12, r0, _unaligned_data_exception
-       set_vms;
-       rtbd    r12, 0; /* interrupts enabled */
-       nop;
+       rtbd    r0, _unaligned_data_exception
+       addik   r7, r1, PTO             /* parameter struct pt_regs * regs */
 
 /*
  * Page fault traps.
@@ -625,38 +540,32 @@ C_ENTRY(unaligned_data_trap):
  */
 /* data and intruction trap - which is choose is resolved int fault.c */
 C_ENTRY(page_fault_data_trap):
-       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
        SAVE_STATE              /* Save registers.*/
+       /* PC, before IRQ/trap - this is one instruction above */
+       swi     r17, r1, PTO+PT_PC;
+       tovirt(r1,r1)
        /* where the trap should return need -8 to adjust for rtsd r15, 8 */
-       la      r15, r0, ret_from_exc-8
-       la      r5, r1, PTO             /* parameter struct pt_regs * regs */
+       addik   r15, r0, ret_from_exc-8
        mfs     r6, rear                /* parameter unsigned long address */
-       nop
        mfs     r7, resr                /* parameter unsigned long error_code */
-       nop
-       la      r12, r0, do_page_fault
-       set_vms;
-       rtbd    r12, 0; /* interrupts enabled */
-       nop;
+       rted    r0, do_page_fault
+       addik   r5, r1, PTO             /* parameter struct pt_regs * regs */
 
 C_ENTRY(page_fault_instr_trap):
-       swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
        SAVE_STATE              /* Save registers.*/
+       /* PC, before IRQ/trap - this is one instruction above */
+       swi     r17, r1, PTO+PT_PC;
+       tovirt(r1,r1)
        /* where the trap should return need -8 to adjust for rtsd r15, 8 */
-       la      r15, r0, ret_from_exc-8
-       la      r5, r1, PTO             /* parameter struct pt_regs * regs */
+       addik   r15, r0, ret_from_exc-8
        mfs     r6, rear                /* parameter unsigned long address */
-       nop
        ori     r7, r0, 0               /* parameter unsigned long error_code */
-       la      r12, r0, do_page_fault
-       set_vms;
-       rtbd    r12, 0; /* interrupts enabled */
-       nop;
+       rted    r0, do_page_fault
+       addik   r5, r1, PTO             /* parameter struct pt_regs * regs */
 
 /* Entry point used to return from an exception.  */
 C_ENTRY(ret_from_exc):
-       set_bip;                        /*  Ints masked for state restore*/
-       lwi     r11, r1, PTO+PT_MODE;
+       lwi     r11, r1, PTO + PT_MODE;
        bnei    r11, 2f;                /* See if returning to kernel mode, */
                                        /* ... if so, skip resched &c.  */
 
@@ -687,32 +596,27 @@ C_ENTRY(ret_from_exc):
         * traps), but signal handlers may want to examine or change the
         * complete register state.  Here we save anything not saved by
         * the normal entry sequence, so that it may be safely restored
-        * (in a possibly modified form) after do_signal returns.
-        * store return registers separately because this macros is use
-        * for others exceptions */
-       la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
+        * (in a possibly modified form) after do_signal returns. */
+       addik   r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
        addi    r7, r0, 0;              /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
        add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
 
 /* Finally, return to user state.  */
-1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
+1:     set_bip;                        /* Ints masked for state restore */
        swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
 
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
        RESTORE_REGS;
        addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
 
        lwi     r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
        bri     6f;
 /* Return to kernel state.  */
-2:     VM_OFF;
+2:     set_bip;                        /* Ints masked for state restore */
+       VM_OFF;
        tophys(r1,r1);
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
        RESTORE_REGS;
        addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
 
@@ -736,36 +640,23 @@ C_ENTRY(_interrupt):
 /* MS: we are in physical address */
 /* Save registers, switch to proper stack, convert SP to virtual.*/
        swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
-       swi     r11, r0, TOPHYS(PER_CPU(R11_SAVE));
        /* MS: See if already in kernel mode. */
-       lwi     r11, r0, TOPHYS(PER_CPU(KM));
-       beqi    r11, 1f; /* MS: Jump ahead if coming from user */
+       mfs     r1, rmsr
+       nop
+       andi    r1, r1, MSR_UMS
+       bnei    r1, 1f
 
 /* Kernel-mode state save. */
-       or      r11, r1, r0
-       tophys(r1,r11); /* MS: I have in r1 physical address where stack is */
-/* MS: Save original SP - position PT_R1 to next stack frame 4 *1 - 152*/
-       swi     r11, r1, (PT_R1 - PT_SIZE);
-/* MS: restore r11 because of saving in SAVE_REGS */
-       lwi     r11, r0, TOPHYS(PER_CPU(R11_SAVE));
+       lwi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
+       tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
        /* save registers */
 /* MS: Make room on the stack -> activation record */
        addik   r1, r1, -STATE_SAVE_SIZE;
-/* MS: store return registers separately because
- * this macros is use for others exceptions */
-       swi     r3, r1, PTO + PT_R3;
-       swi     r4, r1, PTO + PT_R4;
        SAVE_REGS
-       /* MS: store mode */
-       addi    r11, r0, 1; /* MS: Was in kernel-mode. */
-       swi     r11, r1, PTO + PT_MODE; /* MS: and save it */
        brid    2f;
-       nop; /* MS: Fill delay slot */
-
+       swi     r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */
 1:
 /* User-mode state save. */
-/* MS: restore r11 -> FIXME move before SAVE_REG */
-       lwi     r11, r0, TOPHYS(PER_CPU(R11_SAVE));
  /* MS: get the saved current */
        lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
        tophys(r1,r1);
@@ -774,27 +665,18 @@ C_ENTRY(_interrupt):
        tophys(r1,r1);
        /* save registers */
        addik   r1, r1, -STATE_SAVE_SIZE;
-       swi     r3, r1, PTO+PT_R3;
-       swi     r4, r1, PTO+PT_R4;
        SAVE_REGS
        /* calculate mode */
        swi     r0, r1, PTO + PT_MODE;
        lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
        swi     r11, r1, PTO+PT_R1;
-       /* setup kernel mode to KM */
-       addi    r11, r0, 1;
-       swi     r11, r0, TOPHYS(PER_CPU(KM));
-
+       clear_ums;
 2:
        lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
-       swi     r0, r1, PTO + PT_R0;
        tovirt(r1,r1)
-       la      r5, r1, PTO;
-       set_vms;
-       la      r11, r0, do_IRQ;
-       la      r15, r0, irq_call;
-irq_call:rtbd  r11, 0;
-       nop;
+       addik   r15, r0, irq_call;
+irq_call:rtbd  r0, do_IRQ;
+       addik   r5, r1, PTO;
 
 /* MS: we are in virtual mode */
 ret_from_irq:
@@ -815,7 +697,7 @@ ret_from_irq:
        beqid   r11, no_intr_resched
 /* Handle a signal return; Pending signals should be in r18. */
        addi    r7, r0, 0; /* Arg 3: int in_syscall */
-       la      r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+       addik   r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
        bralid  r15, do_signal; /* Handle any signals */
        add     r6, r0, r0; /* Arg 2: sigset_t *oldset */
 
@@ -823,12 +705,9 @@ ret_from_irq:
 no_intr_resched:
     /* Disable interrupts, we are now committed to the state restore */
        disable_irq
-       swi     r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */
        swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
        VM_OFF;
        tophys(r1,r1);
-       lwi     r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
-       lwi     r4, r1, PTO + PT_R4;
        RESTORE_REGS
        addik   r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
        lwi     r1, r1, PT_R1 - PT_SIZE;
@@ -857,8 +736,6 @@ restore:
 #endif
        VM_OFF /* MS: turn off MMU */
        tophys(r1,r1)
-       lwi     r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */
-       lwi     r4, r1, PTO + PT_R4;
        RESTORE_REGS
        addik   r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
        tovirt(r1,r1);
@@ -868,86 +745,91 @@ IRQ_return: /* MS: Make global symbol for debugging */
        nop
 
 /*
- * `Debug' trap
- *  We enter dbtrap in "BIP" (breakpoint) mode.
- *  So we exit the breakpoint mode with an 'rtbd' and proceed with the
- *  original dbtrap.
- *  however, wait to save state first
+ * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18
+ * and call handling function with saved pt_regs
  */
 C_ENTRY(_debug_exception):
        /* BIP bit is set on entry, no interrupts can occur */
        swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP))
 
-       swi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */
-       set_bip;        /*equalize initial state for all possible entries*/
-       clear_eip;
-       enable_irq;
-       lwi     r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/
-       beqi    r11, 1f;                /* Jump ahead if coming from user */
-       /* Kernel-mode state save.  */
-       lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
-       tophys(r1,r11);
-       swi     r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */
-       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
+       mfs     r1, rmsr
+       nop
+       andi    r1, r1, MSR_UMS
+       bnei    r1, 1f
+/* MS: Kernel-mode state save - kgdb */
+       lwi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
 
-       addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
-       swi     r3, r1, PTO + PT_R3;
-       swi     r4, r1, PTO + PT_R4;
+       /* BIP bit is set on entry, no interrupts can occur */
+       addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
        SAVE_REGS;
+       /* save all regs to pt_reg structure */
+       swi     r0, r1, PTO+PT_R0;      /* R0 must be saved too */
+       swi     r14, r1, PTO+PT_R14     /* rewrite saved R14 value */
+       swi     r16, r1, PTO+PT_R16
+       swi     r16, r1, PTO+PT_PC; /* PC and r16 are the same */
+       swi     r17, r1, PTO+PT_R17
+       /* save special purpose registers to pt_regs */
+       mfs     r11, rear;
+       swi     r11, r1, PTO+PT_EAR;
+       mfs     r11, resr;
+       swi     r11, r1, PTO+PT_ESR;
+       mfs     r11, rfsr;
+       swi     r11, r1, PTO+PT_FSR;
+
+       /* stack pointer is in physical address at it is decrease
+        * by STATE_SAVE_SIZE but we need to get correct R1 value */
+       addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE;
+       swi     r11, r1, PTO+PT_R1
+       /* MS: r31 - current pointer isn't changed */
+       tovirt(r1,r1)
+#ifdef CONFIG_KGDB
+       addi    r5, r1, PTO /* pass pt_reg address as the first arg */
+       la      r15, r0, dbtrap_call; /* return address */
+       rtbd    r0, microblaze_kgdb_break
+       nop;
+#endif
+       /* MS: Place handler for brki from kernel space if KGDB is OFF.
+        * It is very unlikely that another brki instruction is called. */
+       bri 0
 
-       addi    r11, r0, 1;             /* Was in kernel-mode.  */
-       swi     r11, r1, PTO + PT_MODE;
-       brid    2f;
-       nop;                            /* Fill delay slot */
-1:      /* User-mode state save.  */
-       lwi     r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */
-       lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
+/* MS: User-mode state save - gdb */
+1:     lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
        tophys(r1,r1);
        lwi     r1, r1, TS_THREAD_INFO; /* get the thread info */
        addik   r1, r1, THREAD_SIZE;    /* calculate kernel stack pointer */
        tophys(r1,r1);
 
        addik   r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
-       swi     r3, r1, PTO + PT_R3;
-       swi     r4, r1, PTO + PT_R4;
        SAVE_REGS;
-
-       swi     r0, r1, PTO+PT_MODE; /* Was in user-mode.  */
+       swi     r17, r1, PTO+PT_R17;
+       swi     r16, r1, PTO+PT_R16;
+       swi     r16, r1, PTO+PT_PC;     /* Save LP */
+       swi     r0, r1, PTO + PT_MODE; /* Was in user-mode.  */
        lwi     r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
        swi     r11, r1, PTO+PT_R1; /* Store user SP.  */
-       addi    r11, r0, 1;
-       swi     r11, r0, TOPHYS(PER_CPU(KM));   /* Now we're in kernel-mode.  */
-2:     lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
-       /* Save away the syscall number.  */
-       swi     r0, r1, PTO+PT_R0;
+       lwi     CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
        tovirt(r1,r1)
-
-       addi    r5, r0, SIGTRAP              /* send the trap signal */
-       add     r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */
-       addk    r7, r0, r0                   /* 3rd param zero */
-
        set_vms;
-       la      r11, r0, send_sig;
-       la      r15, r0, dbtrap_call;
-dbtrap_call:   rtbd    r11, 0;
-       nop;
+       addik   r5, r1, PTO;
+       addik   r15, r0, dbtrap_call;
+dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
+       rtbd    r0, sw_exception
+       nop
 
-       set_bip;                        /*  Ints masked for state restore*/
-       lwi     r11, r1, PTO+PT_MODE;
+       /* MS: The first instruction for the second part of the gdb/kgdb */
+       set_bip; /* Ints masked for state restore */
+       lwi     r11, r1, PTO + PT_MODE;
        bnei    r11, 2f;
-
+/* MS: Return to user space - gdb */
        /* Get current task ptr into r11 */
        lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
        lwi     r11, r11, TI_FLAGS;     /* get flags in thread info */
        andi    r11, r11, _TIF_NEED_RESCHED;
        beqi    r11, 5f;
 
-/* Call the scheduler before returning from a syscall/trap. */
-
+       /* Call the scheduler before returning from a syscall/trap. */
        bralid  r15, schedule;  /* Call scheduler */
        nop;                            /* delay slot */
-       /* XXX Is PT_DTRACE handling needed here? */
-       /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here.  */
 
        /* Maybe handle a signal */
 5:     lwi     r11, CURRENT_TASK, TS_THREAD_INFO;      /* get thread info */
@@ -955,54 +837,40 @@ dbtrap_call:      rtbd    r11, 0;
        andi    r11, r11, _TIF_SIGPENDING;
        beqi    r11, 1f;                /* Signals to handle, handle them */
 
-/* Handle a signal return; Pending signals should be in r18.  */
-       /* Not all registers are saved by the normal trap/interrupt entry
-          points (for instance, call-saved registers (because the normal
-          C-compiler calling sequence in the kernel makes sure they're
-          preserved), and call-clobbered registers in the case of
-          traps), but signal handlers may want to examine or change the
-          complete register state.  Here we save anything not saved by
-          the normal entry sequence, so that it may be safely restored
-          (in a possibly modified form) after do_signal returns.  */
-
-       la      r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
+       addik   r5, r1, PTO;            /* Arg 1: struct pt_regs *regs */
        addi  r7, r0, 0;        /* Arg 3: int in_syscall */
        bralid  r15, do_signal; /* Handle any signals */
        add     r6, r0, r0;             /* Arg 2: sigset_t *oldset */
 
-
 /* Finally, return to user state.  */
-1:     swi     r0, r0, PER_CPU(KM);    /* Now officially in user state. */
-       swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
+1:     swi     CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
        VM_OFF;
        tophys(r1,r1);
-
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
+       /* MS: Restore all regs */
        RESTORE_REGS
-       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
-
-
-       lwi     r1, r1, PT_R1 - PT_SIZE;
-                                       /* Restore user stack pointer. */
-       bri     6f;
+       lwi     r17, r1, PTO+PT_R17;
+       lwi     r16, r1, PTO+PT_R16;
+       addik   r1, r1, STATE_SAVE_SIZE  /* Clean up stack space */
+       lwi     r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
+DBTRAP_return_user: /* MS: Make global symbol for debugging */
+       rtbd    r16, 0; /* MS: Instructions to return from a debug trap */
+       nop;
 
-/* Return to kernel state.  */
+/* MS: Return to kernel state - kgdb */
 2:     VM_OFF;
        tophys(r1,r1);
-       lwi     r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-       lwi     r4, r1, PTO+PT_R4;
+       /* MS: Restore all regs */
        RESTORE_REGS
-       addik   r1, r1, STATE_SAVE_SIZE         /* Clean up stack space.  */
-
+       lwi     r14, r1, PTO+PT_R14;
+       lwi     r16, r1, PTO+PT_PC;
+       lwi     r17, r1, PTO+PT_R17;
+       addik   r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
        tovirt(r1,r1);
-6:
-DBTRAP_return:         /* Make global symbol for debugging */
-       rtbd    r14, 0; /* Instructions to return from an IRQ */
+DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
+       rtbd    r16, 0; /* MS: Instructions to return from a debug trap */
        nop;
 
 
-
 ENTRY(_switch_to)
        /* prepare return value */
        addk    r3, r0, CURRENT_TASK
@@ -1037,16 +905,12 @@ ENTRY(_switch_to)
        swi     r30, r11, CC_R30
        /* special purpose registers */
        mfs     r12, rmsr
-       nop
        swi     r12, r11, CC_MSR
        mfs     r12, rear
-       nop
        swi     r12, r11, CC_EAR
        mfs     r12, resr
-       nop
        swi     r12, r11, CC_ESR
        mfs     r12, rfsr
-       nop
        swi     r12, r11, CC_FSR
 
        /* update r31, the current-give me pointer to task which will be next */
@@ -1085,10 +949,8 @@ ENTRY(_switch_to)
        /* special purpose registers */
        lwi     r12, r11, CC_FSR
        mts     rfsr, r12
-       nop
        lwi     r12, r11, CC_MSR
        mts     rmsr, r12
-       nop
 
        rtsd    r15, 8
        nop
@@ -1096,15 +958,6 @@ ENTRY(_switch_to)
 ENTRY(_reset)
        brai    0x70; /* Jump back to FS-boot */
 
-ENTRY(_break)
-       mfs     r5, rmsr
-       nop
-       swi     r5, r0, 0x250 + TOPHYS(r0_ram)
-       mfs     r5, resr
-       nop
-       swi     r5, r0, 0x254 + TOPHYS(r0_ram)
-       bri     0
-
        /* These are compiled and loaded into high memory, then
         * copied into place in mach_early_setup */
        .section        .init.ivt, "ax"
@@ -1116,14 +969,38 @@ ENTRY(_break)
        nop
        brai    TOPHYS(_user_exception); /* syscall handler */
        brai    TOPHYS(_interrupt);     /* Interrupt handler */
-       brai    TOPHYS(_break);         /* nmi trap handler */
+       brai    TOPHYS(_debug_exception);       /* debug trap handler */
        brai    TOPHYS(_hw_exception_handler);  /* HW exception handler */
 
-       .org    0x60
-       brai    TOPHYS(_debug_exception);       /* debug trap handler*/
-
 .section .rodata,"a"
 #include "syscall_table.S"
 
 syscall_table_size=(.-sys_call_table)
 
+type_SYSCALL:
+       .ascii "SYSCALL\0"
+type_IRQ:
+       .ascii "IRQ\0"
+type_IRQ_PREEMPT:
+       .ascii "IRQ (PREEMPTED)\0"
+type_SYSCALL_PREEMPT:
+       .ascii " SYSCALL (PREEMPTED)\0"
+
+       /*
+        * Trap decoding for stack unwinder
+        * Tuples are (start addr, end addr, string)
+        * If return address lies on [start addr, end addr],
+        * unwinder displays 'string'
+        */
+
+       .align 4
+.global microblaze_trap_handlers
+microblaze_trap_handlers:
+       /* Exact matches come first */
+       .word ret_from_trap; .word ret_from_trap   ; .word type_SYSCALL
+       .word ret_from_irq ; .word ret_from_irq    ; .word type_IRQ
+       /* Fuzzy matches go here */
+       .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT
+       .word ret_from_trap; .word TRAP_return     ; .word type_SYSCALL_PREEMPT
+       /* End of table */
+       .word 0               ; .word 0               ; .word 0