powerpc/cpumask: Update some comments
[safe/jmp/linux-2.6] / arch / powerpc / kernel / process.c
index 892a9f2..9d255b4 100644 (file)
@@ -245,6 +245,24 @@ void discard_lazy_cpu_state(void)
 }
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+void do_send_trap(struct pt_regs *regs, unsigned long address,
+                 unsigned long error_code, int signal_code, int breakpt)
+{
+       siginfo_t info;
+
+       if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
+                       11, SIGSEGV) == NOTIFY_STOP)
+               return;
+
+       /* Deliver the signal to userspace */
+       info.si_signo = SIGTRAP;
+       info.si_errno = breakpt;        /* breakpoint or watchpoint id */
+       info.si_code = signal_code;
+       info.si_addr = (void __user *)address;
+       force_sig_info(SIGTRAP, &info, current);
+}
+#else  /* !CONFIG_PPC_ADV_DEBUG_REGS */
 void do_dabr(struct pt_regs *regs, unsigned long address,
                    unsigned long error_code)
 {
@@ -257,12 +275,6 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
        if (debugger_dabr_match(regs))
                return;
 
-       /* Clear the DAC and struct entries.  One shot trigger */
-#if defined(CONFIG_BOOKE)
-       mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W
-                                                       | DBCR0_IDM));
-#endif
-
        /* Clear the DABR */
        set_dabr(0);
 
@@ -273,9 +285,82 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
        info.si_addr = (void __user *)address;
        force_sig_info(SIGTRAP, &info, current);
 }
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
 static DEFINE_PER_CPU(unsigned long, current_dabr);
 
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+/*
+ * Set the debug registers back to their default "safe" values.
+ */
+static void set_debug_reg_defaults(struct thread_struct *thread)
+{
+       thread->iac1 = thread->iac2 = 0;
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+       thread->iac3 = thread->iac4 = 0;
+#endif
+       thread->dac1 = thread->dac2 = 0;
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+       thread->dvc1 = thread->dvc2 = 0;
+#endif
+       thread->dbcr0 = 0;
+#ifdef CONFIG_BOOKE
+       /*
+        * Force User/Supervisor bits to b11 (user-only MSR[PR]=1)
+        */
+       thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US |   \
+                       DBCR1_IAC3US | DBCR1_IAC4US;
+       /*
+        * Force Data Address Compare User/Supervisor bits to be User-only
+        * (0b11 MSR[PR]=1) and set all other bits in DBCR2 register to be 0.
+        */
+       thread->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
+#else
+       thread->dbcr1 = 0;
+#endif
+}
+
+static void prime_debug_regs(struct thread_struct *thread)
+{
+       mtspr(SPRN_IAC1, thread->iac1);
+       mtspr(SPRN_IAC2, thread->iac2);
+#if CONFIG_PPC_ADV_DEBUG_IACS > 2
+       mtspr(SPRN_IAC3, thread->iac3);
+       mtspr(SPRN_IAC4, thread->iac4);
+#endif
+       mtspr(SPRN_DAC1, thread->dac1);
+       mtspr(SPRN_DAC2, thread->dac2);
+#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
+       mtspr(SPRN_DVC1, thread->dvc1);
+       mtspr(SPRN_DVC2, thread->dvc2);
+#endif
+       mtspr(SPRN_DBCR0, thread->dbcr0);
+       mtspr(SPRN_DBCR1, thread->dbcr1);
+#ifdef CONFIG_BOOKE
+       mtspr(SPRN_DBCR2, thread->dbcr2);
+#endif
+}
+/*
+ * Unless neither the old or new thread are making use of the
+ * debug registers, set the debug registers from the values
+ * stored in the new thread.
+ */
+static void switch_booke_debug_regs(struct thread_struct *new_thread)
+{
+       if ((current->thread.dbcr0 & DBCR0_IDM)
+               || (new_thread->dbcr0 & DBCR0_IDM))
+                       prime_debug_regs(new_thread);
+}
+#else  /* !CONFIG_PPC_ADV_DEBUG_REGS */
+static void set_debug_reg_defaults(struct thread_struct *thread)
+{
+       if (thread->dabr) {
+               thread->dabr = 0;
+               set_dabr(0);
+       }
+}
+#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
+
 int set_dabr(unsigned long dabr)
 {
        __get_cpu_var(current_dabr) = dabr;
@@ -284,13 +369,15 @@ int set_dabr(unsigned long dabr)
                return ppc_md.set_dabr(dabr);
 
        /* XXX should we have a CPU_FTR_HAS_DABR ? */
-#if defined(CONFIG_PPC64) || defined(CONFIG_6xx)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+       mtspr(SPRN_DAC1, dabr);
+#ifdef CONFIG_PPC_47x
+       isync();
+#endif
+#elif defined(CONFIG_PPC_BOOK3S)
        mtspr(SPRN_DABR, dabr);
 #endif
 
-#if defined(CONFIG_BOOKE)
-       mtspr(SPRN_DAC1, dabr);
-#endif
 
        return 0;
 }
