18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_PGTABLE_64_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_PGTABLE_64_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/const.h> 68c2ecf20Sopenharmony_ci#include <asm/pgtable_64_types.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * This file contains the functions and defines necessary to modify and use 128c2ecf20Sopenharmony_ci * the x86-64 page table tree. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <asm/processor.h> 158c2ecf20Sopenharmony_ci#include <linux/bitops.h> 168c2ecf20Sopenharmony_ci#include <linux/threads.h> 178c2ecf20Sopenharmony_ci#include <asm/fixmap.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciextern p4d_t level4_kernel_pgt[512]; 208c2ecf20Sopenharmony_ciextern p4d_t level4_ident_pgt[512]; 218c2ecf20Sopenharmony_ciextern pud_t level3_kernel_pgt[512]; 228c2ecf20Sopenharmony_ciextern pud_t level3_ident_pgt[512]; 238c2ecf20Sopenharmony_ciextern pmd_t level2_kernel_pgt[512]; 248c2ecf20Sopenharmony_ciextern pmd_t level2_fixmap_pgt[512]; 258c2ecf20Sopenharmony_ciextern pmd_t level2_ident_pgt[512]; 268c2ecf20Sopenharmony_ciextern pte_t level1_fixmap_pgt[512 * FIXMAP_PMD_NUM]; 278c2ecf20Sopenharmony_ciextern pgd_t init_top_pgt[]; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define swapper_pg_dir init_top_pgt 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciextern void paging_init(void); 328c2ecf20Sopenharmony_cistatic inline void sync_initial_page_table(void) { } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define pte_ERROR(e) \ 358c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pte %p(%016lx)\n", \ 368c2ecf20Sopenharmony_ci __FILE__, __LINE__, &(e), pte_val(e)) 378c2ecf20Sopenharmony_ci#define pmd_ERROR(e) \ 388c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pmd %p(%016lx)\n", \ 398c2ecf20Sopenharmony_ci __FILE__, __LINE__, &(e), pmd_val(e)) 408c2ecf20Sopenharmony_ci#define pud_ERROR(e) \ 418c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pud %p(%016lx)\n", \ 428c2ecf20Sopenharmony_ci __FILE__, __LINE__, &(e), pud_val(e)) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS >= 5 458c2ecf20Sopenharmony_ci#define p4d_ERROR(e) \ 468c2ecf20Sopenharmony_ci pr_err("%s:%d: bad p4d %p(%016lx)\n", \ 478c2ecf20Sopenharmony_ci __FILE__, __LINE__, &(e), p4d_val(e)) 488c2ecf20Sopenharmony_ci#endif 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define pgd_ERROR(e) \ 518c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pgd %p(%016lx)\n", \ 528c2ecf20Sopenharmony_ci __FILE__, __LINE__, &(e), pgd_val(e)) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct mm_struct; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define mm_p4d_folded mm_p4d_folded 578c2ecf20Sopenharmony_cistatic inline bool mm_p4d_folded(struct mm_struct *mm) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return !pgtable_l5_enabled(); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_civoid set_pte_vaddr_p4d(p4d_t *p4d_page, unsigned long vaddr, pte_t new_pte); 638c2ecf20Sopenharmony_civoid set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline void native_set_pte(pte_t *ptep, pte_t pte) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci WRITE_ONCE(*ptep, pte); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, 718c2ecf20Sopenharmony_ci pte_t *ptep) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci native_set_pte(ptep, native_make_pte(0)); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci native_set_pte(ptep, pte); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci WRITE_ONCE(*pmdp, pmd); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline void native_pmd_clear(pmd_t *pmd) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci native_set_pmd(pmd, native_make_pmd(0)); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline pte_t native_ptep_get_and_clear(pte_t *xp) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 948c2ecf20Sopenharmony_ci return native_make_pte(xchg(&xp->pte, 0)); 958c2ecf20Sopenharmony_ci#else 968c2ecf20Sopenharmony_ci /* native_local_ptep_get_and_clear, 978c2ecf20Sopenharmony_ci but duplicated because of cyclic dependency */ 988c2ecf20Sopenharmony_ci pte_t ret = *xp; 998c2ecf20Sopenharmony_ci native_pte_clear(NULL, 0, xp); 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 1078c2ecf20Sopenharmony_ci return native_make_pmd(xchg(&xp->pmd, 0)); 1088c2ecf20Sopenharmony_ci#else 1098c2ecf20Sopenharmony_ci /* native_local_pmdp_get_and_clear, 1108c2ecf20Sopenharmony_ci but duplicated because of cyclic dependency */ 1118c2ecf20Sopenharmony_ci pmd_t ret = *xp; 1128c2ecf20Sopenharmony_ci native_pmd_clear(xp); 1138c2ecf20Sopenharmony_ci return ret; 1148c2ecf20Sopenharmony_ci#endif 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline void native_set_pud(pud_t *pudp, pud_t pud) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci WRITE_ONCE(*pudp, pud); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic inline void native_pud_clear(pud_t *pud) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci native_set_pud(pud, native_make_pud(0)); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic inline pud_t native_pudp_get_and_clear(pud_t *xp) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 1308c2ecf20Sopenharmony_ci return native_make_pud(xchg(&xp->pud, 0)); 1318c2ecf20Sopenharmony_ci#else 1328c2ecf20Sopenharmony_ci /* native_local_pudp_get_and_clear, 1338c2ecf20Sopenharmony_ci * but duplicated because of cyclic dependency 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci pud_t ret = *xp; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci native_pud_clear(xp); 1388c2ecf20Sopenharmony_ci return ret; 1398c2ecf20Sopenharmony_ci#endif 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci pgd_t pgd; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (pgtable_l5_enabled() || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) { 1478c2ecf20Sopenharmony_ci WRITE_ONCE(*p4dp, p4d); 1488c2ecf20Sopenharmony_ci return; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci pgd = native_make_pgd(native_p4d_val(p4d)); 1528c2ecf20Sopenharmony_ci pgd = pti_set_user_pgtbl((pgd_t *)p4dp, pgd); 1538c2ecf20Sopenharmony_ci WRITE_ONCE(*p4dp, native_make_p4d(native_pgd_val(pgd))); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void native_p4d_clear(p4d_t *p4d) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci native_set_p4d(p4d, native_make_p4d(0)); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci WRITE_ONCE(*pgdp, pti_set_user_pgtbl(pgdp, pgd)); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline void native_pgd_clear(pgd_t *pgd) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci native_set_pgd(pgd, native_make_pgd(0)); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* 1728c2ecf20Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry, 1738c2ecf20Sopenharmony_ci * and a page entry and page directory to the page they refer to. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* PGD - Level 4 access */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* PUD - Level 3 access */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* PMD - Level 2 access */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* PTE - Level 1 access */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * Encode and de-code a swap entry 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * | ... | 11| 10| 9|8|7|6|5| 4| 3|2| 1|0| <- bit number 1888c2ecf20Sopenharmony_ci * | ... |SW3|SW2|SW1|G|L|D|A|CD|WT|U| W|P| <- bit names 1898c2ecf20Sopenharmony_ci * | TYPE (59-63) | ~OFFSET (9-58) |0|0|X|X| X| X|F|SD|0| <- swp entry 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * G (8) is aliased and used as a PROT_NONE indicator for 1928c2ecf20Sopenharmony_ci * !present ptes. We need to start storing swap entries above 1938c2ecf20Sopenharmony_ci * there. We also need to avoid using A and D because of an 1948c2ecf20Sopenharmony_ci * erratum where they can be incorrectly set by hardware on 1958c2ecf20Sopenharmony_ci * non-present PTEs. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * SD Bits 1-4 are not used in non-present format and available for 1988c2ecf20Sopenharmony_ci * special use described below: 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * SD (1) in swp entry is used to store soft dirty bit, which helps us 2018c2ecf20Sopenharmony_ci * remember soft dirty over page migration 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * F (2) in swp entry is used to record when a pagetable is 2048c2ecf20Sopenharmony_ci * writeprotected by userfaultfd WP support. 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * Bit 7 in swp entry should be 0 because pmd_present checks not only P, 2078c2ecf20Sopenharmony_ci * but also L and G. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * The offset is inverted by a binary not operation to make the high 2108c2ecf20Sopenharmony_ci * physical bits set. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci#define SWP_TYPE_BITS 5 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci#define SWP_OFFSET_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* We always extract/encode the offset by shifting it all the way up, and then down again */ 2178c2ecf20Sopenharmony_ci#define SWP_OFFSET_SHIFT (SWP_OFFSET_FIRST_BIT+SWP_TYPE_BITS) 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* Extract the high bits for type */ 2228c2ecf20Sopenharmony_ci#define __swp_type(x) ((x).val >> (64 - SWP_TYPE_BITS)) 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Shift up (to get rid of type), then down to get value */ 2258c2ecf20Sopenharmony_ci#define __swp_offset(x) (~(x).val << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT) 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/* 2288c2ecf20Sopenharmony_ci * Shift the offset up "too far" by TYPE bits, then down again 2298c2ecf20Sopenharmony_ci * The offset is inverted by a binary not operation to make the high 2308c2ecf20Sopenharmony_ci * physical bits set. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci#define __swp_entry(type, offset) ((swp_entry_t) { \ 2338c2ecf20Sopenharmony_ci (~(unsigned long)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \ 2348c2ecf20Sopenharmony_ci | ((unsigned long)(type) << (64-SWP_TYPE_BITS)) }) 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) 2378c2ecf20Sopenharmony_ci#define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val((pmd)) }) 2388c2ecf20Sopenharmony_ci#define __swp_entry_to_pte(x) (__pte((x).val)) 2398c2ecf20Sopenharmony_ci#define __swp_entry_to_pmd(x) (__pmd((x).val)) 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ciextern int kern_addr_valid(unsigned long addr); 2428c2ecf20Sopenharmony_ciextern void cleanup_highmap(void); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA 2458c2ecf20Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#define PAGE_AGP PAGE_KERNEL_NOCACHE 2488c2ecf20Sopenharmony_ci#define HAVE_PAGE_AGP 1 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* fs/proc/kcore.c */ 2518c2ecf20Sopenharmony_ci#define kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK) 2528c2ecf20Sopenharmony_ci#define kc_offset_to_vaddr(o) ((o) | ~__VIRTUAL_MASK) 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTE_SAME 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci#define vmemmap ((struct page *)VMEMMAP_START) 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ciextern void init_extra_mapping_uc(unsigned long phys, unsigned long size); 2598c2ecf20Sopenharmony_ciextern void init_extra_mapping_wb(unsigned long phys, unsigned long size); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci#define gup_fast_permitted gup_fast_permitted 2628c2ecf20Sopenharmony_cistatic inline bool gup_fast_permitted(unsigned long start, unsigned long end) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci if (end >> __VIRTUAL_MASK_SHIFT) 2658c2ecf20Sopenharmony_ci return false; 2668c2ecf20Sopenharmony_ci return true; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci#include <asm/pgtable-invert.h> 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 2728c2ecf20Sopenharmony_ci#endif /* _ASM_X86_PGTABLE_64_H */ 273