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 |
