aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorJoakim Tjernlund <joakim.tjernlund@transmode.se>2009-11-19 19:21:06 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-12-09 01:10:36 -0500
commit0a2ab51ffb8dfdf51402dcfb446629648c96bc78 (patch)
treea5d481e64406a443f99eec136c40a3bebeab5c6c /arch/powerpc
parent60e071fee994ff98c37d03a4a7c5a3f8b1e3b8e5 (diff)
powerpc/8xx: Fixup DAR from buggy dcbX instructions.
This is an assembler version to fixup DAR not being set by dcbX, icbi instructions. There are two versions, one uses selfmodifing code, the other uses a jump table but is much bigger(default). Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/head_8xx.S147
1 files changed, 143 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index a9f1ace484d5..c00120d56f8f 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -494,11 +494,16 @@ DataTLBError:
494 494
495 mfspr r10, SPRN_DAR 495 mfspr r10, SPRN_DAR
496 cmpwi cr0, r10, 0x00f0 496 cmpwi cr0, r10, 0x00f0
497 beq- 2f /* must be a buggy dcbX, icbi insn. */ 497 beq- FixupDAR /* must be a buggy dcbX, icbi insn. */
498 498DARFixed:/* Return from dcbx instruction bug workaround, r10 holds value of DAR */
499 mfspr r11, SPRN_DSISR 499 mfspr r11, SPRN_DSISR
500 andis. r11, r11, 0x4800 /* !translation or protection */ 500 /* As the DAR fixup may clear store we may have all 3 states zero.
501 bne 2f /* branch if either is set */ 501 * Make sure only 0x0200(store) falls down into DIRTY handling
502 */
503 andis. r11, r11, 0x4a00 /* !translation, protection or store */
504 srwi r11, r11, 16
505 cmpwi cr0, r11, 0x0200 /* just store ? */
506 bne 2f
502 /* Only Change bit left now, do it here as it is faster 507 /* Only Change bit left now, do it here as it is faster
503 * than trapping to the C fault handler. 508 * than trapping to the C fault handler.
504 */ 509 */
@@ -604,6 +609,140 @@ DataTLBError:
604 609
605 . = 0x2000 610 . = 0x2000
606 611
612/* This is the procedure to calculate the data EA for buggy dcbx,dcbi instructions
613 * by decoding the registers used by the dcbx instruction and adding them.
614 * DAR is set to the calculated address and r10 also holds the EA on exit.
615 */
616 /* define if you don't want to use self modifying code */
617#define NO_SELF_MODIFYING_CODE
618FixupDAR:/* Entry point for dcbx workaround. */
619 /* fetch instruction from memory. */
620 mfspr r10, SPRN_SRR0
621 DO_8xx_CPU6(0x3780, r3)
622 mtspr SPRN_MD_EPN, r10
623 mfspr r11, SPRN_M_TWB /* Get level 1 table entry address */
624 cmplwi cr0, r11, 0x0800
625 blt- 3f /* Branch if user space */
626 lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
627 ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
628 rlwimi r11, r10, 32-20, 0xffc /* r11 = r11&~0xffc|(r10>>20)&0xffc */
6293: lwz r11, 0(r11) /* Get the level 1 entry */
630 DO_8xx_CPU6(0x3b80, r3)
631 mtspr SPRN_MD_TWC, r11 /* Load pte table base address */
632 mfspr r11, SPRN_MD_TWC /* ....and get the pte address */
633 lwz r11, 0(r11) /* Get the pte */
634 /* concat physical page address(r11) and page offset(r10) */
635 rlwimi r11, r10, 0, 20, 31
636 lwz r11,0(r11)
637/* Check if it really is a dcbx instruction. */
638/* dcbt and dcbtst does not generate DTLB Misses/Errors,
639 * no need to include them here */
640 srwi r10, r11, 26 /* check if major OP code is 31 */
641 cmpwi cr0, r10, 31
642 bne- 141f
643 rlwinm r10, r11, 0, 21, 30
644 cmpwi cr0, r10, 2028 /* Is dcbz? */
645 beq+ 142f
646 cmpwi cr0, r10, 940 /* Is dcbi? */
647 beq+ 142f
648 cmpwi cr0, r10, 108 /* Is dcbst? */
649 beq+ 144f /* Fix up store bit! */
650 cmpwi cr0, r10, 172 /* Is dcbf? */
651 beq+ 142f
652 cmpwi cr0, r10, 1964 /* Is icbi? */
653 beq+ 142f
654141: mfspr r10, SPRN_DAR /* r10 must hold DAR at exit */
655 b DARFixed /* Nope, go back to normal TLB processing */
656
657144: mfspr r10, SPRN_DSISR
658 rlwinm r10, r10,0,7,5 /* Clear store bit for buggy dcbst insn */
659 mtspr SPRN_DSISR, r10
660142: /* continue, it was a dcbx, dcbi instruction. */
661#ifdef CONFIG_8xx_CPU6
662 lwz r3, 8(r0) /* restore r3 from memory */
663#endif
664#ifndef NO_SELF_MODIFYING_CODE
665 andis. r10,r11,0x1f /* test if reg RA is r0 */
666 li r10,modified_instr@l
667 dcbtst r0,r10 /* touch for store */
668 rlwinm r11,r11,0,0,20 /* Zero lower 10 bits */
669 oris r11,r11,640 /* Transform instr. to a "add r10,RA,RB" */
670 ori r11,r11,532
671 stw r11,0(r10) /* store add/and instruction */
672 dcbf 0,r10 /* flush new instr. to memory. */
673 icbi 0,r10 /* invalidate instr. cache line */
674 lwz r11, 4(r0) /* restore r11 from memory */
675 mfspr r10, SPRN_M_TW /* restore r10 from M_TW */
676 isync /* Wait until new instr is loaded from memory */
677modified_instr:
678 .space 4 /* this is where the add instr. is stored */
679 bne+ 143f
680 subf r10,r0,r10 /* r10=r10-r0, only if reg RA is r0 */
681143: mtdar r10 /* store faulting EA in DAR */
682 b DARFixed /* Go back to normal TLB handling */
683#else
684 mfctr r10
685 mtdar r10 /* save ctr reg in DAR */
686 rlwinm r10, r11, 24, 24, 28 /* offset into jump table for reg RB */
687 addi r10, r10, 150f@l /* add start of table */
688 mtctr r10 /* load ctr with jump address */
689 xor r10, r10, r10 /* sum starts at zero */
690 bctr /* jump into table */
691150:
692 add r10, r10, r0 ;b 151f
693 add r10, r10, r1 ;b 151f
694 add r10, r10, r2 ;b 151f
695 add r10, r10, r3 ;b 151f
696 add r10, r10, r4 ;b 151f
697 add r10, r10, r5 ;b 151f
698 add r10, r10, r6 ;b 151f
699 add r10, r10, r7 ;b 151f
700 add r10, r10, r8 ;b 151f
701 add r10, r10, r9 ;b 151f
702 mtctr r11 ;b 154f /* r10 needs special handling */
703 mtctr r11 ;b 153f /* r11 needs special handling */
704 add r10, r10, r12 ;b 151f
705 add r10, r10, r13 ;b 151f
706 add r10, r10, r14 ;b 151f
707 add r10, r10, r15 ;b 151f
708 add r10, r10, r16 ;b 151f
709 add r10, r10, r17 ;b 151f
710 add r10, r10, r18 ;b 151f
711 add r10, r10, r19 ;b 151f
712 add r10, r10, r20 ;b 151f
713 add r10, r10, r21 ;b 151f
714 add r10, r10, r22 ;b 151f
715 add r10, r10, r23 ;b 151f
716 add r10, r10, r24 ;b 151f
717 add r10, r10, r25 ;b 151f
718 add r10, r10, r26 ;b 151f
719 add r10, r10, r27 ;b 151f
720 add r10, r10, r28 ;b 151f
721 add r10, r10, r29 ;b 151f
722 add r10, r10, r30 ;b 151f
723 add r10, r10, r31
724151:
725 rlwinm. r11,r11,19,24,28 /* offset into jump table for reg RA */
726 beq 152f /* if reg RA is zero, don't add it */
727 addi r11, r11, 150b@l /* add start of table */
728 mtctr r11 /* load ctr with jump address */
729 rlwinm r11,r11,0,16,10 /* make sure we don't execute this more than once */
730 bctr /* jump into table */
731152:
732 mfdar r11
733 mtctr r11 /* restore ctr reg from DAR */
734 mtdar r10 /* save fault EA to DAR */
735 b DARFixed /* Go back to normal TLB handling */
736
737 /* special handling for r10,r11 since these are modified already */
738153: lwz r11, 4(r0) /* load r11 from memory */
739 b 155f
740154: mfspr r11, SPRN_M_TW /* load r10 from M_TW */
741155: add r10, r10, r11 /* add it */
742 mfctr r11 /* restore r11 */
743 b 151b
744#endif
745
607 .globl giveup_fpu 746 .globl giveup_fpu
608giveup_fpu: 747giveup_fpu:
609 blr 748 blr