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