diff options
Diffstat (limited to 'arch/arm64/include/asm/pgtable.h')
-rw-r--r-- | arch/arm64/include/asm/pgtable.h | 100 |
1 files changed, 76 insertions, 24 deletions
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index e0ccceb317d9..ffe1ba0506d1 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h | |||
@@ -33,9 +33,16 @@ | |||
33 | 33 | ||
34 | /* | 34 | /* |
35 | * VMALLOC and SPARSEMEM_VMEMMAP ranges. | 35 | * VMALLOC and SPARSEMEM_VMEMMAP ranges. |
36 | * | ||
37 | * VMEMAP_SIZE: allows the whole VA space to be covered by a struct page array | ||
38 | * (rounded up to PUD_SIZE). | ||
39 | * VMALLOC_START: beginning of the kernel VA space | ||
40 | * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space, | ||
41 | * fixed mappings and modules | ||
36 | */ | 42 | */ |
43 | #define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE) | ||
37 | #define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS) | 44 | #define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS) |
38 | #define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K) | 45 | #define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K) |
39 | 46 | ||
40 | #define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) | 47 | #define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) |
41 | 48 | ||
@@ -44,14 +51,9 @@ | |||
44 | #ifndef __ASSEMBLY__ | 51 | #ifndef __ASSEMBLY__ |
45 | extern void __pte_error(const char *file, int line, unsigned long val); | 52 | extern void __pte_error(const char *file, int line, unsigned long val); |
46 | extern void __pmd_error(const char *file, int line, unsigned long val); | 53 | extern void __pmd_error(const char *file, int line, unsigned long val); |
54 | extern void __pud_error(const char *file, int line, unsigned long val); | ||
47 | extern void __pgd_error(const char *file, int line, unsigned long val); | 55 | extern void __pgd_error(const char *file, int line, unsigned long val); |
48 | 56 | ||
49 | #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) | ||
50 | #ifndef CONFIG_ARM64_64K_PAGES | ||
51 | #define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) | ||
52 | #endif | ||
53 | #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) | ||
54 | |||
55 | #ifdef CONFIG_SMP | 57 | #ifdef CONFIG_SMP |
56 | #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) | 58 | #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) |
57 | #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) | 59 | #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) |
@@ -112,6 +114,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val); | |||
112 | extern struct page *empty_zero_page; | 114 | extern struct page *empty_zero_page; |
113 | #define ZERO_PAGE(vaddr) (empty_zero_page) | 115 | #define ZERO_PAGE(vaddr) (empty_zero_page) |
114 | 116 | ||
117 | #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) | ||
118 | |||
115 | #define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT) | 119 | #define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT) |
116 | 120 | ||
117 | #define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) | 121 | #define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) |
@@ -119,6 +123,10 @@ extern struct page *empty_zero_page; | |||
119 | #define pte_none(pte) (!pte_val(pte)) | 123 | #define pte_none(pte) (!pte_val(pte)) |
120 | #define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) | 124 | #define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) |
121 | #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) | 125 | #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) |
126 | |||
127 | /* Find an entry in the third-level page table. */ | ||
128 | #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) | ||
129 | |||
122 | #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr)) | 130 | #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr)) |
123 | 131 | ||
124 | #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) | 132 | #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) |
@@ -138,6 +146,8 @@ extern struct page *empty_zero_page; | |||
138 | 146 | ||
139 | #define pte_valid_user(pte) \ | 147 | #define pte_valid_user(pte) \ |
140 | ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) | 148 | ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) |
149 | #define pte_valid_not_user(pte) \ | ||
150 | ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID) | ||
141 | 151 | ||
142 | static inline pte_t pte_wrprotect(pte_t pte) | 152 | static inline pte_t pte_wrprotect(pte_t pte) |
143 | { | 153 | { |
@@ -184,6 +194,15 @@ static inline pte_t pte_mkspecial(pte_t pte) | |||
184 | static inline void set_pte(pte_t *ptep, pte_t pte) | 194 | static inline void set_pte(pte_t *ptep, pte_t pte) |
185 | { | 195 | { |
186 | *ptep = pte; | 196 | *ptep = pte; |
197 | |||
198 | /* | ||
199 | * Only if the new pte is valid and kernel, otherwise TLB maintenance | ||
200 | * or update_mmu_cache() have the necessary barriers. | ||
201 | */ | ||
202 | if (pte_valid_not_user(pte)) { | ||
203 | dsb(ishst); | ||
204 | isb(); | ||
205 | } | ||
187 | } | 206 | } |
188 | 207 | ||
189 | extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); | 208 | extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); |
@@ -303,6 +322,7 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) | |||
303 | { | 322 | { |
304 | *pmdp = pmd; | 323 | *pmdp = pmd; |
305 | dsb(ishst); | 324 | dsb(ishst); |
325 | isb(); | ||
306 | } | 326 | } |
307 | 327 | ||
308 | static inline void pmd_clear(pmd_t *pmdp) | 328 | static inline void pmd_clear(pmd_t *pmdp) |
@@ -323,7 +343,9 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) | |||
323 | */ | 343 | */ |
324 | #define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) | 344 | #define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) |
325 | 345 | ||
326 | #ifndef CONFIG_ARM64_64K_PAGES | 346 | #if CONFIG_ARM64_PGTABLE_LEVELS > 2 |
347 | |||
348 | #define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) | ||
327 | 349 | ||
328 | #define pud_none(pud) (!pud_val(pud)) | 350 | #define pud_none(pud) (!pud_val(pud)) |
329 | #define pud_bad(pud) (!(pud_val(pud) & 2)) | 351 | #define pud_bad(pud) (!(pud_val(pud) & 2)) |
@@ -333,6 +355,7 @@ static inline void set_pud(pud_t *pudp, pud_t pud) | |||
333 | { | 355 | { |
334 | *pudp = pud; | 356 | *pudp = pud; |
335 | dsb(ishst); | 357 | dsb(ishst); |
358 | isb(); | ||
336 | } | 359 | } |
337 | 360 | ||
338 | static inline void pud_clear(pud_t *pudp) | 361 | static inline void pud_clear(pud_t *pudp) |
@@ -345,7 +368,51 @@ static inline pmd_t *pud_page_vaddr(pud_t pud) | |||
345 | return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); | 368 | return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); |
346 | } | 369 | } |
347 | 370 | ||
348 | #endif /* CONFIG_ARM64_64K_PAGES */ | 371 | /* Find an entry in the second-level page table. */ |
372 | #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) | ||
373 | |||
374 | static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | ||
375 | { | ||
376 | return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr); | ||
377 | } | ||
378 | |||
379 | #endif /* CONFIG_ARM64_PGTABLE_LEVELS > 2 */ | ||
380 | |||
381 | #if CONFIG_ARM64_PGTABLE_LEVELS > 3 | ||
382 | |||
383 | #define pud_ERROR(pud) __pud_error(__FILE__, __LINE__, pud_val(pud)) | ||
384 | |||
385 | #define pgd_none(pgd) (!pgd_val(pgd)) | ||
386 | #define pgd_bad(pgd) (!(pgd_val(pgd) & 2)) | ||
387 | #define pgd_present(pgd) (pgd_val(pgd)) | ||
388 | |||
389 | static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) | ||
390 | { | ||
391 | *pgdp = pgd; | ||
392 | dsb(ishst); | ||
393 | } | ||
394 | |||
395 | static inline void pgd_clear(pgd_t *pgdp) | ||
396 | { | ||
397 | set_pgd(pgdp, __pgd(0)); | ||
398 | } | ||
399 | |||
400 | static inline pud_t *pgd_page_vaddr(pgd_t pgd) | ||
401 | { | ||
402 | return __va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK); | ||
403 | } | ||
404 | |||
405 | /* Find an entry in the frst-level page table. */ | ||
406 | #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) | ||
407 | |||
408 | static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr) | ||
409 | { | ||
410 | return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr); | ||
411 | } | ||
412 | |||
413 | #endif /* CONFIG_ARM64_PGTABLE_LEVELS > 3 */ | ||
414 | |||
415 | #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) | ||
349 | 416 | ||
350 | /* to find an entry in a page-table-directory */ | 417 | /* to find an entry in a page-table-directory */ |
351 | #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) | 418 | #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) |
@@ -355,18 +422,6 @@ static inline pmd_t *pud_page_vaddr(pud_t pud) | |||
355 | /* to find an entry in a kernel page-table-directory */ | 422 | /* to find an entry in a kernel page-table-directory */ |
356 | #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) | 423 | #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) |
357 | 424 | ||
358 | /* Find an entry in the second-level page table.. */ | ||
359 | #ifndef CONFIG_ARM64_64K_PAGES | ||
360 | #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) | ||
361 | static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | ||
362 | { | ||
363 | return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr); | ||
364 | } | ||
365 | #endif | ||
366 | |||
367 | /* Find an entry in the third-level page table.. */ | ||
368 | #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) | ||
369 | |||
370 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | 425 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) |
371 | { | 426 | { |
372 | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | | 427 | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | |
@@ -383,9 +438,6 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) | |||
383 | extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; | 438 | extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; |
384 | extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; | 439 | extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; |
385 | 440 | ||
386 | #define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) | ||
387 | #define IDMAP_DIR_SIZE (2 * PAGE_SIZE) | ||
388 | |||
389 | /* | 441 | /* |
390 | * Encode and decode a swap entry: | 442 | * Encode and decode a swap entry: |
391 | * bits 0-1: present (must be zero) | 443 | * bits 0-1: present (must be zero) |