162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_NOHASH_64_PGTABLE_H
362306a36Sopenharmony_ci#define _ASM_POWERPC_NOHASH_64_PGTABLE_H
462306a36Sopenharmony_ci/*
562306a36Sopenharmony_ci * This file contains the functions and defines necessary to modify and use
662306a36Sopenharmony_ci * the ppc64 non-hashed page table.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/sizes.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/nohash/64/pgtable-4k.h>
1262306a36Sopenharmony_ci#include <asm/barrier.h>
1362306a36Sopenharmony_ci#include <asm/asm-const.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Size of EA range mapped by our pagetables.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
1962306a36Sopenharmony_ci			    PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
2062306a36Sopenharmony_ci#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define PMD_CACHE_INDEX	PMD_INDEX_SIZE
2362306a36Sopenharmony_ci#define PUD_CACHE_INDEX PUD_INDEX_SIZE
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci * Define the address range of the kernel non-linear virtual area
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci#define KERN_VIRT_START ASM_CONST(0xc000100000000000)
2962306a36Sopenharmony_ci#define KERN_VIRT_SIZE	ASM_CONST(0x0000100000000000)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * The vmalloc space starts at the beginning of that region, and
3362306a36Sopenharmony_ci * occupies a quarter of it on Book3E
3462306a36Sopenharmony_ci * (we keep a quarter for the virtual memmap)
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ci#define VMALLOC_START	KERN_VIRT_START
3762306a36Sopenharmony_ci#define VMALLOC_SIZE	(KERN_VIRT_SIZE >> 2)
3862306a36Sopenharmony_ci#define VMALLOC_END	(VMALLOC_START + VMALLOC_SIZE)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * The third quarter of the kernel virtual space is used for IO mappings,
4262306a36Sopenharmony_ci * it's itself carved into the PIO region (ISA and PHB IO space) and
4362306a36Sopenharmony_ci * the ioremap space
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci *  ISA_IO_BASE = KERN_IO_START, 64K reserved area
4662306a36Sopenharmony_ci *  PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
4762306a36Sopenharmony_ci * IOREMAP_BASE = ISA_IO_BASE + 2G to KERN_IO_START + KERN_IO_SIZE
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci#define KERN_IO_START	(KERN_VIRT_START + (KERN_VIRT_SIZE >> 1))
5062306a36Sopenharmony_ci#define KERN_IO_SIZE	(KERN_VIRT_SIZE >> 2)
5162306a36Sopenharmony_ci#define FULL_IO_SIZE	0x80000000ul
5262306a36Sopenharmony_ci#define  ISA_IO_BASE	(KERN_IO_START)
5362306a36Sopenharmony_ci#define  ISA_IO_END	(KERN_IO_START + 0x10000ul)
5462306a36Sopenharmony_ci#define  PHB_IO_BASE	(ISA_IO_END)
5562306a36Sopenharmony_ci#define  PHB_IO_END	(KERN_IO_START + FULL_IO_SIZE)
5662306a36Sopenharmony_ci#define IOREMAP_BASE	(PHB_IO_END)
5762306a36Sopenharmony_ci#define IOREMAP_START	(ioremap_bot)
5862306a36Sopenharmony_ci#define IOREMAP_END	(KERN_IO_START + KERN_IO_SIZE - FIXADDR_SIZE)
5962306a36Sopenharmony_ci#define FIXADDR_SIZE	SZ_32M
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * Defines the address of the vmemap area, in its own region on
6362306a36Sopenharmony_ci * after the vmalloc space on Book3E
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci#define VMEMMAP_BASE		VMALLOC_END
6662306a36Sopenharmony_ci#define VMEMMAP_END		KERN_IO_START
6762306a36Sopenharmony_ci#define vmemmap			((struct page *)VMEMMAP_BASE)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Include the PTE bits definitions
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_ci#include <asm/nohash/pte-e500.h>
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define PTE_RPN_MASK	(~((1UL << PTE_RPN_SHIFT) - 1))
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * _PAGE_CHG_MASK masks of bits that are to be preserved across
7962306a36Sopenharmony_ci * pgprot changes.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci#define _PAGE_CHG_MASK	(PTE_RPN_MASK | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPECIAL)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define H_PAGE_4K_PFN 0
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#ifndef __ASSEMBLY__
8662306a36Sopenharmony_ci/* pte_clear moved to later in this file */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return __pte(pte_val(pte) | _PAGE_RW);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	return __pte(pte_val(pte) | _PAGE_DIRTY);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	return __pte(pte_val(pte) | _PAGE_ACCESSED);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	return __pte(pte_val(pte) & ~_PAGE_RW);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define PMD_BAD_BITS		(PTE_TABLE_SIZE-1)
10962306a36Sopenharmony_ci#define PUD_BAD_BITS		(PMD_TABLE_SIZE-1)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic inline void pmd_set(pmd_t *pmdp, unsigned long val)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	*pmdp = __pmd(val);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic inline void pmd_clear(pmd_t *pmdp)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	*pmdp = __pmd(0);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline pte_t pmd_pte(pmd_t pmd)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return __pte(pmd_val(pmd));
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define pmd_none(pmd)		(!pmd_val(pmd))
12762306a36Sopenharmony_ci#define	pmd_bad(pmd)		(!is_kernel_addr(pmd_val(pmd)) \
12862306a36Sopenharmony_ci				 || (pmd_val(pmd) & PMD_BAD_BITS))
12962306a36Sopenharmony_ci#define	pmd_present(pmd)	(!pmd_none(pmd))
13062306a36Sopenharmony_ci#define pmd_page_vaddr(pmd)	((const void *)(pmd_val(pmd) & ~PMD_MASKED_BITS))
13162306a36Sopenharmony_ciextern struct page *pmd_page(pmd_t pmd);
13262306a36Sopenharmony_ci#define pmd_pfn(pmd)		(page_to_pfn(pmd_page(pmd)))
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic inline void pud_set(pud_t *pudp, unsigned long val)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	*pudp = __pud(val);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline void pud_clear(pud_t *pudp)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	*pudp = __pud(0);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define pud_none(pud)		(!pud_val(pud))
14562306a36Sopenharmony_ci#define	pud_bad(pud)		(!is_kernel_addr(pud_val(pud)) \
14662306a36Sopenharmony_ci				 || (pud_val(pud) & PUD_BAD_BITS))
14762306a36Sopenharmony_ci#define pud_present(pud)	(pud_val(pud) != 0)
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return (pmd_t *)(pud_val(pud) & ~PUD_MASKED_BITS);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciextern struct page *pud_page(pud_t pud);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic inline pte_t pud_pte(pud_t pud)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return __pte(pud_val(pud));
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic inline pud_t pte_pud(pte_t pte)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return __pud(pte_val(pte));
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci#define pud_write(pud)		pte_write(pud_pte(pud))
16662306a36Sopenharmony_ci#define p4d_write(pgd)		pte_write(p4d_pte(p4d))
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic inline void p4d_set(p4d_t *p4dp, unsigned long val)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	*p4dp = __p4d(val);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Atomic PTE updates */
17462306a36Sopenharmony_cistatic inline unsigned long pte_update(struct mm_struct *mm,
17562306a36Sopenharmony_ci				       unsigned long addr,
17662306a36Sopenharmony_ci				       pte_t *ptep, unsigned long clr,
17762306a36Sopenharmony_ci				       unsigned long set,
17862306a36Sopenharmony_ci				       int huge)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	unsigned long old = pte_val(*ptep);
18162306a36Sopenharmony_ci	*ptep = __pte((old & ~clr) | set);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* huge pages use the old page table lock */
18462306a36Sopenharmony_ci	if (!huge)
18562306a36Sopenharmony_ci		assert_pte_locked(mm, addr);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return old;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline int pte_young(pte_t pte)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	return pte_val(pte) & _PAGE_ACCESSED;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic inline int __ptep_test_and_clear_young(struct mm_struct *mm,
19662306a36Sopenharmony_ci					      unsigned long addr, pte_t *ptep)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	unsigned long old;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (!pte_young(*ptep))
20162306a36Sopenharmony_ci		return 0;
20262306a36Sopenharmony_ci	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
20362306a36Sopenharmony_ci	return (old & _PAGE_ACCESSED) != 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
20662306a36Sopenharmony_ci#define ptep_test_and_clear_young(__vma, __addr, __ptep)		   \
20762306a36Sopenharmony_ci({									   \
20862306a36Sopenharmony_ci	int __r;							   \
20962306a36Sopenharmony_ci	__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
21062306a36Sopenharmony_ci	__r;								   \
21162306a36Sopenharmony_ci})
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_WRPROTECT
21462306a36Sopenharmony_cistatic inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
21562306a36Sopenharmony_ci				      pte_t *ptep)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if ((pte_val(*ptep) & _PAGE_RW) == 0)
21962306a36Sopenharmony_ci		return;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT
22562306a36Sopenharmony_cistatic inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
22662306a36Sopenharmony_ci					   unsigned long addr, pte_t *ptep)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	if ((pte_val(*ptep) & _PAGE_RW) == 0)
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
23562306a36Sopenharmony_ci#define ptep_clear_flush_young(__vma, __address, __ptep)		\
23662306a36Sopenharmony_ci({									\
23762306a36Sopenharmony_ci	int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
23862306a36Sopenharmony_ci						  __ptep);		\
23962306a36Sopenharmony_ci	__young;							\
24062306a36Sopenharmony_ci})
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
24362306a36Sopenharmony_cistatic inline pte_t ptep_get_and_clear(struct mm_struct *mm,
24462306a36Sopenharmony_ci				       unsigned long addr, pte_t *ptep)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
24762306a36Sopenharmony_ci	return __pte(old);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic inline void pte_clear(struct mm_struct *mm, unsigned long addr,
25162306a36Sopenharmony_ci			     pte_t * ptep)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	pte_update(mm, addr, ptep, ~0UL, 0, 0);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/* Set the dirty and/or accessed bits atomically in a linux PTE */
25862306a36Sopenharmony_cistatic inline void __ptep_set_access_flags(struct vm_area_struct *vma,
25962306a36Sopenharmony_ci					   pte_t *ptep, pte_t entry,
26062306a36Sopenharmony_ci					   unsigned long address,
26162306a36Sopenharmony_ci					   int psize)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	unsigned long bits = pte_val(entry) &
26462306a36Sopenharmony_ci		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	unsigned long old = pte_val(*ptep);
26762306a36Sopenharmony_ci	*ptep = __pte(old | bits);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	flush_tlb_page(vma, address);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci#define pte_ERROR(e) \
27362306a36Sopenharmony_ci	pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
27462306a36Sopenharmony_ci#define pmd_ERROR(e) \
27562306a36Sopenharmony_ci	pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
27662306a36Sopenharmony_ci#define pgd_ERROR(e) \
27762306a36Sopenharmony_ci	pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/*
28062306a36Sopenharmony_ci * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that
28162306a36Sopenharmony_ci * are !pte_none() && !pte_present().
28262306a36Sopenharmony_ci *
28362306a36Sopenharmony_ci * Format of swap PTEs:
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci *                         1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
28662306a36Sopenharmony_ci *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
28762306a36Sopenharmony_ci *   <-------------------------- offset ----------------------------
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci *   3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6
29062306a36Sopenharmony_ci *   2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
29162306a36Sopenharmony_ci *   --------------> <----------- zero ------------> E < type -> 0 0
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * E is the exclusive marker that is not stored in swap entries.
29462306a36Sopenharmony_ci */
29562306a36Sopenharmony_ci#define MAX_SWAPFILES_CHECK() do { \
29662306a36Sopenharmony_ci	BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS); \
29762306a36Sopenharmony_ci	} while (0)
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci#define SWP_TYPE_BITS 5
30062306a36Sopenharmony_ci#define __swp_type(x)		(((x).val >> 2) \
30162306a36Sopenharmony_ci				& ((1UL << SWP_TYPE_BITS) - 1))
30262306a36Sopenharmony_ci#define __swp_offset(x)		((x).val >> PTE_RPN_SHIFT)
30362306a36Sopenharmony_ci#define __swp_entry(type, offset)	((swp_entry_t) { \
30462306a36Sopenharmony_ci					(((type) & 0x1f) << 2) \
30562306a36Sopenharmony_ci					| ((offset) << PTE_RPN_SHIFT) })
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci#define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val((pte)) })
30862306a36Sopenharmony_ci#define __swp_entry_to_pte(x)		__pte((x).val)
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci/* We borrow MSB 56 (LSB 7) to store the exclusive marker in swap PTEs. */
31162306a36Sopenharmony_ci#define _PAGE_SWP_EXCLUSIVE	0x80
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciint map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot);
31462306a36Sopenharmony_civoid unmap_kernel_page(unsigned long va);
31562306a36Sopenharmony_ciextern int __meminit vmemmap_create_mapping(unsigned long start,
31662306a36Sopenharmony_ci					    unsigned long page_size,
31762306a36Sopenharmony_ci					    unsigned long phys);
31862306a36Sopenharmony_ciextern void vmemmap_remove_mapping(unsigned long start,
31962306a36Sopenharmony_ci				   unsigned long page_size);
32062306a36Sopenharmony_civoid __patch_exception(int exc, unsigned long addr);
32162306a36Sopenharmony_ci#define patch_exception(exc, name) do { \
32262306a36Sopenharmony_ci	extern unsigned int name; \
32362306a36Sopenharmony_ci	__patch_exception((exc), (unsigned long)&name); \
32462306a36Sopenharmony_ci} while (0)
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci#endif /* _ASM_POWERPC_NOHASH_64_PGTABLE_H */
329