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