diff options
author | Will Deacon <will.deacon@arm.com> | 2012-12-18 09:15:15 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2013-01-10 05:48:48 -0500 |
commit | a6fadf7e67d3794aae40244f435d281a62736c93 (patch) | |
tree | 2f12828305659a7ae4ec51305f44f1d836aa474b /arch/arm64 | |
parent | 02522463c84748b3b8ad770f9424bcfa70a5b4c4 (diff) |
arm64: mm: introduce present, faulting entries for PAGE_NONE
This is mostly a port of dbf62d50067e ("ARM: mm: introduce L_PTE_VALID
for page table entries") and 26ffd0d43b18 ("ARM: mm: introduce present,
faulting entries for PAGE_NONE") from ARM, which makes use of present,
faulting page table entries for page table entries mapped as PROT_NONE.
The main difference with this implementation is that we can make use of
the two pte type bits in order to avoid allocating a software bit for
identifying PROT_NONE pages, instead reserving the 10b suffix for these
types of mappings.
This is required to prevent users from accessing such pages via syscalls
such as read/write over a pipe.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/include/asm/pgtable.h | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 7adf4142a85c..e333a243bfcc 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h | |||
@@ -24,7 +24,8 @@ | |||
24 | /* | 24 | /* |
25 | * Software defined PTE bits definition. | 25 | * Software defined PTE bits definition. |
26 | */ | 26 | */ |
27 | #define PTE_VALID (_AT(pteval_t, 1) << 0) /* pte_present() check */ | 27 | #define PTE_VALID (_AT(pteval_t, 1) << 0) |
28 | #define PTE_PROT_NONE (_AT(pteval_t, 1) << 1) /* only when !PTE_VALID */ | ||
28 | #define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ | 29 | #define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ |
29 | #define PTE_DIRTY (_AT(pteval_t, 1) << 55) | 30 | #define PTE_DIRTY (_AT(pteval_t, 1) << 55) |
30 | #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) | 31 | #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) |
@@ -60,9 +61,12 @@ extern void __pgd_error(const char *file, int line, unsigned long val); | |||
60 | 61 | ||
61 | extern pgprot_t pgprot_default; | 62 | extern pgprot_t pgprot_default; |
62 | 63 | ||
63 | #define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b)) | 64 | #define __pgprot_modify(prot,mask,bits) \ |
65 | __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) | ||
66 | |||
67 | #define _MOD_PROT(p, b) __pgprot_modify(p, 0, b) | ||
64 | 68 | ||
65 | #define PAGE_NONE _MOD_PROT(pgprot_default, PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 69 | #define PAGE_NONE __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE) |
66 | #define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) | 70 | #define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) |
67 | #define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) | 71 | #define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) |
68 | #define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 72 | #define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) |
@@ -72,7 +76,7 @@ extern pgprot_t pgprot_default; | |||
72 | #define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY) | 76 | #define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY) |
73 | #define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY) | 77 | #define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY) |
74 | 78 | ||
75 | #define __PAGE_NONE __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 79 | #define __PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE) |
76 | #define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) | 80 | #define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) |
77 | #define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) | 81 | #define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) |
78 | #define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 82 | #define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) |
@@ -125,14 +129,14 @@ extern struct page *empty_zero_page; | |||
125 | /* | 129 | /* |
126 | * The following only work if pte_present(). Undefined behaviour otherwise. | 130 | * The following only work if pte_present(). Undefined behaviour otherwise. |
127 | */ | 131 | */ |
128 | #define pte_present(pte) (pte_val(pte) & PTE_VALID) | 132 | #define pte_present(pte) (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) |
129 | #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) | 133 | #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) |
130 | #define pte_young(pte) (pte_val(pte) & PTE_AF) | 134 | #define pte_young(pte) (pte_val(pte) & PTE_AF) |
131 | #define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) | 135 | #define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) |
132 | #define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) | 136 | #define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) |
133 | #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) | 137 | #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) |
134 | 138 | ||
135 | #define pte_present_user(pte) \ | 139 | #define pte_valid_user(pte) \ |
136 | ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) | 140 | ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) |
137 | 141 | ||
138 | #define PTE_BIT_FUNC(fn,op) \ | 142 | #define PTE_BIT_FUNC(fn,op) \ |
@@ -156,7 +160,7 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); | |||
156 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | 160 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, |
157 | pte_t *ptep, pte_t pte) | 161 | pte_t *ptep, pte_t pte) |
158 | { | 162 | { |
159 | if (pte_present_user(pte)) { | 163 | if (pte_valid_user(pte)) { |
160 | if (pte_exec(pte)) | 164 | if (pte_exec(pte)) |
161 | __sync_icache_dcache(pte, addr); | 165 | __sync_icache_dcache(pte, addr); |
162 | if (!pte_dirty(pte)) | 166 | if (!pte_dirty(pte)) |
@@ -172,9 +176,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
172 | #define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE) | 176 | #define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE) |
173 | #define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE)) | 177 | #define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE)) |
174 | 178 | ||
175 | #define __pgprot_modify(prot,mask,bits) \ | ||
176 | __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) | ||
177 | |||
178 | #define __HAVE_ARCH_PTE_SPECIAL | 179 | #define __HAVE_ARCH_PTE_SPECIAL |
179 | 180 | ||
180 | /* | 181 | /* |
@@ -266,7 +267,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | |||
266 | 267 | ||
267 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | 268 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) |
268 | { | 269 | { |
269 | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY; | 270 | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | |
271 | PTE_PROT_NONE | PTE_VALID; | ||
270 | pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); | 272 | pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); |
271 | return pte; | 273 | return pte; |
272 | } | 274 | } |