diff options
author | Kumar Gala <galak@kernel.crashing.org> | 2008-07-09 11:03:28 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2008-07-16 18:57:51 -0400 |
commit | 6cfd8990e27d3a491c1c605d6cbc18a46ae51fef (patch) | |
tree | 89ff46a4d744fa20e236186deef82971a36e9498 | |
parent | 2d07db33d1875dcaada8eb7e69c68aeede722bb5 (diff) |
powerpc: rework FSL Book-E PTE access and TLB miss
This converts the FSL Book-E PTE access and TLB miss handling to match
with the recent changes to 44x that introduce support for non-atomic PTE
operations in pgtable-ppc32.h and removes write back to the PTE from
the TLB miss handlers. In addition, the DSI interrupt code no longer
tries to fixup write permission, this is left to generic code, and
_PAGE_HWWRITE is gone.
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/kernel/head_fsl_booke.S | 168 | ||||
-rw-r--r-- | include/asm-powerpc/pgtable-ppc32.h | 15 |
2 files changed, 48 insertions, 135 deletions
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index c4268500e856..7d554968b635 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -483,90 +483,16 @@ interrupt_base: | |||
483 | 483 | ||
484 | /* Data Storage Interrupt */ | 484 | /* Data Storage Interrupt */ |
485 | START_EXCEPTION(DataStorage) | 485 | START_EXCEPTION(DataStorage) |
486 | mtspr SPRN_SPRG0, r10 /* Save some working registers */ | 486 | NORMAL_EXCEPTION_PROLOG |
487 | mtspr SPRN_SPRG1, r11 | 487 | mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ |
488 | mtspr SPRN_SPRG4W, r12 | 488 | stw r5,_ESR(r11) |
489 | mtspr SPRN_SPRG5W, r13 | 489 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ |
490 | mfcr r11 | 490 | andis. r10,r5,(ESR_ILK|ESR_DLK)@h |
491 | mtspr SPRN_SPRG7W, r11 | 491 | bne 1f |
492 | 492 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | |
493 | /* | 493 | 1: |
494 | * Check if it was a store fault, if not then bail | 494 | addi r3,r1,STACK_FRAME_OVERHEAD |
495 | * because a user tried to access a kernel or | 495 | EXC_XFER_EE_LITE(0x0300, CacheLockingException) |
496 | * read-protected page. Otherwise, get the | ||
497 | * offending address and handle it. | ||
498 | */ | ||
499 | mfspr r10, SPRN_ESR | ||
500 | andis. r10, r10, ESR_ST@h | ||
501 | beq 2f | ||
502 | |||
503 | mfspr r10, SPRN_DEAR /* Get faulting address */ | ||
504 | |||
505 | /* If we are faulting a kernel address, we have to use the | ||
506 | * kernel page tables. | ||
507 | */ | ||
508 | lis r11, PAGE_OFFSET@h | ||
509 | cmplw 0, r10, r11 | ||
510 | bge 2f | ||
511 | |||
512 | /* Get the PGD for the current thread */ | ||
513 | 3: | ||
514 | mfspr r11,SPRN_SPRG3 | ||
515 | lwz r11,PGDIR(r11) | ||
516 | 4: | ||
517 | FIND_PTE | ||
518 | |||
519 | /* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */ | ||
520 | andi. r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE | ||
521 | cmpwi 0, r13, _PAGE_RW|_PAGE_USER | ||
522 | bne 2f /* Bail if not */ | ||
523 | |||
524 | /* Update 'changed'. */ | ||
525 | ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE | ||
526 | stw r11, PTE_FLAGS_OFFSET(r12) /* Update Linux page table */ | ||
527 | |||
528 | /* MAS2 not updated as the entry does exist in the tlb, this | ||
529 | fault taken to detect state transition (eg: COW -> DIRTY) | ||
530 | */ | ||
531 | andi. r11, r11, _PAGE_HWEXEC | ||
532 | rlwimi r11, r11, 31, 27, 27 /* SX <- _PAGE_HWEXEC */ | ||
533 | ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ | ||
534 | |||
535 | /* update search PID in MAS6, AS = 0 */ | ||
536 | mfspr r12, SPRN_PID0 | ||
537 | slwi r12, r12, 16 | ||
538 | mtspr SPRN_MAS6, r12 | ||
539 | |||
540 | /* find the TLB index that caused the fault. It has to be here. */ | ||
541 | tlbsx 0, r10 | ||
542 | |||
543 | /* only update the perm bits, assume the RPN is fine */ | ||
544 | mfspr r12, SPRN_MAS3 | ||
545 | rlwimi r12, r11, 0, 20, 31 | ||
546 | mtspr SPRN_MAS3,r12 | ||
547 | tlbwe | ||
548 | |||
549 | /* Done...restore registers and get out of here. */ | ||
550 | mfspr r11, SPRN_SPRG7R | ||
551 | mtcr r11 | ||
552 | mfspr r13, SPRN_SPRG5R | ||
553 | mfspr r12, SPRN_SPRG4R | ||
554 | mfspr r11, SPRN_SPRG1 | ||
555 | mfspr r10, SPRN_SPRG0 | ||
556 | rfi /* Force context change */ | ||
557 | |||
558 | 2: | ||
559 | /* | ||
560 | * The bailout. Restore registers to pre-exception conditions | ||
561 | * and call the heavyweights to help us out. | ||
562 | */ | ||
563 | mfspr r11, SPRN_SPRG7R | ||
564 | mtcr r11 | ||
565 | mfspr r13, SPRN_SPRG5R | ||
566 | mfspr r12, SPRN_SPRG4R | ||
567 | mfspr r11, SPRN_SPRG1 | ||
568 | mfspr r10, SPRN_SPRG0 | ||
569 | b data_access | ||
570 | 496 | ||
571 | /* Instruction Storage Interrupt */ | 497 | /* Instruction Storage Interrupt */ |
572 | INSTRUCTION_STORAGE_EXCEPTION | 498 | INSTRUCTION_STORAGE_EXCEPTION |
@@ -645,15 +571,30 @@ interrupt_base: | |||
645 | lwz r11,PGDIR(r11) | 571 | lwz r11,PGDIR(r11) |
646 | 572 | ||
647 | 4: | 573 | 4: |
574 | /* Mask of required permission bits. Note that while we | ||
575 | * do copy ESR:ST to _PAGE_RW position as trying to write | ||
576 | * to an RO page is pretty common, we don't do it with | ||
577 | * _PAGE_DIRTY. We could do it, but it's a fairly rare | ||
578 | * event so I'd rather take the overhead when it happens | ||
579 | * rather than adding an instruction here. We should measure | ||
580 | * whether the whole thing is worth it in the first place | ||
581 | * as we could avoid loading SPRN_ESR completely in the first | ||
582 | * place... | ||
583 | * | ||
584 | * TODO: Is it worth doing that mfspr & rlwimi in the first | ||
585 | * place or can we save a couple of instructions here ? | ||
586 | */ | ||
587 | mfspr r12,SPRN_ESR | ||
588 | li r13,_PAGE_PRESENT|_PAGE_ACCESSED | ||
589 | rlwimi r13,r12,11,29,29 | ||
590 | |||
648 | FIND_PTE | 591 | FIND_PTE |
649 | andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ | 592 | andc. r13,r13,r11 /* Check permission */ |
650 | beq 2f /* Bail if not present */ | 593 | bne 2f /* Bail if permission mismach */ |
651 | 594 | ||
652 | #ifdef CONFIG_PTE_64BIT | 595 | #ifdef CONFIG_PTE_64BIT |
653 | lwz r13, 0(r12) | 596 | lwz r13, 0(r12) |
654 | #endif | 597 | #endif |
655 | ori r11, r11, _PAGE_ACCESSED | ||
656 | stw r11, PTE_FLAGS_OFFSET(r12) | ||
657 | 598 | ||
658 | /* Jump to common tlb load */ | 599 | /* Jump to common tlb load */ |
659 | b finish_tlb_load | 600 | b finish_tlb_load |
@@ -667,7 +608,7 @@ interrupt_base: | |||
667 | mfspr r12, SPRN_SPRG4R | 608 | mfspr r12, SPRN_SPRG4R |
668 | mfspr r11, SPRN_SPRG1 | 609 | mfspr r11, SPRN_SPRG1 |
669 | mfspr r10, SPRN_SPRG0 | 610 | mfspr r10, SPRN_SPRG0 |
670 | b data_access | 611 | b DataStorage |
671 | 612 | ||
672 | /* Instruction TLB Error Interrupt */ | 613 | /* Instruction TLB Error Interrupt */ |
673 | /* | 614 | /* |
@@ -705,15 +646,16 @@ interrupt_base: | |||
705 | lwz r11,PGDIR(r11) | 646 | lwz r11,PGDIR(r11) |
706 | 647 | ||
707 | 4: | 648 | 4: |
649 | /* Make up the required permissions */ | ||
650 | li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC | ||
651 | |||
708 | FIND_PTE | 652 | FIND_PTE |
709 | andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ | 653 | andc. r13,r13,r11 /* Check permission */ |
710 | beq 2f /* Bail if not present */ | 654 | bne 2f /* Bail if permission mismach */ |
711 | 655 | ||
712 | #ifdef CONFIG_PTE_64BIT | 656 | #ifdef CONFIG_PTE_64BIT |
713 | lwz r13, 0(r12) | 657 | lwz r13, 0(r12) |
714 | #endif | 658 | #endif |
715 | ori r11, r11, _PAGE_ACCESSED | ||
716 | stw r11, PTE_FLAGS_OFFSET(r12) | ||
717 | 659 | ||
718 | /* Jump to common TLB load point */ | 660 | /* Jump to common TLB load point */ |
719 | b finish_tlb_load | 661 | b finish_tlb_load |
@@ -768,29 +710,13 @@ interrupt_base: | |||
768 | * Local functions | 710 | * Local functions |
769 | */ | 711 | */ |
770 | 712 | ||
771 | /* | ||
772 | * Data TLB exceptions will bail out to this point | ||
773 | * if they can't resolve the lightweight TLB fault. | ||
774 | */ | ||
775 | data_access: | ||
776 | NORMAL_EXCEPTION_PROLOG | ||
777 | mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ | ||
778 | stw r5,_ESR(r11) | ||
779 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ | ||
780 | andis. r10,r5,(ESR_ILK|ESR_DLK)@h | ||
781 | bne 1f | ||
782 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | ||
783 | 1: | ||
784 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
785 | EXC_XFER_EE_LITE(0x0300, CacheLockingException) | ||
786 | |||
787 | /* | 713 | /* |
788 | |||
789 | * Both the instruction and data TLB miss get to this | 714 | * Both the instruction and data TLB miss get to this |
790 | * point to load the TLB. | 715 | * point to load the TLB. |
791 | * r10 - EA of fault | 716 | * r10 - EA of fault |
792 | * r11 - TLB (info from Linux PTE) | 717 | * r11 - TLB (info from Linux PTE) |
793 | * r12, r13 - available to use | 718 | * r12 - available to use |
719 | * r13 - upper bits of PTE (if PTE_64BIT) or available to use | ||
794 | * CR5 - results of addr >= PAGE_OFFSET | 720 | * CR5 - results of addr >= PAGE_OFFSET |
795 | * MAS0, MAS1 - loaded with proper value when we get here | 721 | * MAS0, MAS1 - loaded with proper value when we get here |
796 | * MAS2, MAS3 - will need additional info from Linux PTE | 722 | * MAS2, MAS3 - will need additional info from Linux PTE |
@@ -812,20 +738,14 @@ finish_tlb_load: | |||
812 | #endif | 738 | #endif |
813 | mtspr SPRN_MAS2, r12 | 739 | mtspr SPRN_MAS2, r12 |
814 | 740 | ||
815 | bge 5, 1f | 741 | li r10, (_PAGE_HWEXEC | _PAGE_PRESENT) |
816 | 742 | rlwimi r10, r11, 31, 29, 29 /* extract _PAGE_DIRTY into SW */ | |
817 | /* is user addr */ | 743 | and r12, r11, r10 |
818 | andi. r12, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC) | ||
819 | andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */ | 744 | andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */ |
820 | srwi r10, r12, 1 | 745 | slwi r10, r12, 1 |
821 | or r12, r12, r10 /* Copy user perms into supervisor */ | 746 | or r10, r10, r12 |
822 | iseleq r12, 0, r12 | 747 | iseleq r12, r12, r10 |
823 | b 2f | 748 | |
824 | |||
825 | /* is kernel addr */ | ||
826 | 1: rlwinm r12, r11, 31, 29, 29 /* Extract _PAGE_HWWRITE into SW */ | ||
827 | ori r12, r12, (MAS3_SX | MAS3_SR) | ||
828 | |||
829 | #ifdef CONFIG_PTE_64BIT | 749 | #ifdef CONFIG_PTE_64BIT |
830 | 2: rlwimi r12, r13, 24, 0, 7 /* grab RPN[32:39] */ | 750 | 2: rlwimi r12, r13, 24, 0, 7 /* grab RPN[32:39] */ |
831 | rlwimi r12, r11, 24, 8, 19 /* grab RPN[40:51] */ | 751 | rlwimi r12, r11, 24, 8, 19 /* grab RPN[40:51] */ |
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h index 73015f0139de..3a96d001cb75 100644 --- a/include/asm-powerpc/pgtable-ppc32.h +++ b/include/asm-powerpc/pgtable-ppc32.h | |||
@@ -295,10 +295,10 @@ extern int icache_44x_need_flush; | |||
295 | #define _PAGE_PRESENT 0x00001 /* S: PTE contains a translation */ | 295 | #define _PAGE_PRESENT 0x00001 /* S: PTE contains a translation */ |
296 | #define _PAGE_USER 0x00002 /* S: User page (maps to UR) */ | 296 | #define _PAGE_USER 0x00002 /* S: User page (maps to UR) */ |
297 | #define _PAGE_FILE 0x00002 /* S: when !present: nonlinear file mapping */ | 297 | #define _PAGE_FILE 0x00002 /* S: when !present: nonlinear file mapping */ |
298 | #define _PAGE_ACCESSED 0x00004 /* S: Page referenced */ | 298 | #define _PAGE_RW 0x00004 /* S: Write permission (SW) */ |
299 | #define _PAGE_HWWRITE 0x00008 /* H: Dirty & RW, set in exception */ | 299 | #define _PAGE_DIRTY 0x00008 /* S: Page dirty */ |
300 | #define _PAGE_RW 0x00010 /* S: Write permission */ | 300 | #define _PAGE_HWEXEC 0x00010 /* H: SX permission */ |
301 | #define _PAGE_HWEXEC 0x00020 /* H: UX permission */ | 301 | #define _PAGE_ACCESSED 0x00020 /* S: Page referenced */ |
302 | 302 | ||
303 | #define _PAGE_ENDIAN 0x00040 /* H: E bit */ | 303 | #define _PAGE_ENDIAN 0x00040 /* H: E bit */ |
304 | #define _PAGE_GUARDED 0x00080 /* H: G bit */ | 304 | #define _PAGE_GUARDED 0x00080 /* H: G bit */ |
@@ -307,21 +307,14 @@ extern int icache_44x_need_flush; | |||
307 | #define _PAGE_WRITETHRU 0x00400 /* H: W bit */ | 307 | #define _PAGE_WRITETHRU 0x00400 /* H: W bit */ |
308 | 308 | ||
309 | #ifdef CONFIG_PTE_64BIT | 309 | #ifdef CONFIG_PTE_64BIT |
310 | #define _PAGE_DIRTY 0x08000 /* S: Page dirty */ | ||
311 | |||
312 | /* ERPN in a PTE never gets cleared, ignore it */ | 310 | /* ERPN in a PTE never gets cleared, ignore it */ |
313 | #define _PTE_NONE_MASK 0xffffffffffff0000ULL | 311 | #define _PTE_NONE_MASK 0xffffffffffff0000ULL |
314 | #else | ||
315 | #define _PAGE_DIRTY 0x00800 /* S: Page dirty */ | ||
316 | #endif | 312 | #endif |
317 | 313 | ||
318 | #define _PMD_PRESENT 0 | 314 | #define _PMD_PRESENT 0 |
319 | #define _PMD_PRESENT_MASK (PAGE_MASK) | 315 | #define _PMD_PRESENT_MASK (PAGE_MASK) |
320 | #define _PMD_BAD (~PAGE_MASK) | 316 | #define _PMD_BAD (~PAGE_MASK) |
321 | 317 | ||
322 | /* Until my rework is finished, FSL BookE still needs atomic PTE updates */ | ||
323 | #define PTE_ATOMIC_UPDATES 1 | ||
324 | |||
325 | #elif defined(CONFIG_8xx) | 318 | #elif defined(CONFIG_8xx) |
326 | /* Definitions for 8xx embedded chips. */ | 319 | /* Definitions for 8xx embedded chips. */ |
327 | #define _PAGE_PRESENT 0x0001 /* Page is valid */ | 320 | #define _PAGE_PRESENT 0x0001 /* Page is valid */ |