aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc32.h7
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h3
-rw-r--r--arch/powerpc/include/asm/pte-40x.h2
-rw-r--r--arch/powerpc/include/asm/pte-44x.h2
-rw-r--r--arch/powerpc/include/asm/pte-8xx.h1
-rw-r--r--arch/powerpc/include/asm/pte-book3e.h13
-rw-r--r--arch/powerpc/include/asm/pte-common.h22
-rw-r--r--arch/powerpc/include/asm/pte-fsl-booke.h2
-rw-r--r--arch/powerpc/include/asm/pte-hash32.h1
-rw-r--r--arch/powerpc/kernel/head_44x.S2
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S4
-rw-r--r--arch/powerpc/mm/40x_mmu.c4
-rw-r--r--arch/powerpc/mm/pgtable.c167
-rw-r--r--arch/powerpc/mm/pgtable_32.c2
-rw-r--r--arch/powerpc/mm/tlb_low_64e.S4
15 files changed, 149 insertions, 87 deletions
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index c9ff9d75990e..f2c52e253956 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -186,7 +186,7 @@ static inline unsigned long pte_update(pte_t *p,
186#endif /* !PTE_ATOMIC_UPDATES */ 186#endif /* !PTE_ATOMIC_UPDATES */
187 187
188#ifdef CONFIG_44x 188#ifdef CONFIG_44x
189 if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) 189 if ((old & _PAGE_USER) && (old & _PAGE_EXEC))
190 icache_44x_need_flush = 1; 190 icache_44x_need_flush = 1;
191#endif 191#endif
192 return old; 192 return old;
@@ -217,7 +217,7 @@ static inline unsigned long long pte_update(pte_t *p,
217#endif /* !PTE_ATOMIC_UPDATES */ 217#endif /* !PTE_ATOMIC_UPDATES */
218 218
219#ifdef CONFIG_44x 219#ifdef CONFIG_44x
220 if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC)) 220 if ((old & _PAGE_USER) && (old & _PAGE_EXEC))
221 icache_44x_need_flush = 1; 221 icache_44x_need_flush = 1;
222#endif 222#endif
223 return old; 223 return old;
@@ -267,8 +267,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
267static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) 267static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
268{ 268{
269 unsigned long bits = pte_val(entry) & 269 unsigned long bits = pte_val(entry) &
270 (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | 270 (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
271 _PAGE_HWEXEC | _PAGE_EXEC);
272 pte_update(ptep, 0, bits); 271 pte_update(ptep, 0, bits);
273} 272}
274 273
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 200ec2dfa034..806abe7a3fa5 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -313,8 +313,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
313static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) 313static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
314{ 314{
315 unsigned long bits = pte_val(entry) & 315 unsigned long bits = pte_val(entry) &
316 (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | 316 (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
317 _PAGE_EXEC | _PAGE_HWEXEC);
318 317
319#ifdef PTE_ATOMIC_UPDATES 318#ifdef PTE_ATOMIC_UPDATES
320 unsigned long old, tmp; 319 unsigned long old, tmp;
diff --git a/arch/powerpc/include/asm/pte-40x.h b/arch/powerpc/include/asm/pte-40x.h
index 07630faae029..6c3e1f4378d4 100644
--- a/arch/powerpc/include/asm/pte-40x.h
+++ b/arch/powerpc/include/asm/pte-40x.h
@@ -46,7 +46,7 @@
46#define _PAGE_RW 0x040 /* software: Writes permitted */ 46#define _PAGE_RW 0x040 /* software: Writes permitted */
47#define _PAGE_DIRTY 0x080 /* software: dirty page */ 47#define _PAGE_DIRTY 0x080 /* software: dirty page */
48#define _PAGE_HWWRITE 0x100 /* hardware: Dirty & RW, set in exception */ 48#define _PAGE_HWWRITE 0x100 /* hardware: Dirty & RW, set in exception */
49#define _PAGE_HWEXEC 0x200 /* hardware: EX permission */ 49#define _PAGE_EXEC 0x200 /* hardware: EX permission */
50#define _PAGE_ACCESSED 0x400 /* software: R: page referenced */ 50#define _PAGE_ACCESSED 0x400 /* software: R: page referenced */
51 51
52#define _PMD_PRESENT 0x400 /* PMD points to page of PTEs */ 52#define _PMD_PRESENT 0x400 /* PMD points to page of PTEs */
diff --git a/arch/powerpc/include/asm/pte-44x.h b/arch/powerpc/include/asm/pte-44x.h
index 37e98bcf83e0..4192b9bad901 100644
--- a/arch/powerpc/include/asm/pte-44x.h
+++ b/arch/powerpc/include/asm/pte-44x.h
@@ -78,7 +78,7 @@
78#define _PAGE_PRESENT 0x00000001 /* S: PTE valid */ 78#define _PAGE_PRESENT 0x00000001 /* S: PTE valid */
79#define _PAGE_RW 0x00000002 /* S: Write permission */ 79#define _PAGE_RW 0x00000002 /* S: Write permission */
80#define _PAGE_FILE 0x00000004 /* S: nonlinear file mapping */ 80#define _PAGE_FILE 0x00000004 /* S: nonlinear file mapping */
81#define _PAGE_HWEXEC 0x00000004 /* H: Execute permission */ 81#define _PAGE_EXEC 0x00000004 /* H: Execute permission */
82#define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */ 82#define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */
83#define _PAGE_DIRTY 0x00000010 /* S: Page dirty */ 83#define _PAGE_DIRTY 0x00000010 /* S: Page dirty */
84#define _PAGE_SPECIAL 0x00000020 /* S: Special page */ 84#define _PAGE_SPECIAL 0x00000020 /* S: Special page */
diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/pte-8xx.h
index 8c6e31251034..94e979718dcf 100644
--- a/arch/powerpc/include/asm/pte-8xx.h
+++ b/arch/powerpc/include/asm/pte-8xx.h
@@ -36,7 +36,6 @@
36/* These five software bits must be masked out when the entry is loaded 36/* These five software bits must be masked out when the entry is loaded
37 * into the TLB. 37 * into the TLB.
38 */ 38 */
39#define _PAGE_EXEC 0x0008 /* software: i-cache coherency required */
40#define _PAGE_GUARDED 0x0010 /* software: guarded access */ 39#define _PAGE_GUARDED 0x0010 /* software: guarded access */
41#define _PAGE_DIRTY 0x0020 /* software: page changed */ 40#define _PAGE_DIRTY 0x0020 /* software: page changed */
42#define _PAGE_RW 0x0040 /* software: user write access allowed */ 41#define _PAGE_RW 0x0040 /* software: user write access allowed */
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h
index 1d27c77d7704..9800565aebb8 100644
--- a/arch/powerpc/include/asm/pte-book3e.h
+++ b/arch/powerpc/include/asm/pte-book3e.h
@@ -37,12 +37,13 @@
37#define _PAGE_WRITETHRU 0x800000 /* W: cache write-through */ 37#define _PAGE_WRITETHRU 0x800000 /* W: cache write-through */
38 38
39/* "Higher level" linux bit combinations */ 39/* "Higher level" linux bit combinations */
40#define _PAGE_EXEC _PAGE_BAP_SX /* Can be executed from potentially */ 40#define _PAGE_EXEC _PAGE_BAP_UX /* .. and was cache cleaned */
41#define _PAGE_HWEXEC _PAGE_BAP_UX /* .. and was cache cleaned */ 41#define _PAGE_RW (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
42#define _PAGE_RW (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */ 42#define _PAGE_KERNEL_RW (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
43#define _PAGE_KERNEL_RW (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY) 43#define _PAGE_KERNEL_RO (_PAGE_BAP_SR)
44#define _PAGE_KERNEL_RO (_PAGE_BAP_SR) 44#define _PAGE_KERNEL_RWX (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY | _PAGE_BAP_SX)
45#define _PAGE_USER (_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */ 45#define _PAGE_KERNEL_ROX (_PAGE_BAP_SR | _PAGE_BAP_SX)
46#define _PAGE_USER (_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */
46 47
47#define _PAGE_HASHPTE 0 48#define _PAGE_HASHPTE 0
48#define _PAGE_BUSY 0 49#define _PAGE_BUSY 0
diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h
index 8bb6464ba619..c3b65076a263 100644
--- a/arch/powerpc/include/asm/pte-common.h
+++ b/arch/powerpc/include/asm/pte-common.h
@@ -13,9 +13,6 @@
13#ifndef _PAGE_HWWRITE 13#ifndef _PAGE_HWWRITE
14#define _PAGE_HWWRITE 0 14#define _PAGE_HWWRITE 0
15#endif 15#endif
16#ifndef _PAGE_HWEXEC
17#define _PAGE_HWEXEC 0
18#endif
19#ifndef _PAGE_EXEC 16#ifndef _PAGE_EXEC
20#define _PAGE_EXEC 0 17#define _PAGE_EXEC 0
21#endif 18#endif
@@ -48,10 +45,16 @@
48#define PMD_PAGE_SIZE(pmd) bad_call_to_PMD_PAGE_SIZE() 45#define PMD_PAGE_SIZE(pmd) bad_call_to_PMD_PAGE_SIZE()
49#endif 46#endif
50#ifndef _PAGE_KERNEL_RO 47#ifndef _PAGE_KERNEL_RO
51#define _PAGE_KERNEL_RO 0 48#define _PAGE_KERNEL_RO 0
49#endif
50#ifndef _PAGE_KERNEL_ROX
51#define _PAGE_KERNEL_ROX (_PAGE_EXEC)
52#endif 52#endif
53#ifndef _PAGE_KERNEL_RW 53#ifndef _PAGE_KERNEL_RW
54#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE) 54#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE)
55#endif
56#ifndef _PAGE_KERNEL_RWX
57#define _PAGE_KERNEL_RWX (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE | _PAGE_EXEC)
55#endif 58#endif
56#ifndef _PAGE_HPTEFLAGS 59#ifndef _PAGE_HPTEFLAGS
57#define _PAGE_HPTEFLAGS _PAGE_HASHPTE 60#define _PAGE_HPTEFLAGS _PAGE_HASHPTE
@@ -96,8 +99,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
96#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ 99#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
97 _PAGE_WRITETHRU | _PAGE_ENDIAN | _PAGE_4K_PFN | \ 100 _PAGE_WRITETHRU | _PAGE_ENDIAN | _PAGE_4K_PFN | \
98 _PAGE_USER | _PAGE_ACCESSED | \ 101 _PAGE_USER | _PAGE_ACCESSED | \
99 _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \ 102 _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC)
100 _PAGE_EXEC | _PAGE_HWEXEC)
101 103
102/* 104/*
103 * We define 2 sets of base prot bits, one for basic pages (ie, 105 * We define 2 sets of base prot bits, one for basic pages (ie,
@@ -154,11 +156,9 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
154 _PAGE_NO_CACHE) 156 _PAGE_NO_CACHE)
155#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \ 157#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \
156 _PAGE_NO_CACHE | _PAGE_GUARDED) 158 _PAGE_NO_CACHE | _PAGE_GUARDED)
157#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW | _PAGE_EXEC | \ 159#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX)
158 _PAGE_HWEXEC)
159#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO) 160#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO)
160#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO | _PAGE_EXEC | \ 161#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX)
161 _PAGE_HWEXEC)
162 162
163/* Protection used for kernel text. We want the debuggers to be able to 163/* Protection used for kernel text. We want the debuggers to be able to
164 * set breakpoints anywhere, so don't write protect the kernel text 164 * set breakpoints anywhere, so don't write protect the kernel text
diff --git a/arch/powerpc/include/asm/pte-fsl-booke.h b/arch/powerpc/include/asm/pte-fsl-booke.h
index 10820f58acf5..ce8a9e94ce7f 100644
--- a/arch/powerpc/include/asm/pte-fsl-booke.h
+++ b/arch/powerpc/include/asm/pte-fsl-booke.h
@@ -23,7 +23,7 @@
23#define _PAGE_FILE 0x00002 /* S: when !present: nonlinear file mapping */ 23#define _PAGE_FILE 0x00002 /* S: when !present: nonlinear file mapping */
24#define _PAGE_RW 0x00004 /* S: Write permission (SW) */ 24#define _PAGE_RW 0x00004 /* S: Write permission (SW) */
25#define _PAGE_DIRTY 0x00008 /* S: Page dirty */ 25#define _PAGE_DIRTY 0x00008 /* S: Page dirty */
26#define _PAGE_HWEXEC 0x00010 /* H: SX permission */ 26#define _PAGE_EXEC 0x00010 /* H: SX permission */
27#define _PAGE_ACCESSED 0x00020 /* S: Page referenced */ 27#define _PAGE_ACCESSED 0x00020 /* S: Page referenced */
28 28
29#define _PAGE_ENDIAN 0x00040 /* H: E bit */ 29#define _PAGE_ENDIAN 0x00040 /* H: E bit */
diff --git a/arch/powerpc/include/asm/pte-hash32.h b/arch/powerpc/include/asm/pte-hash32.h
index 16e571c7f9ef..4aad4132d0a8 100644
--- a/arch/powerpc/include/asm/pte-hash32.h
+++ b/arch/powerpc/include/asm/pte-hash32.h
@@ -26,7 +26,6 @@
26#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */ 26#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */
27#define _PAGE_DIRTY 0x080 /* C: page changed */ 27#define _PAGE_DIRTY 0x080 /* C: page changed */
28#define _PAGE_ACCESSED 0x100 /* R: page referenced */ 28#define _PAGE_ACCESSED 0x100 /* R: page referenced */
29#define _PAGE_EXEC 0x200 /* software: i-cache coherency required */
30#define _PAGE_RW 0x400 /* software: user write access allowed */ 29#define _PAGE_RW 0x400 /* software: user write access allowed */
31#define _PAGE_SPECIAL 0x800 /* software: Special page */ 30#define _PAGE_SPECIAL 0x800 /* software: Special page */
32 31
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 656cfb2d6666..711368b993f2 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -497,7 +497,7 @@ tlb_44x_patch_hwater_D:
497 mtspr SPRN_MMUCR,r12 497 mtspr SPRN_MMUCR,r12
498 498
499 /* Make up the required permissions */ 499 /* Make up the required permissions */
500 li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC 500 li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
501 501
502 /* Compute pgdir/pmd offset */ 502 /* Compute pgdir/pmd offset */
503 rlwinm r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29 503 rlwinm r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index eca80482ae72..2c5af5256479 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -643,7 +643,7 @@ interrupt_base:
643 643
6444: 6444:
645 /* Make up the required permissions */ 645 /* Make up the required permissions */
646 li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC 646 li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
647 647
648 FIND_PTE 648 FIND_PTE
649 andc. r13,r13,r11 /* Check permission */ 649 andc. r13,r13,r11 /* Check permission */
@@ -742,7 +742,7 @@ finish_tlb_load:
742#endif 742#endif
743 mtspr SPRN_MAS2, r12 743 mtspr SPRN_MAS2, r12
744 744
745 li r10, (_PAGE_HWEXEC | _PAGE_PRESENT) 745 li r10, (_PAGE_EXEC | _PAGE_PRESENT)
746 rlwimi r10, r11, 31, 29, 29 /* extract _PAGE_DIRTY into SW */ 746 rlwimi r10, r11, 31, 29, 29 /* extract _PAGE_DIRTY into SW */
747 and r12, r11, r10 747 and r12, r11, r10
748 andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */ 748 andi. r10, r11, _PAGE_USER /* Test for _PAGE_USER */
diff --git a/arch/powerpc/mm/40x_mmu.c b/arch/powerpc/mm/40x_mmu.c
index 29954dc28942..f5e7b9ce63dd 100644
--- a/arch/powerpc/mm/40x_mmu.c
+++ b/arch/powerpc/mm/40x_mmu.c
@@ -105,7 +105,7 @@ unsigned long __init mmu_mapin_ram(void)
105 105
106 while (s >= LARGE_PAGE_SIZE_16M) { 106 while (s >= LARGE_PAGE_SIZE_16M) {
107 pmd_t *pmdp; 107 pmd_t *pmdp;
108 unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE; 108 unsigned long val = p | _PMD_SIZE_16M | _PAGE_EXEC | _PAGE_HWWRITE;
109 109
110 pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); 110 pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v);
111 pmd_val(*pmdp++) = val; 111 pmd_val(*pmdp++) = val;
@@ -120,7 +120,7 @@ unsigned long __init mmu_mapin_ram(void)
120 120
121 while (s >= LARGE_PAGE_SIZE_4M) { 121 while (s >= LARGE_PAGE_SIZE_4M) {
122 pmd_t *pmdp; 122 pmd_t *pmdp;
123 unsigned long val = p | _PMD_SIZE_4M | _PAGE_HWEXEC | _PAGE_HWWRITE; 123 unsigned long val = p | _PMD_SIZE_4M | _PAGE_EXEC | _PAGE_HWWRITE;
124 124
125 pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); 125 pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v);
126 pmd_val(*pmdp) = val; 126 pmd_val(*pmdp) = val;
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index b6b32487e740..83f1551ec2c9 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -128,28 +128,6 @@ void pte_free_finish(void)
128 128
129#endif /* CONFIG_SMP */ 129#endif /* CONFIG_SMP */
130 130
131/*
132 * Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags()
133 */
134static pte_t do_dcache_icache_coherency(pte_t pte)
135{
136 unsigned long pfn = pte_pfn(pte);
137 struct page *page;
138
139 if (unlikely(!pfn_valid(pfn)))
140 return pte;
141 page = pfn_to_page(pfn);
142
143 if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) {
144 pr_devel("do_dcache_icache_coherency... flushing\n");
145 flush_dcache_icache_page(page);
146 set_bit(PG_arch_1, &page->flags);
147 }
148 else
149 pr_devel("do_dcache_icache_coherency... already clean\n");
150 return __pte(pte_val(pte) | _PAGE_HWEXEC);
151}
152
153static inline int is_exec_fault(void) 131static inline int is_exec_fault(void)
154{ 132{
155 return current->thread.regs && TRAP(current->thread.regs) == 0x400; 133 return current->thread.regs && TRAP(current->thread.regs) == 0x400;
@@ -157,49 +135,139 @@ static inline int is_exec_fault(void)
157 135
158/* We only try to do i/d cache coherency on stuff that looks like 136/* We only try to do i/d cache coherency on stuff that looks like
159 * reasonably "normal" PTEs. We currently require a PTE to be present 137 * reasonably "normal" PTEs. We currently require a PTE to be present
160 * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE 138 * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE. We also only do that
139 * on userspace PTEs
161 */ 140 */
162static inline int pte_looks_normal(pte_t pte) 141static inline int pte_looks_normal(pte_t pte)
163{ 142{
164 return (pte_val(pte) & 143 return (pte_val(pte) &
165 (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE)) == 144 (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE | _PAGE_USER)) ==
166 (_PAGE_PRESENT); 145 (_PAGE_PRESENT | _PAGE_USER);
167} 146}
168 147
169#if defined(CONFIG_PPC_STD_MMU) 148struct page * maybe_pte_to_page(pte_t pte)
149{
150 unsigned long pfn = pte_pfn(pte);
151 struct page *page;
152
153 if (unlikely(!pfn_valid(pfn)))
154 return NULL;
155 page = pfn_to_page(pfn);
156 if (PageReserved(page))
157 return NULL;
158 return page;
159}
160
161#if defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0
162
170/* Server-style MMU handles coherency when hashing if HW exec permission 163/* Server-style MMU handles coherency when hashing if HW exec permission
171 * is supposed per page (currently 64-bit only). Else, we always flush 164 * is supposed per page (currently 64-bit only). If not, then, we always
172 * valid PTEs in set_pte. 165 * flush the cache for valid PTEs in set_pte. Embedded CPU without HW exec
166 * support falls into the same category.
173 */ 167 */
174static inline int pte_need_exec_flush(pte_t pte, int set_pte) 168
169static pte_t set_pte_filter(pte_t pte)
175{ 170{
176 return set_pte && pte_looks_normal(pte) && 171 pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
177 !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) || 172 if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
178 cpu_has_feature(CPU_FTR_NOEXECUTE)); 173 cpu_has_feature(CPU_FTR_NOEXECUTE))) {
174 struct page *pg = maybe_pte_to_page(pte);
175 if (!pg)
176 return pte;
177 if (!test_bit(PG_arch_1, &pg->flags)) {
178 flush_dcache_icache_page(pg);
179 set_bit(PG_arch_1, &pg->flags);
180 }
181 }
182 return pte;
179} 183}
180#elif _PAGE_HWEXEC == 0 184
181/* Embedded type MMU without HW exec support (8xx only so far), we flush 185static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
182 * the cache for any present PTE 186 int dirty)
183 */
184static inline int pte_need_exec_flush(pte_t pte, int set_pte)
185{ 187{
186 return set_pte && pte_looks_normal(pte); 188 return pte;
187} 189}
188#else 190
189/* Other embedded CPUs with HW exec support per-page, we flush on exec 191#else /* defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 */
190 * fault if HWEXEC is not set 192
193/* Embedded type MMU with HW exec support. This is a bit more complicated
194 * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so
195 * instead we "filter out" the exec permission for non clean pages.
191 */ 196 */
192static inline int pte_need_exec_flush(pte_t pte, int set_pte) 197static pte_t set_pte_filter(pte_t pte)
193{ 198{
194 return pte_looks_normal(pte) && is_exec_fault() && 199 struct page *pg;
195 !(pte_val(pte) & _PAGE_HWEXEC); 200
201 /* No exec permission in the first place, move on */
202 if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte))
203 return pte;
204
205 /* If you set _PAGE_EXEC on weird pages you're on your own */
206 pg = maybe_pte_to_page(pte);
207 if (unlikely(!pg))
208 return pte;
209
210 /* If the page clean, we move on */
211 if (test_bit(PG_arch_1, &pg->flags))
212 return pte;
213
214 /* If it's an exec fault, we flush the cache and make it clean */
215 if (is_exec_fault()) {
216 flush_dcache_icache_page(pg);
217 set_bit(PG_arch_1, &pg->flags);
218 return pte;
219 }
220
221 /* Else, we filter out _PAGE_EXEC */
222 return __pte(pte_val(pte) & ~_PAGE_EXEC);
196} 223}
197#endif 224
225static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
226 int dirty)
227{
228 struct page *pg;
229
230 /* So here, we only care about exec faults, as we use them
231 * to recover lost _PAGE_EXEC and perform I$/D$ coherency
232 * if necessary. Also if _PAGE_EXEC is already set, same deal,
233 * we just bail out
234 */
235 if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault())
236 return pte;
237
238#ifdef CONFIG_DEBUG_VM
239 /* So this is an exec fault, _PAGE_EXEC is not set. If it was
240 * an error we would have bailed out earlier in do_page_fault()
241 * but let's make sure of it
242 */
243 if (WARN_ON(!(vma->vm_flags & VM_EXEC)))
244 return pte;
245#endif /* CONFIG_DEBUG_VM */
246
247 /* If you set _PAGE_EXEC on weird pages you're on your own */
248 pg = maybe_pte_to_page(pte);
249 if (unlikely(!pg))
250 goto bail;
251
252 /* If the page is already clean, we move on */
253 if (test_bit(PG_arch_1, &pg->flags))
254 goto bail;
255
256 /* Clean the page and set PG_arch_1 */
257 flush_dcache_icache_page(pg);
258 set_bit(PG_arch_1, &pg->flags);
259
260 bail:
261 return __pte(pte_val(pte) | _PAGE_EXEC);
262}
263
264#endif /* !(defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0) */
198 265
199/* 266/*
200 * set_pte stores a linux PTE into the linux page table. 267 * set_pte stores a linux PTE into the linux page table.
201 */ 268 */
202void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) 269void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
270 pte_t pte)
203{ 271{
204#ifdef CONFIG_DEBUG_VM 272#ifdef CONFIG_DEBUG_VM
205 WARN_ON(pte_present(*ptep)); 273 WARN_ON(pte_present(*ptep));
@@ -208,9 +276,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte
208 * this context might not have been activated yet when this 276 * this context might not have been activated yet when this
209 * is called. 277 * is called.
210 */ 278 */
211 pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); 279 pte = set_pte_filter(pte);
212 if (pte_need_exec_flush(pte, 1))
213 pte = do_dcache_icache_coherency(pte);
214 280
215 /* Perform the setting of the PTE */ 281 /* Perform the setting of the PTE */
216 __set_pte_at(mm, addr, ptep, pte, 0); 282 __set_pte_at(mm, addr, ptep, pte, 0);
@@ -227,8 +293,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
227 pte_t *ptep, pte_t entry, int dirty) 293 pte_t *ptep, pte_t entry, int dirty)
228{ 294{
229 int changed; 295 int changed;
230 if (!dirty && pte_need_exec_flush(entry, 0)) 296 entry = set_access_flags_filter(entry, vma, dirty);
231 entry = do_dcache_icache_coherency(entry);
232 changed = !pte_same(*(ptep), entry); 297 changed = !pte_same(*(ptep), entry);
233 if (changed) { 298 if (changed) {
234 if (!(vma->vm_flags & VM_HUGETLB)) 299 if (!(vma->vm_flags & VM_HUGETLB))
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 5422169626ba..cb96cb2e17cc 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -142,7 +142,7 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
142 flags |= _PAGE_DIRTY | _PAGE_HWWRITE; 142 flags |= _PAGE_DIRTY | _PAGE_HWWRITE;
143 143
144 /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */ 144 /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
145 flags &= ~(_PAGE_USER | _PAGE_EXEC | _PAGE_HWEXEC); 145 flags &= ~(_PAGE_USER | _PAGE_EXEC);
146 146
147 return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); 147 return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
148} 148}
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
index 10d524ded7b2..cd92f62f9cf5 100644
--- a/arch/powerpc/mm/tlb_low_64e.S
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -133,7 +133,7 @@
133 133
134 /* We do the user/kernel test for the PID here along with the RW test 134 /* We do the user/kernel test for the PID here along with the RW test
135 */ 135 */
136 li r11,_PAGE_PRESENT|_PAGE_HWEXEC /* Base perm */ 136 li r11,_PAGE_PRESENT|_PAGE_EXEC /* Base perm */
137 oris r11,r11,_PAGE_ACCESSED@h 137 oris r11,r11,_PAGE_ACCESSED@h
138 138
139 cmpldi cr0,r15,0 /* Check for user region */ 139 cmpldi cr0,r15,0 /* Check for user region */
@@ -256,7 +256,7 @@ normal_tlb_miss_done:
256 256
257normal_tlb_miss_access_fault: 257normal_tlb_miss_access_fault:
258 /* We need to check if it was an instruction miss */ 258 /* We need to check if it was an instruction miss */
259 andi. r10,r11,_PAGE_HWEXEC 259 andi. r10,r11,_PAGE_EXEC
260 bne 1f 260 bne 1f
261 ld r14,EX_TLB_DEAR(r12) 261 ld r14,EX_TLB_DEAR(r12)
262 ld r15,EX_TLB_ESR(r12) 262 ld r15,EX_TLB_ESR(r12)