162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_PGTABLE_64_H 362306a36Sopenharmony_ci#define _ASM_X86_PGTABLE_64_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/const.h> 662306a36Sopenharmony_ci#include <asm/pgtable_64_types.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * This file contains the functions and defines necessary to modify and use 1262306a36Sopenharmony_ci * the x86-64 page table tree. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <asm/processor.h> 1562306a36Sopenharmony_ci#include <linux/bitops.h> 1662306a36Sopenharmony_ci#include <linux/threads.h> 1762306a36Sopenharmony_ci#include <asm/fixmap.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciextern p4d_t level4_kernel_pgt[512]; 2062306a36Sopenharmony_ciextern p4d_t level4_ident_pgt[512]; 2162306a36Sopenharmony_ciextern pud_t level3_kernel_pgt[512]; 2262306a36Sopenharmony_ciextern pud_t level3_ident_pgt[512]; 2362306a36Sopenharmony_ciextern pmd_t level2_kernel_pgt[512]; 2462306a36Sopenharmony_ciextern pmd_t level2_fixmap_pgt[512]; 2562306a36Sopenharmony_ciextern pmd_t level2_ident_pgt[512]; 2662306a36Sopenharmony_ciextern pte_t level1_fixmap_pgt[512 * FIXMAP_PMD_NUM]; 2762306a36Sopenharmony_ciextern pgd_t init_top_pgt[]; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define swapper_pg_dir init_top_pgt 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciextern void paging_init(void); 3262306a36Sopenharmony_cistatic inline void sync_initial_page_table(void) { } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define pte_ERROR(e) \ 3562306a36Sopenharmony_ci pr_err("%s:%d: bad pte %p(%016lx)\n", \ 3662306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pte_val(e)) 3762306a36Sopenharmony_ci#define pmd_ERROR(e) \ 3862306a36Sopenharmony_ci pr_err("%s:%d: bad pmd %p(%016lx)\n", \ 3962306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pmd_val(e)) 4062306a36Sopenharmony_ci#define pud_ERROR(e) \ 4162306a36Sopenharmony_ci pr_err("%s:%d: bad pud %p(%016lx)\n", \ 4262306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pud_val(e)) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS >= 5 4562306a36Sopenharmony_ci#define p4d_ERROR(e) \ 4662306a36Sopenharmony_ci pr_err("%s:%d: bad p4d %p(%016lx)\n", \ 4762306a36Sopenharmony_ci __FILE__, __LINE__, &(e), p4d_val(e)) 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define pgd_ERROR(e) \ 5162306a36Sopenharmony_ci pr_err("%s:%d: bad pgd %p(%016lx)\n", \ 5262306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pgd_val(e)) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct mm_struct; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define mm_p4d_folded mm_p4d_folded 5762306a36Sopenharmony_cistatic inline bool mm_p4d_folded(struct mm_struct *mm) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci return !pgtable_l5_enabled(); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_civoid set_pte_vaddr_p4d(p4d_t *p4d_page, unsigned long vaddr, pte_t new_pte); 6362306a36Sopenharmony_civoid set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic inline void native_set_pte(pte_t *ptep, pte_t pte) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci WRITE_ONCE(*ptep, pte); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, 7162306a36Sopenharmony_ci pte_t *ptep) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci native_set_pte(ptep, native_make_pte(0)); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci native_set_pte(ptep, pte); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci WRITE_ONCE(*pmdp, pmd); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic inline void native_pmd_clear(pmd_t *pmd) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci native_set_pmd(pmd, native_make_pmd(0)); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic inline pte_t native_ptep_get_and_clear(pte_t *xp) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci#ifdef CONFIG_SMP 9462306a36Sopenharmony_ci return native_make_pte(xchg(&xp->pte, 0)); 9562306a36Sopenharmony_ci#else 9662306a36Sopenharmony_ci /* native_local_ptep_get_and_clear, 9762306a36Sopenharmony_ci but duplicated because of cyclic dependency */ 9862306a36Sopenharmony_ci pte_t ret = *xp; 9962306a36Sopenharmony_ci native_pte_clear(NULL, 0, xp); 10062306a36Sopenharmony_ci return ret; 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci#ifdef CONFIG_SMP 10762306a36Sopenharmony_ci return native_make_pmd(xchg(&xp->pmd, 0)); 10862306a36Sopenharmony_ci#else 10962306a36Sopenharmony_ci /* native_local_pmdp_get_and_clear, 11062306a36Sopenharmony_ci but duplicated because of cyclic dependency */ 11162306a36Sopenharmony_ci pmd_t ret = *xp; 11262306a36Sopenharmony_ci native_pmd_clear(xp); 11362306a36Sopenharmony_ci return ret; 11462306a36Sopenharmony_ci#endif 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline void native_set_pud(pud_t *pudp, pud_t pud) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci WRITE_ONCE(*pudp, pud); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic inline void native_pud_clear(pud_t *pud) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci native_set_pud(pud, native_make_pud(0)); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline pud_t native_pudp_get_and_clear(pud_t *xp) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci#ifdef CONFIG_SMP 13062306a36Sopenharmony_ci return native_make_pud(xchg(&xp->pud, 0)); 13162306a36Sopenharmony_ci#else 13262306a36Sopenharmony_ci /* native_local_pudp_get_and_clear, 13362306a36Sopenharmony_ci * but duplicated because of cyclic dependency 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci pud_t ret = *xp; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci native_pud_clear(xp); 13862306a36Sopenharmony_ci return ret; 13962306a36Sopenharmony_ci#endif 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci pgd_t pgd; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (pgtable_l5_enabled() || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) { 14762306a36Sopenharmony_ci WRITE_ONCE(*p4dp, p4d); 14862306a36Sopenharmony_ci return; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci pgd = native_make_pgd(native_p4d_val(p4d)); 15262306a36Sopenharmony_ci pgd = pti_set_user_pgtbl((pgd_t *)p4dp, pgd); 15362306a36Sopenharmony_ci WRITE_ONCE(*p4dp, native_make_p4d(native_pgd_val(pgd))); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic inline void native_p4d_clear(p4d_t *p4d) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci native_set_p4d(p4d, native_make_p4d(0)); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci WRITE_ONCE(*pgdp, pti_set_user_pgtbl(pgdp, pgd)); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic inline void native_pgd_clear(pgd_t *pgd) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci native_set_pgd(pgd, native_make_pgd(0)); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry, 17362306a36Sopenharmony_ci * and a page entry and page directory to the page they refer to. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* PGD - Level 4 access */ 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* PUD - Level 3 access */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* PMD - Level 2 access */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* PTE - Level 1 access */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * Encode and de-code a swap entry 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * | ... | 11| 10| 9|8|7|6|5| 4| 3|2| 1|0| <- bit number 18862306a36Sopenharmony_ci * | ... |SW3|SW2|SW1|G|L|D|A|CD|WT|U| W|P| <- bit names 18962306a36Sopenharmony_ci * | TYPE (59-63) | ~OFFSET (9-58) |0|0|X|X| X| E|F|SD|0| <- swp entry 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * G (8) is aliased and used as a PROT_NONE indicator for 19262306a36Sopenharmony_ci * !present ptes. We need to start storing swap entries above 19362306a36Sopenharmony_ci * there. We also need to avoid using A and D because of an 19462306a36Sopenharmony_ci * erratum where they can be incorrectly set by hardware on 19562306a36Sopenharmony_ci * non-present PTEs. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * SD Bits 1-4 are not used in non-present format and available for 19862306a36Sopenharmony_ci * special use described below: 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * SD (1) in swp entry is used to store soft dirty bit, which helps us 20162306a36Sopenharmony_ci * remember soft dirty over page migration 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * F (2) in swp entry is used to record when a pagetable is 20462306a36Sopenharmony_ci * writeprotected by userfaultfd WP support. 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * E (3) in swp entry is used to rememeber PG_anon_exclusive. 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * Bit 7 in swp entry should be 0 because pmd_present checks not only P, 20962306a36Sopenharmony_ci * but also L and G. 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * The offset is inverted by a binary not operation to make the high 21262306a36Sopenharmony_ci * physical bits set. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci#define SWP_TYPE_BITS 5 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci#define SWP_OFFSET_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* We always extract/encode the offset by shifting it all the way up, and then down again */ 21962306a36Sopenharmony_ci#define SWP_OFFSET_SHIFT (SWP_OFFSET_FIRST_BIT+SWP_TYPE_BITS) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* Extract the high bits for type */ 22462306a36Sopenharmony_ci#define __swp_type(x) ((x).val >> (64 - SWP_TYPE_BITS)) 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/* Shift up (to get rid of type), then down to get value */ 22762306a36Sopenharmony_ci#define __swp_offset(x) (~(x).val << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT) 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* 23062306a36Sopenharmony_ci * Shift the offset up "too far" by TYPE bits, then down again 23162306a36Sopenharmony_ci * The offset is inverted by a binary not operation to make the high 23262306a36Sopenharmony_ci * physical bits set. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci#define __swp_entry(type, offset) ((swp_entry_t) { \ 23562306a36Sopenharmony_ci (~(unsigned long)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \ 23662306a36Sopenharmony_ci | ((unsigned long)(type) << (64-SWP_TYPE_BITS)) }) 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) 23962306a36Sopenharmony_ci#define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val((pmd)) }) 24062306a36Sopenharmony_ci#define __swp_entry_to_pte(x) (__pte((x).val)) 24162306a36Sopenharmony_ci#define __swp_entry_to_pmd(x) (__pmd((x).val)) 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciextern void cleanup_highmap(void); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA 24662306a36Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci#define PAGE_AGP PAGE_KERNEL_NOCACHE 24962306a36Sopenharmony_ci#define HAVE_PAGE_AGP 1 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* fs/proc/kcore.c */ 25262306a36Sopenharmony_ci#define kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK) 25362306a36Sopenharmony_ci#define kc_offset_to_vaddr(o) ((o) | ~__VIRTUAL_MASK) 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_SAME 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci#define vmemmap ((struct page *)VMEMMAP_START) 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciextern void init_extra_mapping_uc(unsigned long phys, unsigned long size); 26062306a36Sopenharmony_ciextern void init_extra_mapping_wb(unsigned long phys, unsigned long size); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define gup_fast_permitted gup_fast_permitted 26362306a36Sopenharmony_cistatic inline bool gup_fast_permitted(unsigned long start, unsigned long end) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci if (end >> __VIRTUAL_MASK_SHIFT) 26662306a36Sopenharmony_ci return false; 26762306a36Sopenharmony_ci return true; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci#include <asm/pgtable-invert.h> 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 27362306a36Sopenharmony_ci#endif /* _ASM_X86_PGTABLE_64_H */ 274