Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/32s: Introduce _PAGE_READ and remove _PAGE_USER

On 603 MMU, TLB missed are handled by SW and there are separated
DTLB and ITLB. It is therefore possible to implement execute-only
protection by not loading DTLB when read access is not permitted.

To do that, _PAGE_READ flag is needed but there is no bit available
for it in PTE. On the other hand the only real use of _PAGE_USER is
to implement PAGE_NONE by clearing _PAGE_USER.

As _PAGE_NONE can also be implemented by clearing _PAGE_READ, remove
_PAGE_USER and add _PAGE_READ. Then use the virtual address to know
whether user rights or kernel rights are to be used.

With that change, 603 MMU now honors execute-only protection.

For hash (604) MMU it is more tricky because hash table is common to
load/store and execute. Nevertheless it is still possible to check
whether _PAGE_READ is set before loading hash table for a load/store
access. At least it can't be read unless it is executed first.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/b7702dd5a041ec59055ed2880f4952e94c087a2e.1695659959.git.christophe.leroy@csgroup.eu

authored by

Christophe Leroy and committed by
Michael Ellerman
bac4cffc 46ebef51

+60 -71
+12 -36
arch/powerpc/include/asm/book3s/32/pgtable.h
··· 20 20 21 21 #define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ 22 22 #define _PAGE_HASHPTE 0x002 /* hash_page has made an HPTE for this pte */ 23 - #define _PAGE_USER 0x004 /* usermode access allowed */ 23 + #define _PAGE_READ 0x004 /* software: read access allowed */ 24 24 #define _PAGE_GUARDED 0x008 /* G: prohibit speculative access */ 25 25 #define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */ 26 26 #define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */ ··· 28 28 #define _PAGE_DIRTY 0x080 /* C: page changed */ 29 29 #define _PAGE_ACCESSED 0x100 /* R: page referenced */ 30 30 #define _PAGE_EXEC 0x200 /* software: exec allowed */ 31 - #define _PAGE_RW 0x400 /* software: user write access allowed */ 31 + #define _PAGE_WRITE 0x400 /* software: user write access allowed */ 32 32 #define _PAGE_SPECIAL 0x800 /* software: Special page */ 33 - 34 - #define _PAGE_WRITE _PAGE_RW 35 33 36 34 #ifdef CONFIG_PTE_64BIT 37 35 /* We never clear the high word of the pte */ ··· 42 44 #define _PMD_PRESENT_MASK (PAGE_MASK) 43 45 #define _PMD_BAD (~PAGE_MASK) 44 46 45 - /* We borrow the _PAGE_USER bit to store the exclusive marker in swap PTEs. */ 46 - #define _PAGE_SWP_EXCLUSIVE _PAGE_USER 47 + /* We borrow the _PAGE_READ bit to store the exclusive marker in swap PTEs. */ 48 + #define _PAGE_SWP_EXCLUSIVE _PAGE_READ 47 49 48 50 /* And here we include common definitions */ 49 51 50 - #define _PAGE_KERNEL_RO 0 51 - #define _PAGE_KERNEL_ROX (_PAGE_EXEC) 52 - #define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW) 53 - #define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC) 54 - 55 52 #define _PAGE_HPTEFLAGS _PAGE_HASHPTE 56 - 57 - #ifndef __ASSEMBLY__ 58 - 59 - static inline bool pte_user(pte_t pte) 60 - { 61 - return pte_val(pte) & _PAGE_USER; 62 - } 63 - #endif /* __ASSEMBLY__ */ 64 53 65 54 /* 66 55 * Location of the PFN in the PTE. Most 32-bit platforms use the same ··· 84 99 #define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) 85 100 #define _PAGE_BASE (_PAGE_BASE_NC | _PAGE_COHERENT) 86 101 87 - /* 88 - * Permission masks used to generate the __P and __S table. 89 - * 90 - * Note:__pgprot is defined in arch/powerpc/include/asm/page.h 91 - * 92 - * Write permissions imply read permissions for now. 93 - */ 94 - #define PAGE_NONE __pgprot(_PAGE_BASE) 95 - #define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) 96 - #define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) 97 - #define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) 98 - #define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) 99 - #define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) 100 - #define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) 102 + #include <asm/pgtable-masks.h> 101 103 102 104 /* Permission masks used for kernel mappings */ 103 105 #define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) ··· 380 408 } 381 409 382 410 /* Generic accessors to PTE bits */ 411 + static inline bool pte_read(pte_t pte) 412 + { 413 + return !!(pte_val(pte) & _PAGE_READ); 414 + } 415 + 383 416 static inline bool pte_write(pte_t pte) 384 417 { 385 418 return !!(pte_val(pte) & _PAGE_WRITE); 386 419 } 387 420 388 - static inline int pte_read(pte_t pte) { return 1; } 389 421 static inline int pte_dirty(pte_t pte) { return !!(pte_val(pte) & _PAGE_DIRTY); } 390 422 static inline int pte_young(pte_t pte) { return !!(pte_val(pte) & _PAGE_ACCESSED); } 391 423 static inline int pte_special(pte_t pte) { return !!(pte_val(pte) & _PAGE_SPECIAL); } ··· 424 448 static inline bool pte_access_permitted(pte_t pte, bool write) 425 449 { 426 450 /* 427 - * A read-only access is controlled by _PAGE_USER bit. 451 + * A read-only access is controlled by _PAGE_READ bit. 428 452 * We have _PAGE_READ set for WRITE and EXECUTE 429 453 */ 430 - if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte)) 454 + if (!pte_present(pte) || !pte_read(pte)) 431 455 return false; 432 456 433 457 if (write && !pte_write(pte))
+33 -28
arch/powerpc/kernel/head_book3s_32.S
··· 412 412 . = INTERRUPT_INST_TLB_MISS_603 413 413 InstructionTLBMiss: 414 414 /* 415 - * r0: scratch 415 + * r0: userspace flag (later scratch) 416 416 * r1: linux style pte ( later becomes ppc hardware pte ) 417 417 * r2: ptr to linux-style pte 418 - * r3: scratch 418 + * r3: fault address 419 419 */ 420 420 /* Get PTE (linux-style) and check access */ 421 421 mfspr r3,SPRN_IMISS ··· 424 424 cmplw 0,r1,r3 425 425 #endif 426 426 mfspr r2, SPRN_SDR1 427 - li r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER 427 + li r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC 428 428 rlwinm r2, r2, 28, 0xfffff000 429 429 #ifdef CONFIG_MODULES 430 + li r0, 3 430 431 bgt- 112f 431 432 lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */ 432 - li r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC 433 + li r0, 0 433 434 addi r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l /* kernel page table */ 434 435 #endif 435 436 112: rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ ··· 438 437 rlwinm. r2,r2,0,0,19 /* extract address of pte page */ 439 438 beq- InstructionAddressInvalid /* return if no mapping */ 440 439 rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ 441 - lwz r0,0(r2) /* get linux-style pte */ 442 - andc. r1,r1,r0 /* check access & ~permission */ 440 + lwz r2,0(r2) /* get linux-style pte */ 441 + andc. r1,r1,r2 /* check access & ~permission */ 443 442 bne- InstructionAddressInvalid /* return if access not permitted */ 444 443 /* Convert linux-style PTE to low word of PPC-style PTE */ 445 - rlwimi r0,r0,32-2,31,31 /* _PAGE_USER -> PP lsb */ 444 + #ifdef CONFIG_MODULES 445 + rlwimi r2, r0, 0, 31, 31 /* userspace ? -> PP lsb */ 446 + #endif 446 447 ori r1, r1, 0xe06 /* clear out reserved bits */ 447 - andc r1, r0, r1 /* PP = user? 1 : 0 */ 448 + andc r1, r2, r1 /* PP = user? 1 : 0 */ 448 449 BEGIN_FTR_SECTION 449 450 rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */ 450 451 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) ··· 481 478 . = INTERRUPT_DATA_LOAD_TLB_MISS_603 482 479 DataLoadTLBMiss: 483 480 /* 484 - * r0: scratch 481 + * r0: userspace flag (later scratch) 485 482 * r1: linux style pte ( later becomes ppc hardware pte ) 486 483 * r2: ptr to linux-style pte 487 - * r3: scratch 484 + * r3: fault address 488 485 */ 489 486 /* Get PTE (linux-style) and check access */ 490 487 mfspr r3,SPRN_DMISS 491 488 lis r1, TASK_SIZE@h /* check if kernel address */ 492 489 cmplw 0,r1,r3 493 490 mfspr r2, SPRN_SDR1 494 - li r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER 491 + li r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_READ 495 492 rlwinm r2, r2, 28, 0xfffff000 493 + li r0, 3 496 494 bgt- 112f 497 495 lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */ 498 - li r1, _PAGE_PRESENT | _PAGE_ACCESSED 496 + li r0, 0 499 497 addi r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l /* kernel page table */ 500 498 112: rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ 501 499 lwz r2,0(r2) /* get pmd entry */ 502 500 rlwinm. r2,r2,0,0,19 /* extract address of pte page */ 503 501 beq- DataAddressInvalid /* return if no mapping */ 504 502 rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ 505 - lwz r0,0(r2) /* get linux-style pte */ 506 - andc. r1,r1,r0 /* check access & ~permission */ 503 + lwz r2,0(r2) /* get linux-style pte */ 504 + andc. r1,r1,r2 /* check access & ~permission */ 507 505 bne- DataAddressInvalid /* return if access not permitted */ 508 506 /* Convert linux-style PTE to low word of PPC-style PTE */ 509 - rlwinm r1,r0,32-9,30,30 /* _PAGE_WRITE -> PP msb */ 510 - rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */ 511 - rlwimi r1,r0,32-3,24,24 /* _PAGE_WRITE -> _PAGE_DIRTY */ 512 - rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */ 507 + rlwinm r1,r2,32-9,30,30 /* _PAGE_WRITE -> PP msb */ 508 + rlwimi r2,r0,0,30,31 /* userspace ? -> PP */ 509 + rlwimi r1,r2,32-3,24,24 /* _PAGE_WRITE -> _PAGE_DIRTY */ 513 510 xori r1,r1,_PAGE_DIRTY /* clear dirty when not rw */ 514 511 ori r1,r1,0xe04 /* clear out reserved bits */ 515 - andc r1,r0,r1 /* PP = user? rw? 1: 3: 0 */ 512 + andc r1,r2,r1 /* PP = user? rw? 1: 3: 0 */ 516 513 BEGIN_FTR_SECTION 517 514 rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */ 518 515 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) ··· 561 558 . = INTERRUPT_DATA_STORE_TLB_MISS_603 562 559 DataStoreTLBMiss: 563 560 /* 564 - * r0: scratch 561 + * r0: userspace flag (later scratch) 565 562 * r1: linux style pte ( later becomes ppc hardware pte ) 566 563 * r2: ptr to linux-style pte 567 - * r3: scratch 564 + * r3: fault address 568 565 */ 569 566 /* Get PTE (linux-style) and check access */ 570 567 mfspr r3,SPRN_DMISS 571 568 lis r1, TASK_SIZE@h /* check if kernel address */ 572 569 cmplw 0,r1,r3 573 570 mfspr r2, SPRN_SDR1 574 - li r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER 571 + li r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED 575 572 rlwinm r2, r2, 28, 0xfffff000 573 + li r0, 3 576 574 bgt- 112f 577 575 lis r2, (swapper_pg_dir - PAGE_OFFSET)@ha /* if kernel address, use */ 578 - li r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED 576 + li r0, 0 579 577 addi r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l /* kernel page table */ 580 578 112: rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ 581 579 lwz r2,0(r2) /* get pmd entry */ 582 580 rlwinm. r2,r2,0,0,19 /* extract address of pte page */ 583 581 beq- DataAddressInvalid /* return if no mapping */ 584 582 rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ 585 - lwz r0,0(r2) /* get linux-style pte */ 586 - andc. r1,r1,r0 /* check access & ~permission */ 583 + lwz r2,0(r2) /* get linux-style pte */ 584 + andc. r1,r1,r2 /* check access & ~permission */ 587 585 bne- DataAddressInvalid /* return if access not permitted */ 588 586 /* Convert linux-style PTE to low word of PPC-style PTE */ 589 - rlwimi r0,r0,32-2,31,31 /* _PAGE_USER -> PP lsb */ 587 + rlwimi r2,r0,0,31,31 /* userspace ? -> PP lsb */ 590 588 li r1,0xe06 /* clear out reserved bits & PP msb */ 591 - andc r1,r0,r1 /* PP = user? 1: 0 */ 589 + andc r1,r2,r1 /* PP = user? 1: 0 */ 592 590 BEGIN_FTR_SECTION 593 591 rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */ 594 592 END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) ··· 694 690 mfsrr0 r5 695 691 mfsrr1 r9 696 692 rlwinm r3, r3, 32 - 15, _PAGE_WRITE /* DSISR_STORE -> _PAGE_WRITE */ 693 + ori r3, r3, _PAGE_PRESENT | _PAGE_READ 697 694 bl hash_page 698 695 mfspr r10, SPRN_SPRG_THREAD 699 696 restore_regs_thread r10 ··· 704 699 mr r11, r10 705 700 mfspr r10, SPRN_SPRG_THREAD 706 701 save_regs_thread r10 707 - li r3, 0 702 + li r3, _PAGE_PRESENT | _PAGE_EXEC 708 703 lwz r4, SRR0(r10) 709 704 lwz r9, SRR1(r10) 710 705 bl hash_page
+15 -7
arch/powerpc/mm/book3s32/hash_low.S
··· 36 36 37 37 /* 38 38 * Load a PTE into the hash table, if possible. 39 - * The address is in r4, and r3 contains an access flag: 40 - * _PAGE_WRITE (0x400) if a write. 39 + * The address is in r4, and r3 contains required access flags: 40 + * - For ISI: _PAGE_PRESENT | _PAGE_EXEC 41 + * - For DSI: _PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE if a write. 41 42 * r9 contains the SRR1 value, from which we use the MSR_PR bit. 42 43 * SPRG_THREAD contains the physical address of the current task's thread. 43 44 * ··· 68 67 lis r0, TASK_SIZE@h /* check if kernel address */ 69 68 cmplw 0,r4,r0 70 69 mfspr r8,SPRN_SPRG_THREAD /* current task's THREAD (phys) */ 71 - ori r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */ 72 70 lwz r5,PGDIR(r8) /* virt page-table root */ 73 71 blt+ 112f /* assume user more likely */ 74 72 lis r5,swapper_pg_dir@ha /* if kernel address, use */ 73 + andi. r0,r9,MSR_PR /* Check usermode */ 75 74 addi r5,r5,swapper_pg_dir@l /* kernel page table */ 76 - rlwimi r3,r9,32-12,29,29 /* MSR_PR -> _PAGE_USER */ 75 + #ifdef CONFIG_SMP 76 + bne- .Lhash_page_out /* return if usermode */ 77 + #else 78 + bnelr- 79 + #endif 77 80 112: tophys(r5, r5) 78 81 #ifndef CONFIG_PTE_64BIT 79 82 rlwimi r5,r4,12,20,29 /* insert top 10 bits of address */ ··· 312 307 __REF 313 308 _GLOBAL(create_hpte) 314 309 /* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */ 310 + lis r0, TASK_SIZE@h 311 + rlwinm r5,r5,0,~3 /* Clear PP bits */ 312 + cmplw r4,r0 315 313 rlwinm r8,r5,32-9,30,30 /* _PAGE_WRITE -> PP msb */ 316 314 rlwinm r0,r5,32-6,30,30 /* _PAGE_DIRTY -> PP msb */ 317 315 and r8,r8,r0 /* writable if _RW & _DIRTY */ 318 - rlwimi r5,r5,32-1,30,30 /* _PAGE_USER -> PP msb */ 319 - rlwimi r5,r5,32-2,31,31 /* _PAGE_USER -> PP lsb */ 320 - ori r8,r8,0xe04 /* clear out reserved bits */ 316 + bge- 1f /* Kernelspace ? Skip */ 317 + ori r5,r5,3 /* Userspace ? PP = 3 */ 318 + 1: ori r8,r8,0xe04 /* clear out reserved bits */ 321 319 andc r8,r5,r8 /* PP = user? (rw&dirty? 1: 3): 0 */ 322 320 BEGIN_FTR_SECTION 323 321 rlwinm r8,r8,0,~_PAGE_COHERENT /* clear M (coherence not required) */