162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Derived from MIPS: 662306a36Sopenharmony_ci * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle 762306a36Sopenharmony_ci * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#ifndef _ASM_PGTABLE_H 1062306a36Sopenharmony_ci#define _ASM_PGTABLE_H 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/compiler.h> 1362306a36Sopenharmony_ci#include <asm/addrspace.h> 1462306a36Sopenharmony_ci#include <asm/page.h> 1562306a36Sopenharmony_ci#include <asm/pgtable-bits.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS == 2 1862306a36Sopenharmony_ci#include <asm-generic/pgtable-nopmd.h> 1962306a36Sopenharmony_ci#elif CONFIG_PGTABLE_LEVELS == 3 2062306a36Sopenharmony_ci#include <asm-generic/pgtable-nopud.h> 2162306a36Sopenharmony_ci#else 2262306a36Sopenharmony_ci#include <asm-generic/pgtable-nop4d.h> 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS == 2 2662306a36Sopenharmony_ci#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3)) 2762306a36Sopenharmony_ci#elif CONFIG_PGTABLE_LEVELS == 3 2862306a36Sopenharmony_ci#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3)) 2962306a36Sopenharmony_ci#define PMD_SIZE (1UL << PMD_SHIFT) 3062306a36Sopenharmony_ci#define PMD_MASK (~(PMD_SIZE-1)) 3162306a36Sopenharmony_ci#define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT - 3)) 3262306a36Sopenharmony_ci#elif CONFIG_PGTABLE_LEVELS == 4 3362306a36Sopenharmony_ci#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3)) 3462306a36Sopenharmony_ci#define PMD_SIZE (1UL << PMD_SHIFT) 3562306a36Sopenharmony_ci#define PMD_MASK (~(PMD_SIZE-1)) 3662306a36Sopenharmony_ci#define PUD_SHIFT (PMD_SHIFT + (PAGE_SHIFT - 3)) 3762306a36Sopenharmony_ci#define PUD_SIZE (1UL << PUD_SHIFT) 3862306a36Sopenharmony_ci#define PUD_MASK (~(PUD_SIZE-1)) 3962306a36Sopenharmony_ci#define PGDIR_SHIFT (PUD_SHIFT + (PAGE_SHIFT - 3)) 4062306a36Sopenharmony_ci#endif 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 4362306a36Sopenharmony_ci#define PGDIR_MASK (~(PGDIR_SIZE-1)) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define VA_BITS (PGDIR_SHIFT + (PAGE_SHIFT - 3)) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define PTRS_PER_PGD (PAGE_SIZE >> 3) 4862306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3 4962306a36Sopenharmony_ci#define PTRS_PER_PUD (PAGE_SIZE >> 3) 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2 5262306a36Sopenharmony_ci#define PTRS_PER_PMD (PAGE_SIZE >> 3) 5362306a36Sopenharmony_ci#endif 5462306a36Sopenharmony_ci#define PTRS_PER_PTE (PAGE_SIZE >> 3) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE):1) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include <linux/mm_types.h> 6162306a36Sopenharmony_ci#include <linux/mmzone.h> 6262306a36Sopenharmony_ci#include <asm/fixmap.h> 6362306a36Sopenharmony_ci#include <asm/sparsemem.h> 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistruct mm_struct; 6662306a36Sopenharmony_cistruct vm_area_struct; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * ZERO_PAGE is a global shared page that is always zero; used 7062306a36Sopenharmony_ci * for zero-mapped memory areas etc.. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciextern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * TLB refill handlers may also map the vmalloc area into xkvrange. 7962306a36Sopenharmony_ci * Avoid the first couple of pages so NULL pointer dereferences will 8062306a36Sopenharmony_ci * still reliably trap. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci#define MODULES_VADDR (vm_map_base + PCI_IOSIZE + (2 * PAGE_SIZE)) 8362306a36Sopenharmony_ci#define MODULES_END (MODULES_VADDR + SZ_256M) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#ifdef CONFIG_KFENCE 8662306a36Sopenharmony_ci#define KFENCE_AREA_SIZE (((CONFIG_KFENCE_NUM_OBJECTS + 1) * 2 + 2) * PAGE_SIZE) 8762306a36Sopenharmony_ci#else 8862306a36Sopenharmony_ci#define KFENCE_AREA_SIZE 0 8962306a36Sopenharmony_ci#endif 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define VMALLOC_START MODULES_END 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#ifndef CONFIG_KASAN 9462306a36Sopenharmony_ci#define VMALLOC_END \ 9562306a36Sopenharmony_ci (vm_map_base + \ 9662306a36Sopenharmony_ci min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE - KFENCE_AREA_SIZE) 9762306a36Sopenharmony_ci#else 9862306a36Sopenharmony_ci#define VMALLOC_END \ 9962306a36Sopenharmony_ci (vm_map_base + \ 10062306a36Sopenharmony_ci min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits) / 2) - PMD_SIZE - VMEMMAP_SIZE - KFENCE_AREA_SIZE) 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define vmemmap ((struct page *)((VMALLOC_END + PMD_SIZE) & PMD_MASK)) 10462306a36Sopenharmony_ci#define VMEMMAP_END ((unsigned long)vmemmap + VMEMMAP_SIZE - 1) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define KFENCE_AREA_START (VMEMMAP_END + 1) 10762306a36Sopenharmony_ci#define KFENCE_AREA_END (KFENCE_AREA_START + KFENCE_AREA_SIZE - 1) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define pte_ERROR(e) \ 11062306a36Sopenharmony_ci pr_err("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) 11162306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 11262306a36Sopenharmony_ci#define pmd_ERROR(e) \ 11362306a36Sopenharmony_ci pr_err("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) 11462306a36Sopenharmony_ci#endif 11562306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED 11662306a36Sopenharmony_ci#define pud_ERROR(e) \ 11762306a36Sopenharmony_ci pr_err("%s:%d: bad pud %016lx.\n", __FILE__, __LINE__, pud_val(e)) 11862306a36Sopenharmony_ci#endif 11962306a36Sopenharmony_ci#define pgd_ERROR(e) \ 12062306a36Sopenharmony_ci pr_err("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciextern pte_t invalid_pte_table[PTRS_PER_PTE]; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_citypedef struct { unsigned long pud; } pud_t; 12762306a36Sopenharmony_ci#define pud_val(x) ((x).pud) 12862306a36Sopenharmony_ci#define __pud(x) ((pud_t) { (x) }) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciextern pud_t invalid_pud_table[PTRS_PER_PUD]; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * Empty pgd/p4d entries point to the invalid_pud_table. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistatic inline int p4d_none(p4d_t p4d) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return p4d_val(p4d) == (unsigned long)invalid_pud_table; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic inline int p4d_bad(p4d_t p4d) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return p4d_val(p4d) & ~PAGE_MASK; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic inline int p4d_present(p4d_t p4d) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci return p4d_val(p4d) != (unsigned long)invalid_pud_table; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic inline void p4d_clear(p4d_t *p4dp) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci p4d_val(*p4dp) = (unsigned long)invalid_pud_table; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic inline pud_t *p4d_pgtable(p4d_t p4d) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci return (pud_t *)p4d_val(p4d); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic inline void set_p4d(p4d_t *p4d, p4d_t p4dval) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci *p4d = p4dval; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#define p4d_phys(p4d) PHYSADDR(p4d_val(p4d)) 16662306a36Sopenharmony_ci#define p4d_page(p4d) (pfn_to_page(p4d_phys(p4d) >> PAGE_SHIFT)) 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#endif 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_citypedef struct { unsigned long pmd; } pmd_t; 17362306a36Sopenharmony_ci#define pmd_val(x) ((x).pmd) 17462306a36Sopenharmony_ci#define __pmd(x) ((pmd_t) { (x) }) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciextern pmd_t invalid_pmd_table[PTRS_PER_PMD]; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * Empty pud entries point to the invalid_pmd_table. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic inline int pud_none(pud_t pud) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci return pud_val(pud) == (unsigned long)invalid_pmd_table; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic inline int pud_bad(pud_t pud) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci return pud_val(pud) & ~PAGE_MASK; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic inline int pud_present(pud_t pud) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci return pud_val(pud) != (unsigned long)invalid_pmd_table; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic inline void pud_clear(pud_t *pudp) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci pud_val(*pudp) = ((unsigned long)invalid_pmd_table); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci return (pmd_t *)pud_val(pud); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while (0) 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define pud_phys(pud) PHYSADDR(pud_val(pud)) 20962306a36Sopenharmony_ci#define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT)) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci#endif 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* 21462306a36Sopenharmony_ci * Empty pmd entries point to the invalid_pte_table. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_cistatic inline int pmd_none(pmd_t pmd) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return pmd_val(pmd) == (unsigned long)invalid_pte_table; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic inline int pmd_bad(pmd_t pmd) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return (pmd_val(pmd) & ~PAGE_MASK); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic inline int pmd_present(pmd_t pmd) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci if (unlikely(pmd_val(pmd) & _PAGE_HUGE)) 22962306a36Sopenharmony_ci return !!(pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PRESENT_INVALID)); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return pmd_val(pmd) != (unsigned long)invalid_pte_table; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic inline void pmd_clear(pmd_t *pmdp) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci pmd_val(*pmdp) = ((unsigned long)invalid_pte_table); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while (0) 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci#define pmd_phys(pmd) PHYSADDR(pmd_val(pmd)) 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci#ifndef CONFIG_TRANSPARENT_HUGEPAGE 24462306a36Sopenharmony_ci#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT)) 24562306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci#define pmd_page_vaddr(pmd) pmd_val(pmd) 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ciextern pmd_t mk_pmd(struct page *page, pgprot_t prot); 25062306a36Sopenharmony_ciextern void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci#define pte_page(x) pfn_to_page(pte_pfn(x)) 25362306a36Sopenharmony_ci#define pte_pfn(x) ((unsigned long)(((x).pte & _PFN_MASK) >> PFN_PTE_SHIFT)) 25462306a36Sopenharmony_ci#define pfn_pte(pfn, prot) __pte(((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot)) 25562306a36Sopenharmony_ci#define pfn_pmd(pfn, prot) __pmd(((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot)) 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* 25862306a36Sopenharmony_ci * Initialize a new pgd / pud / pmd table with invalid pointers. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ciextern void pgd_init(void *addr); 26162306a36Sopenharmony_ciextern void pud_init(void *addr); 26262306a36Sopenharmony_ciextern void pmd_init(void *addr); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that 26662306a36Sopenharmony_ci * are !pte_none() && !pte_present(). 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * Format of swap PTEs: 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * 6 6 6 6 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 27162306a36Sopenharmony_ci * 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 27262306a36Sopenharmony_ci * <--------------------------- offset --------------------------- 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 27562306a36Sopenharmony_ci * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 27662306a36Sopenharmony_ci * --------------> E <--- type ---> <---------- zeroes ----------> 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * E is the exclusive marker that is not stored in swap entries. 27962306a36Sopenharmony_ci * The zero'ed bits include _PAGE_PRESENT and _PAGE_PROTNONE. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) 28262306a36Sopenharmony_ci{ pte_t pte; pte_val(pte) = ((type & 0x7f) << 16) | (offset << 24); return pte; } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci#define __swp_type(x) (((x).val >> 16) & 0x7f) 28562306a36Sopenharmony_ci#define __swp_offset(x) ((x).val >> 24) 28662306a36Sopenharmony_ci#define __swp_entry(type, offset) ((swp_entry_t) { pte_val(mk_swap_pte((type), (offset))) }) 28762306a36Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) 28862306a36Sopenharmony_ci#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) 28962306a36Sopenharmony_ci#define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) }) 29062306a36Sopenharmony_ci#define __swp_entry_to_pmd(x) ((pmd_t) { (x).val | _PAGE_HUGE }) 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic inline int pte_swp_exclusive(pte_t pte) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic inline pte_t pte_swp_mkexclusive(pte_t pte) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci pte_val(pte) |= _PAGE_SWP_EXCLUSIVE; 30062306a36Sopenharmony_ci return pte; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_exclusive(pte_t pte) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci pte_val(pte) &= ~_PAGE_SWP_EXCLUSIVE; 30662306a36Sopenharmony_ci return pte; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ciextern void paging_init(void); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci#define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL)) 31262306a36Sopenharmony_ci#define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROTNONE)) 31362306a36Sopenharmony_ci#define pte_no_exec(pte) (pte_val(pte) & _PAGE_NO_EXEC) 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic inline void set_pte(pte_t *ptep, pte_t pteval) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci *ptep = pteval; 31862306a36Sopenharmony_ci if (pte_val(pteval) & _PAGE_GLOBAL) { 31962306a36Sopenharmony_ci pte_t *buddy = ptep_buddy(ptep); 32062306a36Sopenharmony_ci /* 32162306a36Sopenharmony_ci * Make sure the buddy is global too (if it's !none, 32262306a36Sopenharmony_ci * it better already be global) 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci#ifdef CONFIG_SMP 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * For SMP, multiple CPUs can race, so we need to do 32762306a36Sopenharmony_ci * this atomically. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci unsigned long page_global = _PAGE_GLOBAL; 33062306a36Sopenharmony_ci unsigned long tmp; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci __asm__ __volatile__ ( 33362306a36Sopenharmony_ci "1:" __LL "%[tmp], %[buddy] \n" 33462306a36Sopenharmony_ci " bnez %[tmp], 2f \n" 33562306a36Sopenharmony_ci " or %[tmp], %[tmp], %[global] \n" 33662306a36Sopenharmony_ci __SC "%[tmp], %[buddy] \n" 33762306a36Sopenharmony_ci " beqz %[tmp], 1b \n" 33862306a36Sopenharmony_ci " nop \n" 33962306a36Sopenharmony_ci "2: \n" 34062306a36Sopenharmony_ci __WEAK_LLSC_MB 34162306a36Sopenharmony_ci : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) 34262306a36Sopenharmony_ci : [global] "r" (page_global)); 34362306a36Sopenharmony_ci#else /* !CONFIG_SMP */ 34462306a36Sopenharmony_ci if (pte_none(*buddy)) 34562306a36Sopenharmony_ci pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL; 34662306a36Sopenharmony_ci#endif /* CONFIG_SMP */ 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci /* Preserve global status for the pair */ 35362306a36Sopenharmony_ci if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL) 35462306a36Sopenharmony_ci set_pte(ptep, __pte(_PAGE_GLOBAL)); 35562306a36Sopenharmony_ci else 35662306a36Sopenharmony_ci set_pte(ptep, __pte(0)); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci#define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1) 36062306a36Sopenharmony_ci#define PMD_T_LOG2 (__builtin_ffs(sizeof(pmd_t)) - 1) 36162306a36Sopenharmony_ci#define PTE_T_LOG2 (__builtin_ffs(sizeof(pte_t)) - 1) 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ciextern pgd_t swapper_pg_dir[]; 36462306a36Sopenharmony_ciextern pgd_t invalid_pg_dir[]; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistruct page *dmw_virt_to_page(unsigned long kaddr); 36762306a36Sopenharmony_cistruct page *tlb_virt_to_page(unsigned long kaddr); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/* 37062306a36Sopenharmony_ci * The following only work if pte_present() is true. 37162306a36Sopenharmony_ci * Undefined behaviour if not.. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_cistatic inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } 37462306a36Sopenharmony_cistatic inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } 37562306a36Sopenharmony_cistatic inline int pte_dirty(pte_t pte) { return pte_val(pte) & (_PAGE_DIRTY | _PAGE_MODIFIED); } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci pte_val(pte) &= ~_PAGE_ACCESSED; 38062306a36Sopenharmony_ci return pte; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci pte_val(pte) |= _PAGE_ACCESSED; 38662306a36Sopenharmony_ci return pte; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_MODIFIED); 39262306a36Sopenharmony_ci return pte; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci pte_val(pte) |= _PAGE_MODIFIED; 39862306a36Sopenharmony_ci if (pte_val(pte) & _PAGE_WRITE) 39962306a36Sopenharmony_ci pte_val(pte) |= _PAGE_DIRTY; 40062306a36Sopenharmony_ci return pte; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci pte_val(pte) |= _PAGE_WRITE; 40662306a36Sopenharmony_ci if (pte_val(pte) & _PAGE_MODIFIED) 40762306a36Sopenharmony_ci pte_val(pte) |= _PAGE_DIRTY; 40862306a36Sopenharmony_ci return pte; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_DIRTY); 41462306a36Sopenharmony_ci return pte; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic inline int pte_huge(pte_t pte) { return pte_val(pte) & _PAGE_HUGE; } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic inline pte_t pte_mkhuge(pte_t pte) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci pte_val(pte) |= _PAGE_HUGE; 42262306a36Sopenharmony_ci return pte; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci#if defined(CONFIG_ARCH_HAS_PTE_SPECIAL) 42662306a36Sopenharmony_cistatic inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; } 42762306a36Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte) { pte_val(pte) |= _PAGE_SPECIAL; return pte; } 42862306a36Sopenharmony_ci#endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci#define pte_accessible pte_accessible 43162306a36Sopenharmony_cistatic inline unsigned long pte_accessible(struct mm_struct *mm, pte_t a) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci if (pte_val(a) & _PAGE_PRESENT) 43462306a36Sopenharmony_ci return true; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if ((pte_val(a) & _PAGE_PROTNONE) && 43762306a36Sopenharmony_ci atomic_read(&mm->tlb_flush_pending)) 43862306a36Sopenharmony_ci return true; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return false; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* 44462306a36Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry, 44562306a36Sopenharmony_ci * and a page entry and page directory to the page they refer to. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci return __pte((pte_val(pte) & _PAGE_CHG_MASK) | 45262306a36Sopenharmony_ci (pgprot_val(newprot) & ~_PAGE_CHG_MASK)); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciextern void __update_tlb(struct vm_area_struct *vma, 45662306a36Sopenharmony_ci unsigned long address, pte_t *ptep); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic inline void update_mmu_cache_range(struct vm_fault *vmf, 45962306a36Sopenharmony_ci struct vm_area_struct *vma, unsigned long address, 46062306a36Sopenharmony_ci pte_t *ptep, unsigned int nr) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci for (;;) { 46362306a36Sopenharmony_ci __update_tlb(vma, address, ptep); 46462306a36Sopenharmony_ci if (--nr == 0) 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci address += PAGE_SIZE; 46762306a36Sopenharmony_ci ptep++; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci#define update_mmu_cache(vma, addr, ptep) \ 47162306a36Sopenharmony_ci update_mmu_cache_range(NULL, vma, addr, ptep, 1) 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci#define __HAVE_ARCH_UPDATE_MMU_TLB 47462306a36Sopenharmony_ci#define update_mmu_tlb update_mmu_cache 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic inline void update_mmu_cache_pmd(struct vm_area_struct *vma, 47762306a36Sopenharmony_ci unsigned long address, pmd_t *pmdp) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci __update_tlb(vma, address, (pte_t *)pmdp); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic inline unsigned long pmd_pfn(pmd_t pmd) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci return (pmd_val(pmd) & _PFN_MASK) >> PFN_PTE_SHIFT; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/ 49062306a36Sopenharmony_ci#define pmdp_establish generic_pmdp_establish 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic inline int pmd_trans_huge(pmd_t pmd) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci return !!(pmd_val(pmd) & _PAGE_HUGE) && pmd_present(pmd); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic inline pmd_t pmd_mkhuge(pmd_t pmd) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci pmd_val(pmd) = (pmd_val(pmd) & ~(_PAGE_GLOBAL)) | 50062306a36Sopenharmony_ci ((pmd_val(pmd) & _PAGE_GLOBAL) << (_PAGE_HGLOBAL_SHIFT - _PAGE_GLOBAL_SHIFT)); 50162306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_HUGE; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return pmd; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci#define pmd_write pmd_write 50762306a36Sopenharmony_cistatic inline int pmd_write(pmd_t pmd) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci return !!(pmd_val(pmd) & _PAGE_WRITE); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic inline pmd_t pmd_mkwrite_novma(pmd_t pmd) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_WRITE; 51562306a36Sopenharmony_ci if (pmd_val(pmd) & _PAGE_MODIFIED) 51662306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_DIRTY; 51762306a36Sopenharmony_ci return pmd; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic inline pmd_t pmd_wrprotect(pmd_t pmd) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci pmd_val(pmd) &= ~(_PAGE_WRITE | _PAGE_DIRTY); 52362306a36Sopenharmony_ci return pmd; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic inline int pmd_dirty(pmd_t pmd) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci return !!(pmd_val(pmd) & (_PAGE_DIRTY | _PAGE_MODIFIED)); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic inline pmd_t pmd_mkclean(pmd_t pmd) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci pmd_val(pmd) &= ~(_PAGE_DIRTY | _PAGE_MODIFIED); 53462306a36Sopenharmony_ci return pmd; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic inline pmd_t pmd_mkdirty(pmd_t pmd) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_MODIFIED; 54062306a36Sopenharmony_ci if (pmd_val(pmd) & _PAGE_WRITE) 54162306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_DIRTY; 54262306a36Sopenharmony_ci return pmd; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci#define pmd_young pmd_young 54662306a36Sopenharmony_cistatic inline int pmd_young(pmd_t pmd) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci return !!(pmd_val(pmd) & _PAGE_ACCESSED); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic inline pmd_t pmd_mkold(pmd_t pmd) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci pmd_val(pmd) &= ~_PAGE_ACCESSED; 55462306a36Sopenharmony_ci return pmd; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic inline pmd_t pmd_mkyoung(pmd_t pmd) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_ACCESSED; 56062306a36Sopenharmony_ci return pmd; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic inline struct page *pmd_page(pmd_t pmd) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci if (pmd_trans_huge(pmd)) 56662306a36Sopenharmony_ci return pfn_to_page(pmd_pfn(pmd)); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci pmd_val(pmd) = (pmd_val(pmd) & _HPAGE_CHG_MASK) | 57462306a36Sopenharmony_ci (pgprot_val(newprot) & ~_HPAGE_CHG_MASK); 57562306a36Sopenharmony_ci return pmd; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic inline pmd_t pmd_mkinvalid(pmd_t pmd) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci pmd_val(pmd) |= _PAGE_PRESENT_INVALID; 58162306a36Sopenharmony_ci pmd_val(pmd) &= ~(_PAGE_PRESENT | _PAGE_VALID | _PAGE_DIRTY | _PAGE_PROTNONE); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return pmd; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* 58762306a36Sopenharmony_ci * The generic version pmdp_huge_get_and_clear uses a version of pmd_clear() with a 58862306a36Sopenharmony_ci * different prototype. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR 59162306a36Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, 59262306a36Sopenharmony_ci unsigned long address, pmd_t *pmdp) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci pmd_t old = *pmdp; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci pmd_clear(pmdp); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return old; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING 60462306a36Sopenharmony_cistatic inline long pte_protnone(pte_t pte) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci return (pte_val(pte) & _PAGE_PROTNONE); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic inline long pmd_protnone(pmd_t pmd) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci return (pmd_val(pmd) & _PAGE_PROTNONE); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci#endif /* CONFIG_NUMA_BALANCING */ 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci#define pmd_leaf(pmd) ((pmd_val(pmd) & _PAGE_HUGE) != 0) 61662306a36Sopenharmony_ci#define pud_leaf(pud) ((pud_val(pud) & _PAGE_HUGE) != 0) 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci/* 61962306a36Sopenharmony_ci * We provide our own get_unmapped area to cope with the virtual aliasing 62062306a36Sopenharmony_ci * constraints placed on us by the cache architecture. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA 62362306a36Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci#endif /* _ASM_PGTABLE_H */ 628