aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig8
-rw-r--r--arch/powerpc/kernel/head_64.S1
-rw-r--r--arch/powerpc/mm/Makefile1
-rw-r--r--arch/powerpc/mm/hash_low_64.S16
-rw-r--r--arch/powerpc/mm/hash_utils_64.c83
-rw-r--r--arch/powerpc/mm/subpage-prot.c213
-rw-r--r--include/asm-powerpc/mmu-hash64.h3
-rw-r--r--include/asm-powerpc/pgalloc-64.h5
-rw-r--r--include/asm-powerpc/pgtable-64k.h39
-rw-r--r--include/asm-powerpc/systbl.h1
-rw-r--r--include/asm-powerpc/unistd.h3
-rw-r--r--kernel/sys_ni.c1
12 files changed, 353 insertions, 21 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 66a3d8cee5cf..53d0955abf11 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -342,6 +342,14 @@ config PPC_64K_PAGES
342 while on hardware with such support, it will be used to map 342 while on hardware with such support, it will be used to map
343 normal application pages. 343 normal application pages.
344 344
345config PPC_SUBPAGE_PROT
346 bool "Support setting protections for 4k subpages"
347 depends on PPC_64K_PAGES
348 help
349 This option adds support for a system call to allow user programs
350 to set access permissions (read/write, readonly, or no access)
351 on the 4k subpages of each 64k page.
352
345config SCHED_SMT 353config SCHED_SMT
346 bool "SMT (Hyperthreading) scheduler support" 354 bool "SMT (Hyperthreading) scheduler support"
347 depends on PPC64 && SMP 355 depends on PPC64 && SMP
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index c34986835a4e..11b4f6d9ffce 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -903,6 +903,7 @@ handle_page_fault:
903 * the PTE insertion 903 * the PTE insertion
904 */ 904 */
90512: bl .save_nvgprs 90512: bl .save_nvgprs
906 mr r5,r3
906 addi r3,r1,STACK_FRAME_OVERHEAD 907 addi r3,r1,STACK_FRAME_OVERHEAD
907 ld r4,_DAR(r1) 908 ld r4,_DAR(r1)
908 bl .low_hash_fault 909 bl .low_hash_fault
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 20629ae95c50..41649a5d3602 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o
22obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o 22obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
23obj-$(CONFIG_PPC_MM_SLICES) += slice.o 23obj-$(CONFIG_PPC_MM_SLICES) += slice.o
24obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 24obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
25obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index e935edd6b72b..21d248486479 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -331,7 +331,8 @@ htab_pte_insert_failure:
331 *****************************************************************************/ 331 *****************************************************************************/
332 332
333/* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, 333/* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
334 * pte_t *ptep, unsigned long trap, int local, int ssize) 334 * pte_t *ptep, unsigned long trap, int local, int ssize,
335 * int subpg_prot)
335 */ 336 */
336 337
337/* 338/*
@@ -429,12 +430,19 @@ END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
429 xor r28,r28,r0 /* hash */ 430 xor r28,r28,r0 /* hash */
430 431
431 /* Convert linux PTE bits into HW equivalents */ 432 /* Convert linux PTE bits into HW equivalents */
4324: andi. r3,r30,0x1fe /* Get basic set of flags */ 4334:
433 xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */ 434#ifdef CONFIG_PPC_SUBPAGE_PROT
435 andc r10,r30,r10
436 andi. r3,r10,0x1fe /* Get basic set of flags */
437 rlwinm r0,r10,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
438#else
439 andi. r3,r30,0x1fe /* Get basic set of flags */
434 rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */ 440 rlwinm r0,r30,32-9+1,30,30 /* _PAGE_RW -> _PAGE_USER (r0) */
441#endif
442 xori r3,r3,HPTE_R_N /* _PAGE_EXEC -> NOEXEC */
435 rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */ 443 rlwinm r4,r30,32-7+1,30,30 /* _PAGE_DIRTY -> _PAGE_USER (r4) */
436 and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ 444 and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
437 andc r0,r30,r0 /* r0 = pte & ~r0 */ 445 andc r0,r3,r0 /* r0 = pte & ~r0 */
438 rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ 446 rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */
439 ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ 447 ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */
440 448
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 9326a6962b42..7b4cacb0d4ba 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -637,7 +637,7 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
637 * For now this makes the whole process use 4k pages. 637 * For now this makes the whole process use 4k pages.
638 */ 638 */
639#ifdef CONFIG_PPC_64K_PAGES 639#ifdef CONFIG_PPC_64K_PAGES
640static void demote_segment_4k(struct mm_struct *mm, unsigned long addr) 640void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
641{ 641{
642 if (mm->context.user_psize == MMU_PAGE_4K) 642 if (mm->context.user_psize == MMU_PAGE_4K)
643 return; 643 return;
@@ -645,13 +645,62 @@ static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
645#ifdef CONFIG_SPU_BASE 645#ifdef CONFIG_SPU_BASE
646 spu_flush_all_slbs(mm); 646 spu_flush_all_slbs(mm);
647#endif 647#endif
648 if (get_paca()->context.user_psize != MMU_PAGE_4K) {
649 get_paca()->context = mm->context;
650 slb_flush_and_rebolt();
651 }
648} 652}
649#endif /* CONFIG_PPC_64K_PAGES */ 653#endif /* CONFIG_PPC_64K_PAGES */
650 654
655#ifdef CONFIG_PPC_SUBPAGE_PROT
656/*
657 * This looks up a 2-bit protection code for a 4k subpage of a 64k page.
658 * Userspace sets the subpage permissions using the subpage_prot system call.
659 *
660 * Result is 0: full permissions, _PAGE_RW: read-only,
661 * _PAGE_USER or _PAGE_USER|_PAGE_RW: no access.
662 */
663static int subpage_protection(pgd_t *pgdir, unsigned long ea)
664{
665 struct subpage_prot_table *spt = pgd_subpage_prot(pgdir);
666 u32 spp = 0;
667 u32 **sbpm, *sbpp;
668
669 if (ea >= spt->maxaddr)
670 return 0;
671 if (ea < 0x100000000) {
672 /* addresses below 4GB use spt->low_prot */
673 sbpm = spt->low_prot;
674 } else {
675 sbpm = spt->protptrs[ea >> SBP_L3_SHIFT];
676 if (!sbpm)
677 return 0;
678 }
679 sbpp = sbpm[(ea >> SBP_L2_SHIFT) & (SBP_L2_COUNT - 1)];
680 if (!sbpp)
681 return 0;
682 spp = sbpp[(ea >> PAGE_SHIFT) & (SBP_L1_COUNT - 1)];
683
684 /* extract 2-bit bitfield for this 4k subpage */
685 spp >>= 30 - 2 * ((ea >> 12) & 0xf);
686
687 /* turn 0,1,2,3 into combination of _PAGE_USER and _PAGE_RW */
688 spp = ((spp & 2) ? _PAGE_USER : 0) | ((spp & 1) ? _PAGE_RW : 0);
689 return spp;
690}
691
692#else /* CONFIG_PPC_SUBPAGE_PROT */
693static inline int subpage_protection(pgd_t *pgdir, unsigned long ea)
694{
695 return 0;
696}
697#endif
698
651/* Result code is: 699/* Result code is:
652 * 0 - handled 700 * 0 - handled
653 * 1 - normal page fault 701 * 1 - normal page fault
654 * -1 - critical hash insertion error 702 * -1 - critical hash insertion error
703 * -2 - access not permitted by subpage protection mechanism
655 */ 704 */
656int hash_page(unsigned long ea, unsigned long access, unsigned long trap) 705int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
657{ 706{
@@ -802,7 +851,14 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
802 rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); 851 rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize);
803 else 852 else
804#endif /* CONFIG_PPC_HAS_HASH_64K */ 853#endif /* CONFIG_PPC_HAS_HASH_64K */
805 rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize); 854 {
855 int spp = subpage_protection(pgdir, ea);
856 if (access & spp)
857 rc = -2;
858 else
859 rc = __hash_page_4K(ea, access, vsid, ptep, trap,
860 local, ssize, spp);
861 }
806 862
807#ifndef CONFIG_PPC_64K_PAGES 863#ifndef CONFIG_PPC_64K_PAGES
808 DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); 864 DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
@@ -874,7 +930,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
874 __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); 930 __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize);
875 else 931 else
876#endif /* CONFIG_PPC_HAS_HASH_64K */ 932#endif /* CONFIG_PPC_HAS_HASH_64K */
877 __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize); 933 __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
934 subpage_protection(pgdir, ea));
878 935
879 local_irq_restore(flags); 936 local_irq_restore(flags);
880} 937}
@@ -919,19 +976,17 @@ void flush_hash_range(unsigned long number, int local)
919 * low_hash_fault is called when we the low level hash code failed 976 * low_hash_fault is called when we the low level hash code failed
920 * to instert a PTE due to an hypervisor error 977 * to instert a PTE due to an hypervisor error
921 */ 978 */
922void low_hash_fault(struct pt_regs *regs, unsigned long address) 979void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc)
923{ 980{
924 if (user_mode(regs)) { 981 if (user_mode(regs)) {
925 siginfo_t info; 982#ifdef CONFIG_PPC_SUBPAGE_PROT
926 983 if (rc == -2)
927 info.si_signo = SIGBUS; 984 _exception(SIGSEGV, regs, SEGV_ACCERR, address);
928 info.si_errno = 0; 985 else
929 info.si_code = BUS_ADRERR; 986#endif
930 info.si_addr = (void __user *)address; 987 _exception(SIGBUS, regs, BUS_ADRERR, address);
931 force_sig_info(SIGBUS, &info, current); 988 } else
932 return; 989 bad_page_fault(regs, address, SIGBUS);
933 }
934 bad_page_fault(regs, address, SIGBUS);
935} 990}
936 991
937#ifdef CONFIG_DEBUG_PAGEALLOC 992#ifdef CONFIG_DEBUG_PAGEALLOC
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
new file mode 100644
index 000000000000..4cafc0c33d0a
--- /dev/null
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright 2007-2008 Paul Mackerras, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/errno.h>
11#include <linux/kernel.h>
12#include <linux/gfp.h>
13#include <linux/slab.h>
14#include <linux/types.h>
15#include <linux/mm.h>
16#include <linux/hugetlb.h>
17
18#include <asm/pgtable.h>
19#include <asm/uaccess.h>
20#include <asm/tlbflush.h>
21
22/*
23 * Free all pages allocated for subpage protection maps and pointers.
24 * Also makes sure that the subpage_prot_table structure is
25 * reinitialized for the next user.
26 */
27void subpage_prot_free(pgd_t *pgd)
28{
29 struct subpage_prot_table *spt = pgd_subpage_prot(pgd);
30 unsigned long i, j, addr;
31 u32 **p;
32
33 for (i = 0; i < 4; ++i) {
34 if (spt->low_prot[i]) {
35 free_page((unsigned long)spt->low_prot[i]);
36 spt->low_prot[i] = NULL;
37 }
38 }
39 addr = 0;
40 for (i = 0; i < 2; ++i) {
41 p = spt->protptrs[i];
42 if (!p)
43 continue;
44 spt->protptrs[i] = NULL;
45 for (j = 0; j < SBP_L2_COUNT && addr < spt->maxaddr;
46 ++j, addr += PAGE_SIZE)
47 if (p[j])
48 free_page((unsigned long)p[j]);
49 free_page((unsigned long)p);
50 }
51 spt->maxaddr = 0;
52}
53
54static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
55 int npages)
56{
57 pgd_t *pgd;
58 pud_t *pud;
59 pmd_t *pmd;
60 pte_t *pte;
61 spinlock_t *ptl;
62
63 pgd = pgd_offset(mm, addr);
64 if (pgd_none(*pgd))
65 return;
66 pud = pud_offset(pgd, addr);
67 if (pud_none(*pud))
68 return;
69 pmd = pmd_offset(pud, addr);
70 if (pmd_none(*pmd))
71 return;
72 pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
73 arch_enter_lazy_mmu_mode();
74 for (; npages > 0; --npages) {
75 pte_update(mm, addr, pte, 0, 0);
76 addr += PAGE_SIZE;
77 ++pte;
78 }
79 arch_leave_lazy_mmu_mode();
80 pte_unmap_unlock(pte - 1, ptl);
81}
82
83/*
84 * Clear the subpage protection map for an address range, allowing
85 * all accesses that are allowed by the pte permissions.
86 */
87static void subpage_prot_clear(unsigned long addr, unsigned long len)
88{
89 struct mm_struct *mm = current->mm;
90 struct subpage_prot_table *spt = pgd_subpage_prot(mm->pgd);
91 u32 **spm, *spp;
92 int i, nw;
93 unsigned long next, limit;
94
95 down_write(&mm->mmap_sem);
96 limit = addr + len;
97 if (limit > spt->maxaddr)
98 limit = spt->maxaddr;
99 for (; addr < limit; addr = next) {
100 next = pmd_addr_end(addr, limit);
101 if (addr < 0x100000000) {
102 spm = spt->low_prot;
103 } else {
104 spm = spt->protptrs[addr >> SBP_L3_SHIFT];
105 if (!spm)
106 continue;
107 }
108 spp = spm[(addr >> SBP_L2_SHIFT) & (SBP_L2_COUNT - 1)];
109 if (!spp)
110 continue;
111 spp += (addr >> PAGE_SHIFT) & (SBP_L1_COUNT - 1);
112
113 i = (addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
114 nw = PTRS_PER_PTE - i;
115 if (addr + (nw << PAGE_SHIFT) > next)
116 nw = (next - addr) >> PAGE_SHIFT;
117
118 memset(spp, 0, nw * sizeof(u32));
119
120 /* now flush any existing HPTEs for the range */
121 hpte_flush_range(mm, addr, nw);
122 }
123 up_write(&mm->mmap_sem);
124}
125
126/*
127 * Copy in a subpage protection map for an address range.
128 * The map has 2 bits per 4k subpage, so 32 bits per 64k page.
129 * Each 2-bit field is 0 to allow any access, 1 to prevent writes,
130 * 2 or 3 to prevent all accesses.
131 * Note that the normal page protections also apply; the subpage
132 * protection mechanism is an additional constraint, so putting 0
133 * in a 2-bit field won't allow writes to a page that is otherwise
134 * write-protected.
135 */
136long sys_subpage_prot(unsigned long addr, unsigned long len, u32 __user *map)
137{
138 struct mm_struct *mm = current->mm;
139 struct subpage_prot_table *spt = pgd_subpage_prot(mm->pgd);
140 u32 **spm, *spp;
141 int i, nw;
142 unsigned long next, limit;
143 int err;
144
145 /* Check parameters */
146 if ((addr & ~PAGE_MASK) || (len & ~PAGE_MASK) ||
147 addr >= TASK_SIZE || len >= TASK_SIZE || addr + len > TASK_SIZE)
148 return -EINVAL;
149
150 if (is_hugepage_only_range(mm, addr, len))
151 return -EINVAL;
152
153 if (!map) {
154 /* Clear out the protection map for the address range */
155 subpage_prot_clear(addr, len);
156 return 0;
157 }
158
159 if (!access_ok(VERIFY_READ, map, (len >> PAGE_SHIFT) * sizeof(u32)))
160 return -EFAULT;
161
162 down_write(&mm->mmap_sem);
163 for (limit = addr + len; addr < limit; addr = next) {
164 next = pmd_addr_end(addr, limit);
165 err = -ENOMEM;
166 if (addr < 0x100000000) {
167 spm = spt->low_prot;
168 } else {
169 spm = spt->protptrs[addr >> SBP_L3_SHIFT];
170 if (!spm) {
171 spm = (u32 **)get_zeroed_page(GFP_KERNEL);
172 if (!spm)
173 goto out;
174 spt->protptrs[addr >> SBP_L3_SHIFT] = spm;
175 }
176 }
177 spm += (addr >> SBP_L2_SHIFT) & (SBP_L2_COUNT - 1);
178 spp = *spm;
179 if (!spp) {
180 spp = (u32 *)get_zeroed_page(GFP_KERNEL);
181 if (!spp)
182 goto out;
183 *spm = spp;
184 }
185 spp += (addr >> PAGE_SHIFT) & (SBP_L1_COUNT - 1);
186
187 local_irq_disable();
188 demote_segment_4k(mm, addr);
189 local_irq_enable();
190
191 i = (addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
192 nw = PTRS_PER_PTE - i;
193 if (addr + (nw << PAGE_SHIFT) > next)
194 nw = (next - addr) >> PAGE_SHIFT;
195
196 up_write(&mm->mmap_sem);
197 err = -EFAULT;
198 if (__copy_from_user(spp, map, nw * sizeof(u32)))
199 goto out2;
200 map += nw;
201 down_write(&mm->mmap_sem);
202
203 /* now flush any existing HPTEs for the range */
204 hpte_flush_range(mm, addr, nw);
205 }
206 if (limit > spt->maxaddr)
207 spt->maxaddr = limit;
208 err = 0;
209 out:
210 up_write(&mm->mmap_sem);
211 out2:
212 return err;
213}
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
index 2a1b4040e20d..2864fa3989ea 100644
--- a/include/asm-powerpc/mmu-hash64.h
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -265,7 +265,7 @@ static inline unsigned long hpt_hash(unsigned long va, unsigned int shift,
265 265
266extern int __hash_page_4K(unsigned long ea, unsigned long access, 266extern int __hash_page_4K(unsigned long ea, unsigned long access,
267 unsigned long vsid, pte_t *ptep, unsigned long trap, 267 unsigned long vsid, pte_t *ptep, unsigned long trap,
268 unsigned int local, int ssize); 268 unsigned int local, int ssize, int subpage_prot);
269extern int __hash_page_64K(unsigned long ea, unsigned long access, 269extern int __hash_page_64K(unsigned long ea, unsigned long access,
270 unsigned long vsid, pte_t *ptep, unsigned long trap, 270 unsigned long vsid, pte_t *ptep, unsigned long trap,
271 unsigned int local, int ssize); 271 unsigned int local, int ssize);
@@ -279,6 +279,7 @@ extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
279 unsigned long pstart, unsigned long mode, 279 unsigned long pstart, unsigned long mode,
280 int psize, int ssize); 280 int psize, int ssize);
281extern void set_huge_psize(int psize); 281extern void set_huge_psize(int psize);
282extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr);
282 283
283extern void htab_initialize(void); 284extern void htab_initialize(void);
284extern void htab_initialize_secondary(void); 285extern void htab_initialize_secondary(void);
diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h
index 94d0294341d6..43214c8085b7 100644
--- a/include/asm-powerpc/pgalloc-64.h
+++ b/include/asm-powerpc/pgalloc-64.h
@@ -12,6 +12,10 @@
12#include <linux/cpumask.h> 12#include <linux/cpumask.h>
13#include <linux/percpu.h> 13#include <linux/percpu.h>
14 14
15#ifndef CONFIG_PPC_SUBPAGE_PROT
16static inline void subpage_prot_free(pgd_t *pgd) {}
17#endif
18
15extern struct kmem_cache *pgtable_cache[]; 19extern struct kmem_cache *pgtable_cache[];
16 20
17#define PGD_CACHE_NUM 0 21#define PGD_CACHE_NUM 0
@@ -27,6 +31,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
27 31
28static inline void pgd_free(pgd_t *pgd) 32static inline void pgd_free(pgd_t *pgd)
29{ 33{
34 subpage_prot_free(pgd);
30 kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd); 35 kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
31} 36}
32 37
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index bd54b772fbc6..1cbd6b377eea 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -13,12 +13,49 @@
13#define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE) 13#define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE)
14#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE) 14#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
15#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE) 15#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
16#endif /* __ASSEMBLY__ */
17 16
18#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) 17#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE)
19#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) 18#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE)
20#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) 19#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE)
21 20
21#ifdef CONFIG_PPC_SUBPAGE_PROT
22/*
23 * For the sub-page protection option, we extend the PGD with one of
24 * these. Basically we have a 3-level tree, with the top level being
25 * the protptrs array. To optimize speed and memory consumption when
26 * only addresses < 4GB are being protected, pointers to the first
27 * four pages of sub-page protection words are stored in the low_prot
28 * array.
29 * Each page of sub-page protection words protects 1GB (4 bytes
30 * protects 64k). For the 3-level tree, each page of pointers then
31 * protects 8TB.
32 */
33struct subpage_prot_table {
34 unsigned long maxaddr; /* only addresses < this are protected */
35 unsigned int **protptrs[2];
36 unsigned int *low_prot[4];
37};
38
39#undef PGD_TABLE_SIZE
40#define PGD_TABLE_SIZE ((sizeof(pgd_t) << PGD_INDEX_SIZE) + \
41 sizeof(struct subpage_prot_table))
42
43#define SBP_L1_BITS (PAGE_SHIFT - 2)
44#define SBP_L2_BITS (PAGE_SHIFT - 3)
45#define SBP_L1_COUNT (1 << SBP_L1_BITS)
46#define SBP_L2_COUNT (1 << SBP_L2_BITS)
47#define SBP_L2_SHIFT (PAGE_SHIFT + SBP_L1_BITS)
48#define SBP_L3_SHIFT (SBP_L2_SHIFT + SBP_L2_BITS)
49
50extern void subpage_prot_free(pgd_t *pgd);
51
52static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
53{
54 return (struct subpage_prot_table *)(pgd + PTRS_PER_PGD);
55}
56#endif /* CONFIG_PPC_SUBPAGE_PROT */
57#endif /* __ASSEMBLY__ */
58
22/* With 4k base page size, hugepage PTEs go at the PMD level */ 59/* With 4k base page size, hugepage PTEs go at the PMD level */
23#define MIN_HUGEPTE_SHIFT PAGE_SHIFT 60#define MIN_HUGEPTE_SHIFT PAGE_SHIFT
24 61
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 11d5383b2f09..0c8b0d679139 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -313,3 +313,4 @@ COMPAT_SYS_SPU(timerfd)
313SYSCALL_SPU(eventfd) 313SYSCALL_SPU(eventfd)
314COMPAT_SYS_SPU(sync_file_range2) 314COMPAT_SYS_SPU(sync_file_range2)
315COMPAT_SYS(fallocate) 315COMPAT_SYS(fallocate)
316SYSCALL(subpage_prot)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 97d82b6a9406..fedc4b8e49e2 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -332,10 +332,11 @@
332#define __NR_eventfd 307 332#define __NR_eventfd 307
333#define __NR_sync_file_range2 308 333#define __NR_sync_file_range2 308
334#define __NR_fallocate 309 334#define __NR_fallocate 309
335#define __NR_subpage_prot 310
335 336
336#ifdef __KERNEL__ 337#ifdef __KERNEL__
337 338
338#define __NR_syscalls 310 339#define __NR_syscalls 311
339 340
340#define __NR__exit __NR_exit 341#define __NR__exit __NR_exit
341#define NR_syscalls __NR_syscalls 342#define NR_syscalls __NR_syscalls
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 56cb009a4b35..beee5b3b68a2 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -131,6 +131,7 @@ cond_syscall(sys32_sysctl);
131cond_syscall(ppc_rtas); 131cond_syscall(ppc_rtas);
132cond_syscall(sys_spu_run); 132cond_syscall(sys_spu_run);
133cond_syscall(sys_spu_create); 133cond_syscall(sys_spu_create);
134cond_syscall(sys_subpage_prot);
134 135
135/* mmu depending weak syscall entries */ 136/* mmu depending weak syscall entries */
136cond_syscall(sys_mprotect); 137cond_syscall(sys_mprotect);