diff options
-rw-r--r-- | arch/powerpc/kernel/head_8xx.S | 147 |
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 | 498 | DARFixed:/* 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 | ||
618 | FixupDAR:/* 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 */ | ||
629 | 3: 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 | ||
654 | 141: mfspr r10, SPRN_DAR /* r10 must hold DAR at exit */ | ||
655 | b DARFixed /* Nope, go back to normal TLB processing */ | ||
656 | |||
657 | 144: mfspr r10, SPRN_DSISR | ||
658 | rlwinm r10, r10,0,7,5 /* Clear store bit for buggy dcbst insn */ | ||
659 | mtspr SPRN_DSISR, r10 | ||
660 | 142: /* 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 */ | ||
677 | modified_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 */ | ||
681 | 143: 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 */ | ||
691 | 150: | ||
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 | ||
724 | 151: | ||
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 */ | ||
731 | 152: | ||
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 */ | ||
738 | 153: lwz r11, 4(r0) /* load r11 from memory */ | ||
739 | b 155f | ||
740 | 154: mfspr r11, SPRN_M_TW /* load r10 from M_TW */ | ||
741 | 155: 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 |
608 | giveup_fpu: | 747 | giveup_fpu: |
609 | blr | 748 | blr |