@@ -372,15 +459,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
 
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+       switch_booke_debug_regs(&new->thread);
+#else
        if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
                set_dabr(new->thread.dabr);
-
-#if defined(CONFIG_BOOKE)
-       /* If new thread DAC (HW breakpoint) is the same then leave it */
-       if (new->thread.dabr)
-               set_dabr(new->thread.dabr);
 #endif
 
+
        new_thread = &new->thread;
        old_thread = &current->thread;
 
@@ -514,7 +600,7 @@ void show_regs(struct pt_regs * regs)
        printk("  CR: %08lx  XER: %08lx\n", regs->ccr, regs->xer);
        trap = TRAP(regs);
        if (trap == 0x300 || trap == 0x600)
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
                printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr);
 #else
                printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
@@ -554,28 +640,9 @@ void exit_thread(void)
 
 void flush_thread(void)
 {
-#ifdef CONFIG_PPC64
-       struct thread_info *t = current_thread_info();
-
-       if (test_ti_thread_flag(t, TIF_ABI_PENDING)) {
-               clear_ti_thread_flag(t, TIF_ABI_PENDING);
-               if (test_ti_thread_flag(t, TIF_32BIT))
-                       clear_ti_thread_flag(t, TIF_32BIT);
-               else
-                       set_ti_thread_flag(t, TIF_32BIT);
-       }
-#endif
-
        discard_lazy_cpu_state();
 
-       if (current->thread.dabr) {
-               current->thread.dabr = 0;
-               set_dabr(0);
-
-#if defined(CONFIG_BOOKE)
-               current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W);
-#endif
-       }
+       set_debug_reg_defaults(&current->thread);
 }
 
 void
@@ -664,6 +731,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                sp_vsid |= SLB_VSID_KERNEL | llp;
                p->thread.ksp_vsid = sp_vsid;
        }
+#endif /* CONFIG_PPC_STD_MMU_64 */
 
        /*
         * The PPC64 ABI makes use of a TOC to contain function 
@@ -671,6 +739,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
         * to the TOC entry.  The first entry is a pointer to the actual
         * function.
         */
+#ifdef CONFIG_PPC64
        kregs->nip = *((unsigned long *)ret_from_fork);
 #else
        kregs->nip = (unsigned long)ret_from_fork;
@@ -1014,9 +1083,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        int curr_frame = current->curr_ret_stack;
        extern void return_to_handler(void);
-       unsigned long addr = (unsigned long)return_to_handler;
+       unsigned long rth = (unsigned long)return_to_handler;
+       unsigned long mrth = -1;
 #ifdef CONFIG_PPC64
-       addr = *(unsigned long*)addr;
+       extern void mod_return_to_handler(void);
+       rth = *(unsigned long *)rth;
+       mrth = (unsigned long)mod_return_to_handler;
+       mrth = *(unsigned long *)mrth;
 #endif
 #endif
 
@@ -1042,7 +1115,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
                if (!firstframe || ip != lr) {
                        printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip);
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-                       if (ip == addr && curr_frame >= 0) {
+                       if ((ip == rth || ip == mrth) && curr_frame >= 0) {
                                printk(" (%pS)",
                                       (void *)current->ret_stack[curr_frame].ret);
                                curr_frame--;
@@ -1163,7 +1236,22 @@ static inline unsigned long brk_rnd(void)
 
 unsigned long arch_randomize_brk(struct mm_struct *mm)
 {
-       unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
+       unsigned long base = mm->brk;
+       unsigned long ret;
+
+#ifdef CONFIG_PPC_STD_MMU_64
+       /*
+        * If we are using 1TB segments and we are allowed to randomise
+        * the heap, we can put it above 1TB so it is backed by a 1TB
+        * segment. Otherwise the heap will be in the bottom 1TB
+        * which always uses 256MB segments and this may result in a
+        * performance penalty.
+        */
+       if (!is_32bit_task() && (mmu_highuser_ssize == MMU_SEGSIZE_1T))
+               base = max_t(unsigned long, mm->brk, 1UL << SID_SHIFT_1T);
+#endif
+
+       ret = PAGE_ALIGN(base + brk_rnd());
 
        if (ret < mm->brk)
                return mm->brk;