diff options
Diffstat (limited to 'include/asm-generic/pgtable.h')
-rw-r--r-- | include/asm-generic/pgtable.h | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h new file mode 100644 index 000000000000..a3b28710d56c --- /dev/null +++ b/include/asm-generic/pgtable.h | |||
@@ -0,0 +1,213 @@ | |||
1 | #ifndef _ASM_GENERIC_PGTABLE_H | ||
2 | #define _ASM_GENERIC_PGTABLE_H | ||
3 | |||
4 | #ifndef __HAVE_ARCH_PTEP_ESTABLISH | ||
5 | /* | ||
6 | * Establish a new mapping: | ||
7 | * - flush the old one | ||
8 | * - update the page tables | ||
9 | * - inform the TLB about the new one | ||
10 | * | ||
11 | * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock. | ||
12 | * | ||
13 | * Note: the old pte is known to not be writable, so we don't need to | ||
14 | * worry about dirty bits etc getting lost. | ||
15 | */ | ||
16 | #ifndef __HAVE_ARCH_SET_PTE_ATOMIC | ||
17 | #define ptep_establish(__vma, __address, __ptep, __entry) \ | ||
18 | do { \ | ||
19 | set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \ | ||
20 | flush_tlb_page(__vma, __address); \ | ||
21 | } while (0) | ||
22 | #else /* __HAVE_ARCH_SET_PTE_ATOMIC */ | ||
23 | #define ptep_establish(__vma, __address, __ptep, __entry) \ | ||
24 | do { \ | ||
25 | set_pte_atomic(__ptep, __entry); \ | ||
26 | flush_tlb_page(__vma, __address); \ | ||
27 | } while (0) | ||
28 | #endif /* __HAVE_ARCH_SET_PTE_ATOMIC */ | ||
29 | #endif | ||
30 | |||
31 | #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | ||
32 | /* | ||
33 | * Largely same as above, but only sets the access flags (dirty, | ||
34 | * accessed, and writable). Furthermore, we know it always gets set | ||
35 | * to a "more permissive" setting, which allows most architectures | ||
36 | * to optimize this. | ||
37 | */ | ||
38 | #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ | ||
39 | do { \ | ||
40 | set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \ | ||
41 | flush_tlb_page(__vma, __address); \ | ||
42 | } while (0) | ||
43 | #endif | ||
44 | |||
45 | #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | ||
46 | #define ptep_test_and_clear_young(__vma, __address, __ptep) \ | ||
47 | ({ \ | ||
48 | pte_t __pte = *(__ptep); \ | ||
49 | int r = 1; \ | ||
50 | if (!pte_young(__pte)) \ | ||
51 | r = 0; \ | ||
52 | else \ | ||
53 | set_pte_at((__vma)->vm_mm, (__address), \ | ||
54 | (__ptep), pte_mkold(__pte)); \ | ||
55 | r; \ | ||
56 | }) | ||
57 | #endif | ||
58 | |||
59 | #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH | ||
60 | #define ptep_clear_flush_young(__vma, __address, __ptep) \ | ||
61 | ({ \ | ||
62 | int __young; \ | ||
63 | __young = ptep_test_and_clear_young(__vma, __address, __ptep); \ | ||
64 | if (__young) \ | ||
65 | flush_tlb_page(__vma, __address); \ | ||
66 | __young; \ | ||
67 | }) | ||
68 | #endif | ||
69 | |||
70 | #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY | ||
71 | #define ptep_test_and_clear_dirty(__vma, __address, __ptep) \ | ||
72 | ({ \ | ||
73 | pte_t __pte = *__ptep; \ | ||
74 | int r = 1; \ | ||
75 | if (!pte_dirty(__pte)) \ | ||
76 | r = 0; \ | ||
77 | else \ | ||
78 | set_pte_at((__vma)->vm_mm, (__address), (__ptep), \ | ||
79 | pte_mkclean(__pte)); \ | ||
80 | r; \ | ||
81 | }) | ||
82 | #endif | ||
83 | |||
84 | #ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH | ||
85 | #define ptep_clear_flush_dirty(__vma, __address, __ptep) \ | ||
86 | ({ \ | ||
87 | int __dirty; \ | ||
88 | __dirty = ptep_test_and_clear_dirty(__vma, __address, __ptep); \ | ||
89 | if (__dirty) \ | ||
90 | flush_tlb_page(__vma, __address); \ | ||
91 | __dirty; \ | ||
92 | }) | ||
93 | #endif | ||
94 | |||
95 | #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR | ||
96 | #define ptep_get_and_clear(__mm, __address, __ptep) \ | ||
97 | ({ \ | ||
98 | pte_t __pte = *(__ptep); \ | ||
99 | pte_clear((__mm), (__address), (__ptep)); \ | ||
100 | __pte; \ | ||
101 | }) | ||
102 | #endif | ||
103 | |||
104 | #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH | ||
105 | #define ptep_clear_flush(__vma, __address, __ptep) \ | ||
106 | ({ \ | ||
107 | pte_t __pte; \ | ||
108 | __pte = ptep_get_and_clear((__vma)->vm_mm, __address, __ptep); \ | ||
109 | flush_tlb_page(__vma, __address); \ | ||
110 | __pte; \ | ||
111 | }) | ||
112 | #endif | ||
113 | |||
114 | #ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT | ||
115 | static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) | ||
116 | { | ||
117 | pte_t old_pte = *ptep; | ||
118 | set_pte_at(mm, address, ptep, pte_wrprotect(old_pte)); | ||
119 | } | ||
120 | #endif | ||
121 | |||
122 | #ifndef __HAVE_ARCH_PTE_SAME | ||
123 | #define pte_same(A,B) (pte_val(A) == pte_val(B)) | ||
124 | #endif | ||
125 | |||
126 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY | ||
127 | #define page_test_and_clear_dirty(page) (0) | ||
128 | #endif | ||
129 | |||
130 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
131 | #define page_test_and_clear_young(page) (0) | ||
132 | #endif | ||
133 | |||
134 | #ifndef __HAVE_ARCH_PGD_OFFSET_GATE | ||
135 | #define pgd_offset_gate(mm, addr) pgd_offset(mm, addr) | ||
136 | #endif | ||
137 | |||
138 | #ifndef __HAVE_ARCH_LAZY_MMU_PROT_UPDATE | ||
139 | #define lazy_mmu_prot_update(pte) do { } while (0) | ||
140 | #endif | ||
141 | |||
142 | /* | ||
143 | * When walking page tables, get the address of the next boundary, or | ||
144 | * the end address of the range if that comes earlier. Although end might | ||
145 | * wrap to 0 only in clear_page_range, __boundary may wrap to 0 throughout. | ||
146 | */ | ||
147 | |||
148 | #ifndef pgd_addr_end | ||
149 | #define pgd_addr_end(addr, end) \ | ||
150 | ({ unsigned long __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \ | ||
151 | (__boundary - 1 < (end) - 1)? __boundary: (end); \ | ||
152 | }) | ||
153 | #endif | ||
154 | |||
155 | #ifndef pud_addr_end | ||
156 | #define pud_addr_end(addr, end) \ | ||
157 | ({ unsigned long __boundary = ((addr) + PUD_SIZE) & PUD_MASK; \ | ||
158 | (__boundary - 1 < (end) - 1)? __boundary: (end); \ | ||
159 | }) | ||
160 | #endif | ||
161 | |||
162 | #ifndef pmd_addr_end | ||
163 | #define pmd_addr_end(addr, end) \ | ||
164 | ({ unsigned long __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \ | ||
165 | (__boundary - 1 < (end) - 1)? __boundary: (end); \ | ||
166 | }) | ||
167 | #endif | ||
168 | |||
169 | #ifndef __ASSEMBLY__ | ||
170 | /* | ||
171 | * When walking page tables, we usually want to skip any p?d_none entries; | ||
172 | * and any p?d_bad entries - reporting the error before resetting to none. | ||
173 | * Do the tests inline, but report and clear the bad entry in mm/memory.c. | ||
174 | */ | ||
175 | void pgd_clear_bad(pgd_t *); | ||
176 | void pud_clear_bad(pud_t *); | ||
177 | void pmd_clear_bad(pmd_t *); | ||
178 | |||
179 | static inline int pgd_none_or_clear_bad(pgd_t *pgd) | ||
180 | { | ||
181 | if (pgd_none(*pgd)) | ||
182 | return 1; | ||
183 | if (unlikely(pgd_bad(*pgd))) { | ||
184 | pgd_clear_bad(pgd); | ||
185 | return 1; | ||
186 | } | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static inline int pud_none_or_clear_bad(pud_t *pud) | ||
191 | { | ||
192 | if (pud_none(*pud)) | ||
193 | return 1; | ||
194 | if (unlikely(pud_bad(*pud))) { | ||
195 | pud_clear_bad(pud); | ||
196 | return 1; | ||
197 | } | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static inline int pmd_none_or_clear_bad(pmd_t *pmd) | ||
202 | { | ||
203 | if (pmd_none(*pmd)) | ||
204 | return 1; | ||
205 | if (unlikely(pmd_bad(*pmd))) { | ||
206 | pmd_clear_bad(pmd); | ||
207 | return 1; | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | #endif /* !__ASSEMBLY__ */ | ||
212 | |||
213 | #endif /* _ASM_GENERIC_PGTABLE_H */ | ||