Benjamin Herrenschmidt <b...@kernel.crashing.org> wrote on 29/09/2009 10:16:38:
>
>
> > hmm, yes. You do get this and mysterious SEGV if you hit the but so does
> > other bugs too so this is probably due to missing invalidation.
> >
> > I suspect that something like below will fix the problem and
> > is the "correct" fix(untested, not even compiled):
>
> Ok but do we also still have to worry about the "unpopulated" TLB
> entries and invalidate them somehow when populating ?

Since I am probably the only one that knows about DAR problem I figured
I should take a stab at it. This is not tested, but I hope Rex and the list
can do that. Once this works as it should, we can remove all special handling
for 8xx in copy_tofrom_user() and friends.
No sign-off yet, want some confirmation first.

diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 4dd38f1..691ebd3 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -774,7 +774,14 @@ restore:
        lwz     r11,_CTR(r1)
        mtspr   SPRN_XER,r10
        mtctr   r11
-
+#ifdef CONFIG_8xx
+       /* Tag DAR with a well know value.
+        * This needs to match head_8xx.S and
+        * do_page_fault()
+        */
+       li      r10, 0xf0
+       mtspr   SPRN_DAR, r10
+#endif
        PPC405_ERR77(0,r1)
 BEGIN_FTR_SECTION
        lwarx   r11,0,r1
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 52ff8c5..418ea96 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -39,6 +39,15 @@
 #else
 #define DO_8xx_CPU6(val, reg)
 #endif
+
+/* DAR needs to be tagged with a known value so that the
+ * DataTLB Miss/Error and do_page_fault() can recognize a
+ * buggy dcbx instruction and workaround the problem.
+ * dcbf, dcbi, dcbst, dcbz instructions do not update DAR
+ * when trapping into a Data TLB Miss/Error. See
+ * DataStoreTLBMiss and DataTLBError for details
+ */
+
        __HEAD
 _ENTRY(_stext);
 _ENTRY(_start);
@@ -428,7 +437,8 @@ DataStoreTLBMiss:
         * set.  All other Linux PTE bits control the behavior
         * of the MMU.
         */
-2:     li      r11, 0x00f0
+       li      r11, 0x00f0
+       mtspr   SPRN_DAR, r11           /* Tag DAR */
        rlwimi  r10, r11, 0, 24, 28     /* Set 24-27, clear 28 */
        DO_8xx_CPU6(0x3d80, r3)
        mtspr   SPRN_MD_RPN, r10        /* Update TLB entry */
@@ -441,7 +451,15 @@ DataStoreTLBMiss:
        lwz     r3, 8(r0)
 #endif
        rfi
-
+2:
+       mfspr   r10, SPRN_M_TW  /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
+#ifdef CONFIG_8xx_CPU6
+       lwz     r3, 8(r0)
+#endif
+       b       DataAccess
 /* This is an instruction TLB error on the MPC8xx.  This could be due
  * to many reasons, such as executing guarded memory or illegal instruction
  * addresses.  There is nothing to do but handle a big time error fault.
@@ -492,6 +510,8 @@ DataTLBError:
         * assuming we only use the dcbi instruction on kernel addresses.
         */
        mfspr   r10, SPRN_DAR
+       cmpwi   cr0, r10, 0xf0          /* check it DAR holds a tag */
+       beq-    2f
        rlwinm  r11, r10, 0, 0, 19
        ori     r11, r11, MD_EVALID
        mfspr   r10, SPRN_M_CASID
@@ -547,6 +567,7 @@ DataTLBError:
         * of the MMU.
         */
        li      r11, 0x00f0
+       mtspr   SPRN_DAR, r11           /* Tag DAR */
        rlwimi  r10, r11, 0, 24, 28     /* Set 24-27, clear 28 */
        DO_8xx_CPU6(0x3d80, r3)
        mtspr   SPRN_MD_RPN, r10        /* Update TLB entry */
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 7699394..be779b2 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -125,6 +125,32 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned 
long address,
        int trap = TRAP(regs);
        int is_exec = trap == 0x400;

+#if defined(CONFIG_8xx)
+/*
+ Workarund DTLB Miss/Error, as these do not update DAR
+ for dcbf, dcbi, dcbst, dcbz instructions
+ This relies on every exception tagging DAR with 0xf0
+ before returning (rfi)
+ DAR as passed as address to this function.
+ */
+#define RA(inst)        (((inst) & 0x001F0000) >> 16)
+#define RB(inst)        (((inst) & 0x0000F800) >> 11)
+       {
+               unsigned long ra, rb, dar, insns;
+
+               if (trap == 0x300 && address == 0xf0) {
+                       insns = *((unsigned long *)regs->nip);
+                       /* Really check if it is an dcbf, dcbi, dcbst, dcbz 
insns ? */
+                       ra  = RA(insns); /* Reg Ra */
+                       rb  = RB(insns); /* Reg Rb */
+                       dar = regs->gpr[rb];
+                       if (ra)
+                               dar += regs->gpr[ra];
+                       /* regs->dar = dar; perhaps */
+                       address = dar;
+               }
+       }
+#endif
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
        /*
         * Fortunately the bit assignments in SRR1 for an instruction

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to