diff options
-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 */ |