vserver 1.9.5.x5
[linux-2.6.git] / arch / mips / kernel / traps.c
index af1b42b..56c36e4 100644 (file)
 #include <asm/watch.h>
 #include <asm/types.h>
 
-extern asmlinkage void handle_mod(void);
+extern asmlinkage void handle_tlbm(void);
 extern asmlinkage void handle_tlbl(void);
 extern asmlinkage void handle_tlbs(void);
-extern asmlinkage void __xtlb_mod(void);
-extern asmlinkage void __xtlb_tlbl(void);
-extern asmlinkage void __xtlb_tlbs(void);
 extern asmlinkage void handle_adel(void);
 extern asmlinkage void handle_ades(void);
 extern asmlinkage void handle_ibe(void);
@@ -82,7 +79,12 @@ void show_stack(struct task_struct *task, unsigned long *sp)
        long stackdata;
        int i;
 
-       sp = sp ? sp : (unsigned long *) &sp;
+       if (!sp) {
+               if (task && task != current)
+                       sp = (unsigned long *) task->thread.reg29;
+               else
+                       sp = (unsigned long *) &sp;
+       }
 
        printk("Stack :");
        i = 0;
@@ -110,8 +112,12 @@ void show_trace(struct task_struct *task, unsigned long *stack)
        const int field = 2 * sizeof(unsigned long);
        unsigned long addr;
 
-       if (!stack)
-               stack = (unsigned long*)&stack;
+       if (!stack) {
+               if (task && task != current)
+                       stack = (unsigned long *) task->thread.reg29;
+               else
+                       stack = (unsigned long *) &stack;
+       }
 
        printk("Call Trace:");
 #ifdef CONFIG_KALLSYMS
@@ -244,7 +250,7 @@ void show_registers(struct pt_regs *regs)
        printk("\n");
 }
 
-static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(die_lock);
 
 NORET_TYPE void __die(const char * str, struct pt_regs * regs,
        const char * file, const char * func, unsigned long line)
@@ -390,6 +396,8 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode)
                goto sig;
        }
 
+       preempt_disable();
+
        if (ll_task == NULL || ll_task == current) {
                ll_bit = 1;
        } else {
@@ -397,6 +405,8 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode)
        }
        ll_task = current;
 
+       preempt_enable();
+
        regs->regs[(opcode & RT) >> 16] = value;
 
        compute_return_epc(regs);
@@ -429,12 +439,18 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode)
                signal = SIGBUS;
                goto sig;
        }
+
+       preempt_disable();
+
        if (ll_bit == 0 || ll_task != current) {
                regs->regs[reg] = 0;
+               preempt_enable();
                compute_return_epc(regs);
                return;
        }
 
+       preempt_enable();
+
        if (put_user(regs->regs[reg], vaddr)) {
                signal = SIGSEGV;
                goto sig;
@@ -494,6 +510,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        if (fcr31 & FPU_CSR_UNI_X) {
                int sig;
 
+               preempt_disable();
+
                /*
                 * Unimplemented operation exception.  If we've got the full
                 * software emulator on-board, let's use it...
@@ -519,6 +537,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                /* Restore the hardware register state */
                restore_fp(current);
 
+               preempt_enable();
+
                /* If something went wrong, signal */
                if (sig)
                        force_sig(sig, current);
@@ -638,12 +658,14 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                break;
 
        case 1:
+               preempt_disable();
+
                own_fpu();
-               if (current->used_math) {       /* Using the FPU again.  */
+               if (used_math()) {      /* Using the FPU again.  */
                        restore_fp(current);
                } else {                        /* First time FPU user.  */
                        init_fpu();
-                       current->used_math = 1;
+                       set_used_math();
                }
 
                if (!cpu_has_fpu) {
@@ -653,6 +675,8 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                                force_sig(sig, current);
                }
 
+               preempt_enable();
+
                return;
 
        case 2:
@@ -892,15 +916,21 @@ extern void tlb_init(void);
 void __init per_cpu_trap_init(void)
 {
        unsigned int cpu = smp_processor_id();
+       unsigned int status_set = ST0_CU0;
 
-       /* Some firmware leaves the BEV flag set, clear it.  */
-       clear_c0_status(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV);
+       /*
+        * Disable coprocessors and select 32-bit or 64-bit addressing
+        * and the 16/32 or 32/32 FPR register model.  Reset the BEV
+        * flag that some firmware may have left set and the TS bit (for
+        * IP27).  Set XX for ISA IV code to work.
+        */
 #ifdef CONFIG_MIPS64
-       set_c0_status(ST0_CU0|ST0_FR|ST0_KX|ST0_SX|ST0_UX);
+       status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
 #endif
-
        if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
-               set_c0_status(ST0_XX);
+               status_set |= ST0_XX;
+       change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
+                        status_set);
 
        /*
         * Some MIPS CPUs have a dedicated interrupt vector which reduces the
@@ -977,16 +1007,10 @@ void __init trap_init(void)
        if (board_be_init)
                board_be_init();
 
-#ifdef CONFIG_MIPS32
-       set_except_vector(1, handle_mod);
+       set_except_vector(1, handle_tlbm);
        set_except_vector(2, handle_tlbl);
        set_except_vector(3, handle_tlbs);
-#endif
-#ifdef CONFIG_MIPS64
-       set_except_vector(1, __xtlb_mod);
-       set_except_vector(2, __xtlb_tlbl);
-       set_except_vector(3, __xtlb_tlbs);
-#endif
+
        set_except_vector(4, handle_adel);
        set_except_vector(5, handle_ades);
 
@@ -1008,7 +1032,8 @@ void __init trap_init(void)
                set_except_vector(24, handle_mcheck);
 
        if (cpu_has_vce)
-               memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x80);
+               /* Special exception: R4[04]00 uses also the divec space. */
+               memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
        else if (cpu_has_4kex)
                memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
        else
@@ -1022,7 +1047,7 @@ void __init trap_init(void)
                 * unaligned ldc1/sdc1 exception.  The handlers have not been
                 * written yet.  Well, anyway there is no R6000 machine on the
                 * current list of targets for Linux/MIPS.
-                * (Duh, crap, there is someone with a tripple R6k machine)
+                * (Duh, crap, there is someone with a triple R6k machine)
                 */
                //set_except_vector(14, handle_mc);
                //set_except_vector(15, handle_ndc);