Message ID | OF94793A12.243E8E02-ONC1257640.0040DE05-C1257640.00419DBD@transmode.se (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Thus spake Joakim Tjernlund (joakim.tjernlund@transmode.se): > Benjamin Herrenschmidt <benh@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. It doesn't make a difference. I applied it to the top of the tree, it got to userspace but it is stuck. Using break I am able to dump the registers, I'm not sure if this is useful. Oh, well, I finally got to a shell but it is unusably slow. Is there some test code that would be better to run? I tried looking through the mailing list archives but I couldn't find anything. thanks! /rex. SysRq : Show Regs NIP: c00588d0 LR: c000e3c4 CTR: 00001fde REGS: c3459d90 TRAP: 0501 Not tainted (2.6.32-rc2-00013-g2d222d9-dirty) MSR: 00009032 <EE,ME,IR,DR> CR: 44008422 XER: 20006a02 TASK = c3438050[13] 'rc.sysinit' THREAD: c3458000 GPR00: c000e3c4 c3459e40 c3438050 c21a2a60 c345bdf4 0fd81032 00000000 3001e920 GPR08: 00000000 00000005 c21a2a60 c0210000 03438260 NIP [c00588d0] handle_mm_fault+0x10/0xacc LR [c000e3c4] do_page_fault+0x2f0/0x474 Call Trace: [c3459e40] [c0059328] handle_mm_fault+0xa68/0xacc (unreliable) [c3459e90] [c000e418] do_page_fault+0x344/0x474 [c3459f40] [c000d520] handle_page_fault+0xc/0x80 Instruction dump: 4bff15f1 39600000 80010014 7d635b78 7c0803a6 bbc10008 38210010 4e800020 7c0802a6 9421ffb0 3d60c021 be810020 <90010054> 38000000 90020000 396b4bec SysRq : Show Regs NIP: c000e0e0 LR: c000d520 CTR: 00001fde REGS: c21adde0 TRAP: 0501 Not tainted (2.6.32-rc2-00013-g2d222d9-dirty) MSR: 00009032 <EE,ME,IR,DR> CR: 48008424 XER: 00006a02 TASK = c3438460[18] 'sh' THREAD: c21ac000 GPR00: c000d520 c21ade90 c3438460 c21adf50 0fd76cb8 c0000000 00000004 0fee8c44 GPR08: 00009f6c c000d788 00009032 c000d514 03438670 NIP [c000e0e0] do_page_fault+0xc/0x474 LR [c000d520] handle_page_fault+0xc/0x80 Call Trace: [c21ade90] [c000e418] do_page_fault+0x344/0x474 (unreliable) [c21adf40] [c000d520] handle_page_fault+0xc/0x80 Instruction dump: 3863f604 7fe4fb78 7fc5f378 4bffcd39 80010014 bbc10008 7c0803a6 38210010 4e800020 7c0802a6 9421ff50 bf010090 <900100b4> 7c7e1b78 800300a0 7c9d2378 SysRq : Show Regs NIP: c005930c LR: c000e3c4 CTR: 00001fde REGS: c21add90 TRAP: 0501 Not tainted (2.6.32-rc2-00013-g2d222d9-dirty) MSR: 00009032 <EE,ME,IR,DR> CR: 24002422 XER: 00006a02 TASK = c3438460[18] 'sh' THREAD: c21ac000 GPR00: c0236000 c21ade40 c3438460 c21a2a60 c3444df4 c3456000 00000000 feff0000 GPR08: c21ac000 03456000 c0220000 00000001 03438670 NIP [c005930c] handle_mm_fault+0xa4c/0xacc LR [c000e3c4] do_page_fault+0x2f0/0x474 Call Trace: [c21ade40] [c0059328] handle_mm_fault+0xa68/0xacc (unreliable) [c21ade90] [c000e3c4] do_page_fault+0x2f0/0x474 [c21adf40] [c000d520] handle_page_fault+0xc/0x80 Instruction dump: 4802192d 48000094 2f9f0000 3ba00001 419e0088 7fe3fb78 4bff46a1 48000078 7fe3fb78 4bff4695 48000070 63390020 <633f0080> 7f45d378 7f63db78 7f04c378
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