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