diff options
Diffstat (limited to 'include/asm-i386/pgtable.h')
-rw-r--r-- | include/asm-i386/pgtable.h | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index c3b58d473a55..e16359f81a40 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h | |||
@@ -159,6 +159,7 @@ void paging_init(void); | |||
159 | 159 | ||
160 | extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; | 160 | extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; |
161 | #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) | 161 | #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) |
162 | #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) | ||
162 | #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) | 163 | #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) |
163 | #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) | 164 | #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) |
164 | #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) | 165 | #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) |
@@ -166,6 +167,7 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; | |||
166 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) | 167 | #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) |
167 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) | 168 | #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) |
168 | #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) | 169 | #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) |
170 | #define PAGE_KERNEL_RX __pgprot(__PAGE_KERNEL_RX) | ||
169 | #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) | 171 | #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) |
170 | #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) | 172 | #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) |
171 | #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) | 173 | #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) |
@@ -241,6 +243,8 @@ static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; re | |||
241 | static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; } | 243 | static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; } |
242 | static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return pte; } | 244 | static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return pte; } |
243 | 245 | ||
246 | extern void vmalloc_sync_all(void); | ||
247 | |||
244 | #ifdef CONFIG_X86_PAE | 248 | #ifdef CONFIG_X86_PAE |
245 | # include <asm/pgtable-3level.h> | 249 | # include <asm/pgtable-3level.h> |
246 | #else | 250 | #else |
@@ -263,9 +267,18 @@ static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return p | |||
263 | */ | 267 | */ |
264 | #define pte_update(mm, addr, ptep) do { } while (0) | 268 | #define pte_update(mm, addr, ptep) do { } while (0) |
265 | #define pte_update_defer(mm, addr, ptep) do { } while (0) | 269 | #define pte_update_defer(mm, addr, ptep) do { } while (0) |
266 | #define paravirt_map_pt_hook(slot, va, pfn) do { } while (0) | ||
267 | #endif | 270 | #endif |
268 | 271 | ||
272 | /* local pte updates need not use xchg for locking */ | ||
273 | static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep) | ||
274 | { | ||
275 | pte_t res = *ptep; | ||
276 | |||
277 | /* Pure native function needs no input for mm, addr */ | ||
278 | native_pte_clear(NULL, 0, ptep); | ||
279 | return res; | ||
280 | } | ||
281 | |||
269 | /* | 282 | /* |
270 | * We only update the dirty/accessed state if we set | 283 | * We only update the dirty/accessed state if we set |
271 | * the dirty bit by hand in the kernel, since the hardware | 284 | * the dirty bit by hand in the kernel, since the hardware |
@@ -283,12 +296,25 @@ do { \ | |||
283 | } \ | 296 | } \ |
284 | } while (0) | 297 | } while (0) |
285 | 298 | ||
286 | /* | ||
287 | * We don't actually have these, but we want to advertise them so that | ||
288 | * we can encompass the flush here. | ||
289 | */ | ||
290 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY | 299 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY |
300 | #define ptep_test_and_clear_dirty(vma, addr, ptep) ({ \ | ||
301 | int ret = 0; \ | ||
302 | if (pte_dirty(*ptep)) \ | ||
303 | ret = test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); \ | ||
304 | if (ret) \ | ||
305 | pte_update_defer(vma->vm_mm, addr, ptep); \ | ||
306 | ret; \ | ||
307 | }) | ||
308 | |||
291 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 309 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
310 | #define ptep_test_and_clear_young(vma, addr, ptep) ({ \ | ||
311 | int ret = 0; \ | ||
312 | if (pte_young(*ptep)) \ | ||
313 | ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); \ | ||
314 | if (ret) \ | ||
315 | pte_update_defer(vma->vm_mm, addr, ptep); \ | ||
316 | ret; \ | ||
317 | }) | ||
292 | 318 | ||
293 | /* | 319 | /* |
294 | * Rules for using ptep_establish: the pte MUST be a user pte, and | 320 | * Rules for using ptep_establish: the pte MUST be a user pte, and |
@@ -305,12 +331,9 @@ do { \ | |||
305 | #define ptep_clear_flush_dirty(vma, address, ptep) \ | 331 | #define ptep_clear_flush_dirty(vma, address, ptep) \ |
306 | ({ \ | 332 | ({ \ |
307 | int __dirty; \ | 333 | int __dirty; \ |
308 | __dirty = pte_dirty(*(ptep)); \ | 334 | __dirty = ptep_test_and_clear_dirty((vma), (address), (ptep)); \ |
309 | if (__dirty) { \ | 335 | if (__dirty) \ |
310 | clear_bit(_PAGE_BIT_DIRTY, &(ptep)->pte_low); \ | ||
311 | pte_update_defer((vma)->vm_mm, (address), (ptep)); \ | ||
312 | flush_tlb_page(vma, address); \ | 336 | flush_tlb_page(vma, address); \ |
313 | } \ | ||
314 | __dirty; \ | 337 | __dirty; \ |
315 | }) | 338 | }) |
316 | 339 | ||
@@ -318,19 +341,16 @@ do { \ | |||
318 | #define ptep_clear_flush_young(vma, address, ptep) \ | 341 | #define ptep_clear_flush_young(vma, address, ptep) \ |
319 | ({ \ | 342 | ({ \ |
320 | int __young; \ | 343 | int __young; \ |
321 | __young = pte_young(*(ptep)); \ | 344 | __young = ptep_test_and_clear_young((vma), (address), (ptep)); \ |
322 | if (__young) { \ | 345 | if (__young) \ |
323 | clear_bit(_PAGE_BIT_ACCESSED, &(ptep)->pte_low); \ | ||
324 | pte_update_defer((vma)->vm_mm, (address), (ptep)); \ | ||
325 | flush_tlb_page(vma, address); \ | 346 | flush_tlb_page(vma, address); \ |
326 | } \ | ||
327 | __young; \ | 347 | __young; \ |
328 | }) | 348 | }) |
329 | 349 | ||
330 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | 350 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR |
331 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 351 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
332 | { | 352 | { |
333 | pte_t pte = raw_ptep_get_and_clear(ptep); | 353 | pte_t pte = native_ptep_get_and_clear(ptep); |
334 | pte_update(mm, addr, ptep); | 354 | pte_update(mm, addr, ptep); |
335 | return pte; | 355 | return pte; |
336 | } | 356 | } |
@@ -340,8 +360,11 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long | |||
340 | { | 360 | { |
341 | pte_t pte; | 361 | pte_t pte; |
342 | if (full) { | 362 | if (full) { |
343 | pte = *ptep; | 363 | /* |
344 | pte_clear(mm, addr, ptep); | 364 | * Full address destruction in progress; paravirt does not |
365 | * care about updates and native needs no locking | ||
366 | */ | ||
367 | pte = native_local_ptep_get_and_clear(ptep); | ||
345 | } else { | 368 | } else { |
346 | pte = ptep_get_and_clear(mm, addr, ptep); | 369 | pte = ptep_get_and_clear(mm, addr, ptep); |
347 | } | 370 | } |
@@ -470,24 +493,10 @@ extern pte_t *lookup_address(unsigned long address); | |||
470 | #endif | 493 | #endif |
471 | 494 | ||
472 | #if defined(CONFIG_HIGHPTE) | 495 | #if defined(CONFIG_HIGHPTE) |
473 | #define pte_offset_map(dir, address) \ | 496 | #define pte_offset_map(dir, address) \ |
474 | ({ \ | 497 | ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address)) |
475 | pte_t *__ptep; \ | 498 | #define pte_offset_map_nested(dir, address) \ |
476 | unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \ | 499 | ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address)) |
477 | __ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE0);\ | ||
478 | paravirt_map_pt_hook(KM_PTE0,__ptep, pfn); \ | ||
479 | __ptep = __ptep + pte_index(address); \ | ||
480 | __ptep; \ | ||
481 | }) | ||
482 | #define pte_offset_map_nested(dir, address) \ | ||
483 | ({ \ | ||
484 | pte_t *__ptep; \ | ||
485 | unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \ | ||
486 | __ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE1);\ | ||
487 | paravirt_map_pt_hook(KM_PTE1,__ptep, pfn); \ | ||
488 | __ptep = __ptep + pte_index(address); \ | ||
489 | __ptep; \ | ||
490 | }) | ||
491 | #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) | 500 | #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) |
492 | #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) | 501 | #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) |
493 | #else | 502 | #else |
@@ -510,6 +519,22 @@ do { \ | |||
510 | * tables contain all the necessary information. | 519 | * tables contain all the necessary information. |
511 | */ | 520 | */ |
512 | #define update_mmu_cache(vma,address,pte) do { } while (0) | 521 | #define update_mmu_cache(vma,address,pte) do { } while (0) |
522 | |||
523 | void native_pagetable_setup_start(pgd_t *base); | ||
524 | void native_pagetable_setup_done(pgd_t *base); | ||
525 | |||
526 | #ifndef CONFIG_PARAVIRT | ||
527 | static inline void paravirt_pagetable_setup_start(pgd_t *base) | ||
528 | { | ||
529 | native_pagetable_setup_start(base); | ||
530 | } | ||
531 | |||
532 | static inline void paravirt_pagetable_setup_done(pgd_t *base) | ||
533 | { | ||
534 | native_pagetable_setup_done(base); | ||
535 | } | ||
536 | #endif /* !CONFIG_PARAVIRT */ | ||
537 | |||
513 | #endif /* !__ASSEMBLY__ */ | 538 | #endif /* !__ASSEMBLY__ */ |
514 | 539 | ||
515 | #ifdef CONFIG_FLATMEM | 540 | #ifdef CONFIG_FLATMEM |