162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ 362306a36Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <asm-generic/pgtable-nop4d.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 862306a36Sopenharmony_ci#include <linux/mmdebug.h> 962306a36Sopenharmony_ci#include <linux/bug.h> 1062306a36Sopenharmony_ci#include <linux/sizes.h> 1162306a36Sopenharmony_ci#endif 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Common bits between hash and Radix page table 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define _PAGE_EXEC 0x00001 /* execute permission */ 1862306a36Sopenharmony_ci#define _PAGE_WRITE 0x00002 /* write access allowed */ 1962306a36Sopenharmony_ci#define _PAGE_READ 0x00004 /* read access allowed */ 2062306a36Sopenharmony_ci#define _PAGE_RW (_PAGE_READ | _PAGE_WRITE) 2162306a36Sopenharmony_ci#define _PAGE_RWX (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC) 2262306a36Sopenharmony_ci#define _PAGE_PRIVILEGED 0x00008 /* kernel access only */ 2362306a36Sopenharmony_ci#define _PAGE_SAO 0x00010 /* Strong access order */ 2462306a36Sopenharmony_ci#define _PAGE_NON_IDEMPOTENT 0x00020 /* non idempotent memory */ 2562306a36Sopenharmony_ci#define _PAGE_TOLERANT 0x00030 /* tolerant memory, cache inhibited */ 2662306a36Sopenharmony_ci#define _PAGE_DIRTY 0x00080 /* C: page changed */ 2762306a36Sopenharmony_ci#define _PAGE_ACCESSED 0x00100 /* R: page referenced */ 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Software bits 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci#define _RPAGE_SW0 0x2000000000000000UL 3262306a36Sopenharmony_ci#define _RPAGE_SW1 0x00800 3362306a36Sopenharmony_ci#define _RPAGE_SW2 0x00400 3462306a36Sopenharmony_ci#define _RPAGE_SW3 0x00200 3562306a36Sopenharmony_ci#define _RPAGE_RSV1 0x00040UL 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define _RPAGE_PKEY_BIT4 0x1000000000000000UL 3862306a36Sopenharmony_ci#define _RPAGE_PKEY_BIT3 0x0800000000000000UL 3962306a36Sopenharmony_ci#define _RPAGE_PKEY_BIT2 0x0400000000000000UL 4062306a36Sopenharmony_ci#define _RPAGE_PKEY_BIT1 0x0200000000000000UL 4162306a36Sopenharmony_ci#define _RPAGE_PKEY_BIT0 0x0100000000000000UL 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define _PAGE_PTE 0x4000000000000000UL /* distinguishes PTEs from pointers */ 4462306a36Sopenharmony_ci#define _PAGE_PRESENT 0x8000000000000000UL /* pte contains a translation */ 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * We need to mark a pmd pte invalid while splitting. We can do that by clearing 4762306a36Sopenharmony_ci * the _PAGE_PRESENT bit. But then that will be taken as a swap pte. In order to 4862306a36Sopenharmony_ci * differentiate between two use a SW field when invalidating. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * We do that temporary invalidate for regular pte entry in ptep_set_access_flags 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * This is used only when _PAGE_PRESENT is cleared. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define _PAGE_INVALID _RPAGE_SW0 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Top and bottom bits of RPN which can be used by hash 5862306a36Sopenharmony_ci * translation mode, because we expect them to be zero 5962306a36Sopenharmony_ci * otherwise. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci#define _RPAGE_RPN0 0x01000 6262306a36Sopenharmony_ci#define _RPAGE_RPN1 0x02000 6362306a36Sopenharmony_ci#define _RPAGE_RPN43 0x0080000000000000UL 6462306a36Sopenharmony_ci#define _RPAGE_RPN42 0x0040000000000000UL 6562306a36Sopenharmony_ci#define _RPAGE_RPN41 0x0020000000000000UL 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* Max physical address bit as per radix table */ 6862306a36Sopenharmony_ci#define _RPAGE_PA_MAX 56 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Max physical address bit we will use for now. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * This is mostly a hardware limitation and for now Power9 has 7462306a36Sopenharmony_ci * a 51 bit limit. 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * This is different from the number of physical bit required to address 7762306a36Sopenharmony_ci * the last byte of memory. That is defined by MAX_PHYSMEM_BITS. 7862306a36Sopenharmony_ci * MAX_PHYSMEM_BITS is a linux limitation imposed by the maximum 7962306a36Sopenharmony_ci * number of sections we can support (SECTIONS_SHIFT). 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * This is different from Radix page table limitation above and 8262306a36Sopenharmony_ci * should always be less than that. The limit is done such that 8362306a36Sopenharmony_ci * we can overload the bits between _RPAGE_PA_MAX and _PAGE_PA_MAX 8462306a36Sopenharmony_ci * for hash linux page table specific bits. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * In order to be compatible with future hardware generations we keep 8762306a36Sopenharmony_ci * some offsets and limit this for now to 53 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci#define _PAGE_PA_MAX 53 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define _PAGE_SOFT_DIRTY _RPAGE_SW3 /* software: software dirty tracking */ 9262306a36Sopenharmony_ci#define _PAGE_SPECIAL _RPAGE_SW2 /* software: special page */ 9362306a36Sopenharmony_ci#define _PAGE_DEVMAP _RPAGE_SW1 /* software: ZONE_DEVICE page */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* 9662306a36Sopenharmony_ci * Drivers request for cache inhibited pte mapping using _PAGE_NO_CACHE 9762306a36Sopenharmony_ci * Instead of fixing all of them, add an alternate define which 9862306a36Sopenharmony_ci * maps CI pte mapping. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci#define _PAGE_NO_CACHE _PAGE_TOLERANT 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * We support _RPAGE_PA_MAX bit real address in pte. On the linux side 10362306a36Sopenharmony_ci * we are limited by _PAGE_PA_MAX. Clear everything above _PAGE_PA_MAX 10462306a36Sopenharmony_ci * and every thing below PAGE_SHIFT; 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci#define PTE_RPN_MASK (((1UL << _PAGE_PA_MAX) - 1) & (PAGE_MASK)) 10762306a36Sopenharmony_ci#define PTE_RPN_SHIFT PAGE_SHIFT 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * set of bits not changed in pmd_modify. Even though we have hash specific bits 11062306a36Sopenharmony_ci * in here, on radix we expect them to be zero. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \ 11362306a36Sopenharmony_ci _PAGE_ACCESSED | H_PAGE_THP_HUGE | _PAGE_PTE | \ 11462306a36Sopenharmony_ci _PAGE_SOFT_DIRTY | _PAGE_DEVMAP) 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * user access blocked by key 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci#define _PAGE_KERNEL_RW (_PAGE_PRIVILEGED | _PAGE_RW | _PAGE_DIRTY) 11962306a36Sopenharmony_ci#define _PAGE_KERNEL_RO (_PAGE_PRIVILEGED | _PAGE_READ) 12062306a36Sopenharmony_ci#define _PAGE_KERNEL_ROX (_PAGE_PRIVILEGED | _PAGE_READ | _PAGE_EXEC) 12162306a36Sopenharmony_ci#define _PAGE_KERNEL_RWX (_PAGE_PRIVILEGED | _PAGE_DIRTY | _PAGE_RW | _PAGE_EXEC) 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * _PAGE_CHG_MASK masks of bits that are to be preserved across 12462306a36Sopenharmony_ci * pgprot changes 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci#define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \ 12762306a36Sopenharmony_ci _PAGE_ACCESSED | _PAGE_SPECIAL | _PAGE_PTE | \ 12862306a36Sopenharmony_ci _PAGE_SOFT_DIRTY | _PAGE_DEVMAP) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * We define 2 sets of base prot bits, one for basic pages (ie, 13262306a36Sopenharmony_ci * cacheable kernel and user pages) and one for non cacheable 13362306a36Sopenharmony_ci * pages. We always set _PAGE_COHERENT when SMP is enabled or 13462306a36Sopenharmony_ci * the processor might need it for DMA coherency. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci#define _PAGE_BASE_NC (_PAGE_PRESENT | _PAGE_ACCESSED) 13762306a36Sopenharmony_ci#define _PAGE_BASE (_PAGE_BASE_NC) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* Permission masks used to generate the __P and __S table, 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Note:__pgprot is defined in arch/powerpc/include/asm/page.h 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * Write permissions imply read permissions for now (we could make write-only 14462306a36Sopenharmony_ci * pages on BookE but we don't bother for now). Execute permission control is 14562306a36Sopenharmony_ci * possible on platforms that define _PAGE_EXEC 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci#define PAGE_NONE __pgprot(_PAGE_BASE | _PAGE_PRIVILEGED) 14862306a36Sopenharmony_ci#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW) 14962306a36Sopenharmony_ci#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_EXEC) 15062306a36Sopenharmony_ci#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_READ) 15162306a36Sopenharmony_ci#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC) 15262306a36Sopenharmony_ci#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_READ) 15362306a36Sopenharmony_ci#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC) 15462306a36Sopenharmony_ci/* Radix only, Hash uses PAGE_READONLY_X + execute-only pkey instead */ 15562306a36Sopenharmony_ci#define PAGE_EXECONLY __pgprot(_PAGE_BASE | _PAGE_EXEC) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* Permission masks used for kernel mappings */ 15862306a36Sopenharmony_ci#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW) 15962306a36Sopenharmony_ci#define PAGE_KERNEL_NC __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_TOLERANT) 16062306a36Sopenharmony_ci#define PAGE_KERNEL_NCG __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | _PAGE_NON_IDEMPOTENT) 16162306a36Sopenharmony_ci#define PAGE_KERNEL_X __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX) 16262306a36Sopenharmony_ci#define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO) 16362306a36Sopenharmony_ci#define PAGE_KERNEL_ROX __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * page table defines 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ciextern unsigned long __pte_index_size; 17062306a36Sopenharmony_ciextern unsigned long __pmd_index_size; 17162306a36Sopenharmony_ciextern unsigned long __pud_index_size; 17262306a36Sopenharmony_ciextern unsigned long __pgd_index_size; 17362306a36Sopenharmony_ciextern unsigned long __pud_cache_index; 17462306a36Sopenharmony_ci#define PTE_INDEX_SIZE __pte_index_size 17562306a36Sopenharmony_ci#define PMD_INDEX_SIZE __pmd_index_size 17662306a36Sopenharmony_ci#define PUD_INDEX_SIZE __pud_index_size 17762306a36Sopenharmony_ci#define PGD_INDEX_SIZE __pgd_index_size 17862306a36Sopenharmony_ci/* pmd table use page table fragments */ 17962306a36Sopenharmony_ci#define PMD_CACHE_INDEX 0 18062306a36Sopenharmony_ci#define PUD_CACHE_INDEX __pud_cache_index 18162306a36Sopenharmony_ci/* 18262306a36Sopenharmony_ci * Because of use of pte fragments and THP, size of page table 18362306a36Sopenharmony_ci * are not always derived out of index size above. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ciextern unsigned long __pte_table_size; 18662306a36Sopenharmony_ciextern unsigned long __pmd_table_size; 18762306a36Sopenharmony_ciextern unsigned long __pud_table_size; 18862306a36Sopenharmony_ciextern unsigned long __pgd_table_size; 18962306a36Sopenharmony_ci#define PTE_TABLE_SIZE __pte_table_size 19062306a36Sopenharmony_ci#define PMD_TABLE_SIZE __pmd_table_size 19162306a36Sopenharmony_ci#define PUD_TABLE_SIZE __pud_table_size 19262306a36Sopenharmony_ci#define PGD_TABLE_SIZE __pgd_table_size 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciextern unsigned long __pmd_val_bits; 19562306a36Sopenharmony_ciextern unsigned long __pud_val_bits; 19662306a36Sopenharmony_ciextern unsigned long __pgd_val_bits; 19762306a36Sopenharmony_ci#define PMD_VAL_BITS __pmd_val_bits 19862306a36Sopenharmony_ci#define PUD_VAL_BITS __pud_val_bits 19962306a36Sopenharmony_ci#define PGD_VAL_BITS __pgd_val_bits 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciextern unsigned long __pte_frag_nr; 20262306a36Sopenharmony_ci#define PTE_FRAG_NR __pte_frag_nr 20362306a36Sopenharmony_ciextern unsigned long __pte_frag_size_shift; 20462306a36Sopenharmony_ci#define PTE_FRAG_SIZE_SHIFT __pte_frag_size_shift 20562306a36Sopenharmony_ci#define PTE_FRAG_SIZE (1UL << PTE_FRAG_SIZE_SHIFT) 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciextern unsigned long __pmd_frag_nr; 20862306a36Sopenharmony_ci#define PMD_FRAG_NR __pmd_frag_nr 20962306a36Sopenharmony_ciextern unsigned long __pmd_frag_size_shift; 21062306a36Sopenharmony_ci#define PMD_FRAG_SIZE_SHIFT __pmd_frag_size_shift 21162306a36Sopenharmony_ci#define PMD_FRAG_SIZE (1UL << PMD_FRAG_SIZE_SHIFT) 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) 21462306a36Sopenharmony_ci#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) 21562306a36Sopenharmony_ci#define PTRS_PER_PUD (1 << PUD_INDEX_SIZE) 21662306a36Sopenharmony_ci#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci#define MAX_PTRS_PER_PTE ((H_PTRS_PER_PTE > R_PTRS_PER_PTE) ? H_PTRS_PER_PTE : R_PTRS_PER_PTE) 21962306a36Sopenharmony_ci#define MAX_PTRS_PER_PMD ((H_PTRS_PER_PMD > R_PTRS_PER_PMD) ? H_PTRS_PER_PMD : R_PTRS_PER_PMD) 22062306a36Sopenharmony_ci#define MAX_PTRS_PER_PUD ((H_PTRS_PER_PUD > R_PTRS_PER_PUD) ? H_PTRS_PER_PUD : R_PTRS_PER_PUD) 22162306a36Sopenharmony_ci#define MAX_PTRS_PER_PGD (1 << (H_PGD_INDEX_SIZE > RADIX_PGD_INDEX_SIZE ? \ 22262306a36Sopenharmony_ci H_PGD_INDEX_SIZE : RADIX_PGD_INDEX_SIZE)) 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* PMD_SHIFT determines what a second-level page table entry can map */ 22562306a36Sopenharmony_ci#define PMD_SHIFT (PAGE_SHIFT + PTE_INDEX_SIZE) 22662306a36Sopenharmony_ci#define PMD_SIZE (1UL << PMD_SHIFT) 22762306a36Sopenharmony_ci#define PMD_MASK (~(PMD_SIZE-1)) 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* PUD_SHIFT determines what a third-level page table entry can map */ 23062306a36Sopenharmony_ci#define PUD_SHIFT (PMD_SHIFT + PMD_INDEX_SIZE) 23162306a36Sopenharmony_ci#define PUD_SIZE (1UL << PUD_SHIFT) 23262306a36Sopenharmony_ci#define PUD_MASK (~(PUD_SIZE-1)) 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* PGDIR_SHIFT determines what a fourth-level page table entry can map */ 23562306a36Sopenharmony_ci#define PGDIR_SHIFT (PUD_SHIFT + PUD_INDEX_SIZE) 23662306a36Sopenharmony_ci#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 23762306a36Sopenharmony_ci#define PGDIR_MASK (~(PGDIR_SIZE-1)) 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* Bits to mask out from a PMD to get to the PTE page */ 24062306a36Sopenharmony_ci#define PMD_MASKED_BITS 0xc0000000000000ffUL 24162306a36Sopenharmony_ci/* Bits to mask out from a PUD to get to the PMD page */ 24262306a36Sopenharmony_ci#define PUD_MASKED_BITS 0xc0000000000000ffUL 24362306a36Sopenharmony_ci/* Bits to mask out from a PGD to get to the PUD page */ 24462306a36Sopenharmony_ci#define P4D_MASKED_BITS 0xc0000000000000ffUL 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci * Used as an indicator for rcu callback functions 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cienum pgtable_index { 25062306a36Sopenharmony_ci PTE_INDEX = 0, 25162306a36Sopenharmony_ci PMD_INDEX, 25262306a36Sopenharmony_ci PUD_INDEX, 25362306a36Sopenharmony_ci PGD_INDEX, 25462306a36Sopenharmony_ci /* 25562306a36Sopenharmony_ci * Below are used with 4k page size and hugetlb 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci HTLB_16M_INDEX, 25862306a36Sopenharmony_ci HTLB_16G_INDEX, 25962306a36Sopenharmony_ci}; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ciextern unsigned long __vmalloc_start; 26262306a36Sopenharmony_ciextern unsigned long __vmalloc_end; 26362306a36Sopenharmony_ci#define VMALLOC_START __vmalloc_start 26462306a36Sopenharmony_ci#define VMALLOC_END __vmalloc_end 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic inline unsigned int ioremap_max_order(void) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci if (radix_enabled()) 26962306a36Sopenharmony_ci return PUD_SHIFT; 27062306a36Sopenharmony_ci return 7 + PAGE_SHIFT; /* default from linux/vmalloc.h */ 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci#define IOREMAP_MAX_ORDER ioremap_max_order() 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciextern unsigned long __kernel_virt_start; 27562306a36Sopenharmony_ciextern unsigned long __kernel_io_start; 27662306a36Sopenharmony_ciextern unsigned long __kernel_io_end; 27762306a36Sopenharmony_ci#define KERN_VIRT_START __kernel_virt_start 27862306a36Sopenharmony_ci#define KERN_IO_START __kernel_io_start 27962306a36Sopenharmony_ci#define KERN_IO_END __kernel_io_end 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ciextern struct page *vmemmap; 28262306a36Sopenharmony_ciextern unsigned long pci_io_base; 28362306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#include <asm/book3s/64/hash.h> 28662306a36Sopenharmony_ci#include <asm/book3s/64/radix.h> 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#if H_MAX_PHYSMEM_BITS > R_MAX_PHYSMEM_BITS 28962306a36Sopenharmony_ci#define MAX_PHYSMEM_BITS H_MAX_PHYSMEM_BITS 29062306a36Sopenharmony_ci#else 29162306a36Sopenharmony_ci#define MAX_PHYSMEM_BITS R_MAX_PHYSMEM_BITS 29262306a36Sopenharmony_ci#endif 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 29662306a36Sopenharmony_ci#include <asm/book3s/64/pgtable-64k.h> 29762306a36Sopenharmony_ci#else 29862306a36Sopenharmony_ci#include <asm/book3s/64/pgtable-4k.h> 29962306a36Sopenharmony_ci#endif 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci#include <asm/barrier.h> 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * IO space itself carved into the PIO region (ISA and PHB IO space) and 30462306a36Sopenharmony_ci * the ioremap space 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * ISA_IO_BASE = KERN_IO_START, 64K reserved area 30762306a36Sopenharmony_ci * PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces 30862306a36Sopenharmony_ci * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci#define FULL_IO_SIZE 0x80000000ul 31162306a36Sopenharmony_ci#define ISA_IO_BASE (KERN_IO_START) 31262306a36Sopenharmony_ci#define ISA_IO_END (KERN_IO_START + 0x10000ul) 31362306a36Sopenharmony_ci#define PHB_IO_BASE (ISA_IO_END) 31462306a36Sopenharmony_ci#define PHB_IO_END (KERN_IO_START + FULL_IO_SIZE) 31562306a36Sopenharmony_ci#define IOREMAP_BASE (PHB_IO_END) 31662306a36Sopenharmony_ci#define IOREMAP_START (ioremap_bot) 31762306a36Sopenharmony_ci#define IOREMAP_END (KERN_IO_END - FIXADDR_SIZE) 31862306a36Sopenharmony_ci#define FIXADDR_SIZE SZ_32M 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* 32362306a36Sopenharmony_ci * This is the default implementation of various PTE accessors, it's 32462306a36Sopenharmony_ci * used in all cases except Book3S with 64K pages where we have a 32562306a36Sopenharmony_ci * concept of sub-pages 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci#ifndef __real_pte 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#define __real_pte(e, p, o) ((real_pte_t){(e)}) 33062306a36Sopenharmony_ci#define __rpte_to_pte(r) ((r).pte) 33162306a36Sopenharmony_ci#define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >> H_PAGE_F_GIX_SHIFT) 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \ 33462306a36Sopenharmony_ci do { \ 33562306a36Sopenharmony_ci index = 0; \ 33662306a36Sopenharmony_ci shift = mmu_psize_defs[psize].shift; \ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci#define pte_iterate_hashed_end() } while(0) 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* 34162306a36Sopenharmony_ci * We expect this to be called only for user addresses or kernel virtual 34262306a36Sopenharmony_ci * addresses other than the linear mapping. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci#endif /* __real_pte */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic inline unsigned long pte_update(struct mm_struct *mm, unsigned long addr, 34962306a36Sopenharmony_ci pte_t *ptep, unsigned long clr, 35062306a36Sopenharmony_ci unsigned long set, int huge) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci if (radix_enabled()) 35362306a36Sopenharmony_ci return radix__pte_update(mm, addr, ptep, clr, set, huge); 35462306a36Sopenharmony_ci return hash__pte_update(mm, addr, ptep, clr, set, huge); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci/* 35762306a36Sopenharmony_ci * For hash even if we have _PAGE_ACCESSED = 0, we do a pte_update. 35862306a36Sopenharmony_ci * We currently remove entries from the hashtable regardless of whether 35962306a36Sopenharmony_ci * the entry was young or dirty. 36062306a36Sopenharmony_ci * 36162306a36Sopenharmony_ci * We should be more intelligent about this but for the moment we override 36262306a36Sopenharmony_ci * these functions and force a tlb flush unconditionally 36362306a36Sopenharmony_ci * For radix: H_PAGE_HASHPTE should be zero. Hence we can use the same 36462306a36Sopenharmony_ci * function for both hash and radix. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_cistatic inline int __ptep_test_and_clear_young(struct mm_struct *mm, 36762306a36Sopenharmony_ci unsigned long addr, pte_t *ptep) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci unsigned long old; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if ((pte_raw(*ptep) & cpu_to_be64(_PAGE_ACCESSED | H_PAGE_HASHPTE)) == 0) 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0); 37462306a36Sopenharmony_ci return (old & _PAGE_ACCESSED) != 0; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG 37862306a36Sopenharmony_ci#define ptep_test_and_clear_young(__vma, __addr, __ptep) \ 37962306a36Sopenharmony_ci({ \ 38062306a36Sopenharmony_ci __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \ 38162306a36Sopenharmony_ci}) 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* 38462306a36Sopenharmony_ci * On Book3S CPUs, clearing the accessed bit without a TLB flush 38562306a36Sopenharmony_ci * doesn't cause data corruption. [ It could cause incorrect 38662306a36Sopenharmony_ci * page aging and the (mistaken) reclaim of hot pages, but the 38762306a36Sopenharmony_ci * chance of that should be relatively low. ] 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * So as a performance optimization don't flush the TLB when 39062306a36Sopenharmony_ci * clearing the accessed bit, it will eventually be flushed by 39162306a36Sopenharmony_ci * a context switch or a VM operation anyway. [ In the rare 39262306a36Sopenharmony_ci * event of it not getting flushed for a long time the delay 39362306a36Sopenharmony_ci * shouldn't really matter because there's no real memory 39462306a36Sopenharmony_ci * pressure for swapout to react to. ] 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * Note: this optimisation also exists in pte_needs_flush() and 39762306a36Sopenharmony_ci * huge_pmd_needs_flush(). 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH 40062306a36Sopenharmony_ci#define ptep_clear_flush_young ptep_test_and_clear_young 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH 40362306a36Sopenharmony_ci#define pmdp_clear_flush_young pmdp_test_and_clear_young 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic inline int pte_write(pte_t pte) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_WRITE)); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic inline int pte_read(pte_t pte) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_READ)); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_WRPROTECT 41662306a36Sopenharmony_cistatic inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, 41762306a36Sopenharmony_ci pte_t *ptep) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci if (pte_write(*ptep)) 42062306a36Sopenharmony_ci pte_update(mm, addr, ptep, _PAGE_WRITE, 0, 0); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT 42462306a36Sopenharmony_cistatic inline void huge_ptep_set_wrprotect(struct mm_struct *mm, 42562306a36Sopenharmony_ci unsigned long addr, pte_t *ptep) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci if (pte_write(*ptep)) 42862306a36Sopenharmony_ci pte_update(mm, addr, ptep, _PAGE_WRITE, 0, 1); 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR 43262306a36Sopenharmony_cistatic inline pte_t ptep_get_and_clear(struct mm_struct *mm, 43362306a36Sopenharmony_ci unsigned long addr, pte_t *ptep) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0); 43662306a36Sopenharmony_ci return __pte(old); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL 44062306a36Sopenharmony_cistatic inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, 44162306a36Sopenharmony_ci unsigned long addr, 44262306a36Sopenharmony_ci pte_t *ptep, int full) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci if (full && radix_enabled()) { 44562306a36Sopenharmony_ci /* 44662306a36Sopenharmony_ci * We know that this is a full mm pte clear and 44762306a36Sopenharmony_ci * hence can be sure there is no parallel set_pte. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci return radix__ptep_get_and_clear_full(mm, addr, ptep, full); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci return ptep_get_and_clear(mm, addr, ptep); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic inline void pte_clear(struct mm_struct *mm, unsigned long addr, 45662306a36Sopenharmony_ci pte_t * ptep) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci pte_update(mm, addr, ptep, ~0UL, 0, 0); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic inline int pte_dirty(pte_t pte) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_DIRTY)); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic inline int pte_young(pte_t pte) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_ACCESSED)); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic inline int pte_special(pte_t pte) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_SPECIAL)); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic inline bool pte_exec(pte_t pte) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_EXEC)); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY 48362306a36Sopenharmony_cistatic inline bool pte_soft_dirty(pte_t pte) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_SOFT_DIRTY)); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic inline pte_t pte_mksoft_dirty(pte_t pte) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SOFT_DIRTY)); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic inline pte_t pte_clear_soft_dirty(pte_t pte) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_SOFT_DIRTY)); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING 50062306a36Sopenharmony_cistatic inline int pte_protnone(pte_t pte) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci return (pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE | _PAGE_RWX)) == 50362306a36Sopenharmony_ci cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci#endif /* CONFIG_NUMA_BALANCING */ 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic inline bool pte_hw_valid(pte_t pte) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci return (pte_raw(pte) & cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE)) == 51062306a36Sopenharmony_ci cpu_to_be64(_PAGE_PRESENT | _PAGE_PTE); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic inline int pte_present(pte_t pte) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci /* 51662306a36Sopenharmony_ci * A pte is considerent present if _PAGE_PRESENT is set. 51762306a36Sopenharmony_ci * We also need to consider the pte present which is marked 51862306a36Sopenharmony_ci * invalid during ptep_set_access_flags. Hence we look for _PAGE_INVALID 51962306a36Sopenharmony_ci * if we find _PAGE_PRESENT cleared. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (pte_hw_valid(pte)) 52362306a36Sopenharmony_ci return true; 52462306a36Sopenharmony_ci return (pte_raw(pte) & cpu_to_be64(_PAGE_INVALID | _PAGE_PTE)) == 52562306a36Sopenharmony_ci cpu_to_be64(_PAGE_INVALID | _PAGE_PTE); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci#ifdef CONFIG_PPC_MEM_KEYS 52962306a36Sopenharmony_ciextern bool arch_pte_access_permitted(u64 pte, bool write, bool execute); 53062306a36Sopenharmony_ci#else 53162306a36Sopenharmony_cistatic inline bool arch_pte_access_permitted(u64 pte, bool write, bool execute) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci return true; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci#endif /* CONFIG_PPC_MEM_KEYS */ 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic inline bool pte_user(pte_t pte) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci return !(pte_raw(pte) & cpu_to_be64(_PAGE_PRIVILEGED)); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci#define pte_access_permitted pte_access_permitted 54362306a36Sopenharmony_cistatic inline bool pte_access_permitted(pte_t pte, bool write) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci /* 54662306a36Sopenharmony_ci * _PAGE_READ is needed for any access and will be 54762306a36Sopenharmony_ci * cleared for PROT_NONE 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte)) 55062306a36Sopenharmony_ci return false; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (write && !pte_write(pte)) 55362306a36Sopenharmony_ci return false; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return arch_pte_access_permitted(pte_val(pte), write, 0); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/* 55962306a36Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry, 56062306a36Sopenharmony_ci * and a page entry and page directory to the page they refer to. 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * Even if PTEs can be unsigned long long, a PFN is always an unsigned 56362306a36Sopenharmony_ci * long for now. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci VM_BUG_ON(pfn >> (64 - PAGE_SHIFT)); 56862306a36Sopenharmony_ci VM_BUG_ON((pfn << PAGE_SHIFT) & ~PTE_RPN_MASK); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return __pte(((pte_basic_t)pfn << PAGE_SHIFT) | pgprot_val(pgprot) | _PAGE_PTE); 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/* Generic modifiers for PTE bits */ 57462306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_WRITE)); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic inline pte_t pte_exprotect(pte_t pte) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_EXEC)); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_DIRTY)); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_ACCESSED)); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic inline pte_t pte_mkexec(pte_t pte) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_EXEC)); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci /* 60262306a36Sopenharmony_ci * write implies read, hence set both 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_RW)); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_DIRTY | _PAGE_SOFT_DIRTY)); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_ACCESSED)); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SPECIAL)); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic inline pte_t pte_mkhuge(pte_t pte) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci return pte; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic inline pte_t pte_mkdevmap(pte_t pte) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SPECIAL | _PAGE_DEVMAP)); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic inline pte_t pte_mkprivileged(pte_t pte) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_PRIVILEGED)); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic inline pte_t pte_mkuser(pte_t pte) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_PRIVILEGED)); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci/* 64362306a36Sopenharmony_ci * This is potentially called with a pmd as the argument, in which case it's not 64462306a36Sopenharmony_ci * safe to check _PAGE_DEVMAP unless we also confirm that _PAGE_PTE is set. 64562306a36Sopenharmony_ci * That's because the bit we use for _PAGE_DEVMAP is not reserved for software 64662306a36Sopenharmony_ci * use in page directory entries (ie. non-ptes). 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cistatic inline int pte_devmap(pte_t pte) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci u64 mask = cpu_to_be64(_PAGE_DEVMAP | _PAGE_PTE); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return (pte_raw(pte) & mask) == mask; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci /* FIXME!! check whether this need to be a conditional */ 65862306a36Sopenharmony_ci return __pte_raw((pte_raw(pte) & cpu_to_be64(_PAGE_CHG_MASK)) | 65962306a36Sopenharmony_ci cpu_to_be64(pgprot_val(newprot))); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* Encode and de-code a swap entry */ 66362306a36Sopenharmony_ci#define MAX_SWAPFILES_CHECK() do { \ 66462306a36Sopenharmony_ci BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS); \ 66562306a36Sopenharmony_ci /* \ 66662306a36Sopenharmony_ci * Don't have overlapping bits with _PAGE_HPTEFLAGS \ 66762306a36Sopenharmony_ci * We filter HPTEFLAGS on set_pte. \ 66862306a36Sopenharmony_ci */ \ 66962306a36Sopenharmony_ci BUILD_BUG_ON(_PAGE_HPTEFLAGS & SWP_TYPE_MASK); \ 67062306a36Sopenharmony_ci BUILD_BUG_ON(_PAGE_HPTEFLAGS & _PAGE_SWP_SOFT_DIRTY); \ 67162306a36Sopenharmony_ci BUILD_BUG_ON(_PAGE_HPTEFLAGS & _PAGE_SWP_EXCLUSIVE); \ 67262306a36Sopenharmony_ci } while (0) 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci#define SWP_TYPE_BITS 5 67562306a36Sopenharmony_ci#define SWP_TYPE_MASK ((1UL << SWP_TYPE_BITS) - 1) 67662306a36Sopenharmony_ci#define __swp_type(x) ((x).val & SWP_TYPE_MASK) 67762306a36Sopenharmony_ci#define __swp_offset(x) (((x).val & PTE_RPN_MASK) >> PAGE_SHIFT) 67862306a36Sopenharmony_ci#define __swp_entry(type, offset) ((swp_entry_t) { \ 67962306a36Sopenharmony_ci (type) | (((offset) << PAGE_SHIFT) & PTE_RPN_MASK)}) 68062306a36Sopenharmony_ci/* 68162306a36Sopenharmony_ci * swp_entry_t must be independent of pte bits. We build a swp_entry_t from 68262306a36Sopenharmony_ci * swap type and offset we get from swap and convert that to pte to find a 68362306a36Sopenharmony_ci * matching pte in linux page table. 68462306a36Sopenharmony_ci * Clear bits not found in swap entries here. 68562306a36Sopenharmony_ci */ 68662306a36Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) & ~_PAGE_PTE }) 68762306a36Sopenharmony_ci#define __swp_entry_to_pte(x) __pte((x).val | _PAGE_PTE) 68862306a36Sopenharmony_ci#define __pmd_to_swp_entry(pmd) (__pte_to_swp_entry(pmd_pte(pmd))) 68962306a36Sopenharmony_ci#define __swp_entry_to_pmd(x) (pte_pmd(__swp_entry_to_pte(x))) 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci#ifdef CONFIG_MEM_SOFT_DIRTY 69262306a36Sopenharmony_ci#define _PAGE_SWP_SOFT_DIRTY _PAGE_SOFT_DIRTY 69362306a36Sopenharmony_ci#else 69462306a36Sopenharmony_ci#define _PAGE_SWP_SOFT_DIRTY 0UL 69562306a36Sopenharmony_ci#endif /* CONFIG_MEM_SOFT_DIRTY */ 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci#define _PAGE_SWP_EXCLUSIVE _PAGE_NON_IDEMPOTENT 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY 70062306a36Sopenharmony_cistatic inline pte_t pte_swp_mksoft_dirty(pte_t pte) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SWP_SOFT_DIRTY)); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic inline bool pte_swp_soft_dirty(pte_t pte) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_SWP_SOFT_DIRTY)); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_soft_dirty(pte_t pte) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_SWP_SOFT_DIRTY)); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic inline pte_t pte_swp_mkexclusive(pte_t pte) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_SWP_EXCLUSIVE)); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic inline int pte_swp_exclusive(pte_t pte) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci return !!(pte_raw(pte) & cpu_to_be64(_PAGE_SWP_EXCLUSIVE)); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_exclusive(pte_t pte) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci return __pte_raw(pte_raw(pte) & cpu_to_be64(~_PAGE_SWP_EXCLUSIVE)); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic inline bool check_pte_access(unsigned long access, unsigned long ptev) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci /* 73462306a36Sopenharmony_ci * This check for _PAGE_RWX and _PAGE_PRESENT bits 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci if (access & ~ptev) 73762306a36Sopenharmony_ci return false; 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * This check for access to privilege space 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci if ((access & _PAGE_PRIVILEGED) != (ptev & _PAGE_PRIVILEGED)) 74262306a36Sopenharmony_ci return false; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return true; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci/* 74762306a36Sopenharmony_ci * Generic functions with hash/radix callbacks 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic inline void __ptep_set_access_flags(struct vm_area_struct *vma, 75162306a36Sopenharmony_ci pte_t *ptep, pte_t entry, 75262306a36Sopenharmony_ci unsigned long address, 75362306a36Sopenharmony_ci int psize) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci if (radix_enabled()) 75662306a36Sopenharmony_ci return radix__ptep_set_access_flags(vma, ptep, entry, 75762306a36Sopenharmony_ci address, psize); 75862306a36Sopenharmony_ci return hash__ptep_set_access_flags(ptep, entry); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_SAME 76262306a36Sopenharmony_cistatic inline int pte_same(pte_t pte_a, pte_t pte_b) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci if (radix_enabled()) 76562306a36Sopenharmony_ci return radix__pte_same(pte_a, pte_b); 76662306a36Sopenharmony_ci return hash__pte_same(pte_a, pte_b); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic inline int pte_none(pte_t pte) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci if (radix_enabled()) 77262306a36Sopenharmony_ci return radix__pte_none(pte); 77362306a36Sopenharmony_ci return hash__pte_none(pte); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, 77762306a36Sopenharmony_ci pte_t *ptep, pte_t pte, int percpu) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci VM_WARN_ON(!(pte_raw(pte) & cpu_to_be64(_PAGE_PTE))); 78162306a36Sopenharmony_ci /* 78262306a36Sopenharmony_ci * Keep the _PAGE_PTE added till we are sure we handle _PAGE_PTE 78362306a36Sopenharmony_ci * in all the callers. 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_ci pte = __pte_raw(pte_raw(pte) | cpu_to_be64(_PAGE_PTE)); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (radix_enabled()) 78862306a36Sopenharmony_ci return radix__set_pte_at(mm, addr, ptep, pte, percpu); 78962306a36Sopenharmony_ci return hash__set_pte_at(mm, addr, ptep, pte, percpu); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci#define _PAGE_CACHE_CTL (_PAGE_SAO | _PAGE_NON_IDEMPOTENT | _PAGE_TOLERANT) 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci#define pgprot_noncached pgprot_noncached 79562306a36Sopenharmony_cistatic inline pgprot_t pgprot_noncached(pgprot_t prot) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | 79862306a36Sopenharmony_ci _PAGE_NON_IDEMPOTENT); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci#define pgprot_noncached_wc pgprot_noncached_wc 80262306a36Sopenharmony_cistatic inline pgprot_t pgprot_noncached_wc(pgprot_t prot) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | 80562306a36Sopenharmony_ci _PAGE_TOLERANT); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci#define pgprot_cached pgprot_cached 80962306a36Sopenharmony_cistatic inline pgprot_t pgprot_cached(pgprot_t prot) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci return __pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL)); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci#define pgprot_writecombine pgprot_writecombine 81562306a36Sopenharmony_cistatic inline pgprot_t pgprot_writecombine(pgprot_t prot) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci return pgprot_noncached_wc(prot); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci/* 82062306a36Sopenharmony_ci * check a pte mapping have cache inhibited property 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_cistatic inline bool pte_ci(pte_t pte) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci __be64 pte_v = pte_raw(pte); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (((pte_v & cpu_to_be64(_PAGE_CACHE_CTL)) == cpu_to_be64(_PAGE_TOLERANT)) || 82762306a36Sopenharmony_ci ((pte_v & cpu_to_be64(_PAGE_CACHE_CTL)) == cpu_to_be64(_PAGE_NON_IDEMPOTENT))) 82862306a36Sopenharmony_ci return true; 82962306a36Sopenharmony_ci return false; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic inline void pmd_clear(pmd_t *pmdp) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_VM) && !radix_enabled()) { 83562306a36Sopenharmony_ci /* 83662306a36Sopenharmony_ci * Don't use this if we can possibly have a hash page table 83762306a36Sopenharmony_ci * entry mapping this. 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci WARN_ON((pmd_val(*pmdp) & (H_PAGE_HASHPTE | _PAGE_PTE)) == (H_PAGE_HASHPTE | _PAGE_PTE)); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci *pmdp = __pmd(0); 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic inline int pmd_none(pmd_t pmd) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci return !pmd_raw(pmd); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic inline int pmd_present(pmd_t pmd) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci /* 85262306a36Sopenharmony_ci * A pmd is considerent present if _PAGE_PRESENT is set. 85362306a36Sopenharmony_ci * We also need to consider the pmd present which is marked 85462306a36Sopenharmony_ci * invalid during a split. Hence we look for _PAGE_INVALID 85562306a36Sopenharmony_ci * if we find _PAGE_PRESENT cleared. 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_ci if (pmd_raw(pmd) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID)) 85862306a36Sopenharmony_ci return true; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return false; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic inline int pmd_is_serializing(pmd_t pmd) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci /* 86662306a36Sopenharmony_ci * If the pmd is undergoing a split, the _PAGE_PRESENT bit is clear 86762306a36Sopenharmony_ci * and _PAGE_INVALID is set (see pmd_present, pmdp_invalidate). 86862306a36Sopenharmony_ci * 86962306a36Sopenharmony_ci * This condition may also occur when flushing a pmd while flushing 87062306a36Sopenharmony_ci * it (see ptep_modify_prot_start), so callers must ensure this 87162306a36Sopenharmony_ci * case is fine as well. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_ci if ((pmd_raw(pmd) & cpu_to_be64(_PAGE_PRESENT | _PAGE_INVALID)) == 87462306a36Sopenharmony_ci cpu_to_be64(_PAGE_INVALID)) 87562306a36Sopenharmony_ci return true; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return false; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic inline int pmd_bad(pmd_t pmd) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci if (radix_enabled()) 88362306a36Sopenharmony_ci return radix__pmd_bad(pmd); 88462306a36Sopenharmony_ci return hash__pmd_bad(pmd); 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic inline void pud_clear(pud_t *pudp) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_VM) && !radix_enabled()) { 89062306a36Sopenharmony_ci /* 89162306a36Sopenharmony_ci * Don't use this if we can possibly have a hash page table 89262306a36Sopenharmony_ci * entry mapping this. 89362306a36Sopenharmony_ci */ 89462306a36Sopenharmony_ci WARN_ON((pud_val(*pudp) & (H_PAGE_HASHPTE | _PAGE_PTE)) == (H_PAGE_HASHPTE | _PAGE_PTE)); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci *pudp = __pud(0); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic inline int pud_none(pud_t pud) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci return !pud_raw(pud); 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic inline int pud_present(pud_t pud) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PRESENT)); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ciextern struct page *pud_page(pud_t pud); 91062306a36Sopenharmony_ciextern struct page *pmd_page(pmd_t pmd); 91162306a36Sopenharmony_cistatic inline pte_t pud_pte(pud_t pud) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci return __pte_raw(pud_raw(pud)); 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic inline pud_t pte_pud(pte_t pte) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci return __pud_raw(pte_raw(pte)); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic inline pte_t *pudp_ptep(pud_t *pud) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci return (pte_t *)pud; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci#define pud_pfn(pud) pte_pfn(pud_pte(pud)) 92762306a36Sopenharmony_ci#define pud_dirty(pud) pte_dirty(pud_pte(pud)) 92862306a36Sopenharmony_ci#define pud_young(pud) pte_young(pud_pte(pud)) 92962306a36Sopenharmony_ci#define pud_mkold(pud) pte_pud(pte_mkold(pud_pte(pud))) 93062306a36Sopenharmony_ci#define pud_wrprotect(pud) pte_pud(pte_wrprotect(pud_pte(pud))) 93162306a36Sopenharmony_ci#define pud_mkdirty(pud) pte_pud(pte_mkdirty(pud_pte(pud))) 93262306a36Sopenharmony_ci#define pud_mkclean(pud) pte_pud(pte_mkclean(pud_pte(pud))) 93362306a36Sopenharmony_ci#define pud_mkyoung(pud) pte_pud(pte_mkyoung(pud_pte(pud))) 93462306a36Sopenharmony_ci#define pud_mkwrite(pud) pte_pud(pte_mkwrite_novma(pud_pte(pud))) 93562306a36Sopenharmony_ci#define pud_write(pud) pte_write(pud_pte(pud)) 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY 93862306a36Sopenharmony_ci#define pud_soft_dirty(pmd) pte_soft_dirty(pud_pte(pud)) 93962306a36Sopenharmony_ci#define pud_mksoft_dirty(pmd) pte_pud(pte_mksoft_dirty(pud_pte(pud))) 94062306a36Sopenharmony_ci#define pud_clear_soft_dirty(pmd) pte_pud(pte_clear_soft_dirty(pud_pte(pud))) 94162306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic inline int pud_bad(pud_t pud) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci if (radix_enabled()) 94662306a36Sopenharmony_ci return radix__pud_bad(pud); 94762306a36Sopenharmony_ci return hash__pud_bad(pud); 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci#define pud_access_permitted pud_access_permitted 95162306a36Sopenharmony_cistatic inline bool pud_access_permitted(pud_t pud, bool write) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci return pte_access_permitted(pud_pte(pud), write); 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci#define __p4d_raw(x) ((p4d_t) { __pgd_raw(x) }) 95762306a36Sopenharmony_cistatic inline __be64 p4d_raw(p4d_t x) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci return pgd_raw(x.pgd); 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci#define p4d_write(p4d) pte_write(p4d_pte(p4d)) 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic inline void p4d_clear(p4d_t *p4dp) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci *p4dp = __p4d(0); 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic inline int p4d_none(p4d_t p4d) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci return !p4d_raw(p4d); 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic inline int p4d_present(p4d_t p4d) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci return !!(p4d_raw(p4d) & cpu_to_be64(_PAGE_PRESENT)); 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic inline pte_t p4d_pte(p4d_t p4d) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci return __pte_raw(p4d_raw(p4d)); 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic inline p4d_t pte_p4d(pte_t pte) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci return __p4d_raw(pte_raw(pte)); 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic inline int p4d_bad(p4d_t p4d) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci if (radix_enabled()) 99262306a36Sopenharmony_ci return radix__p4d_bad(p4d); 99362306a36Sopenharmony_ci return hash__p4d_bad(p4d); 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci#define p4d_access_permitted p4d_access_permitted 99762306a36Sopenharmony_cistatic inline bool p4d_access_permitted(p4d_t p4d, bool write) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci return pte_access_permitted(p4d_pte(p4d), write); 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ciextern struct page *p4d_page(p4d_t p4d); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci/* Pointers in the page table tree are physical addresses */ 100562306a36Sopenharmony_ci#define __pgtable_ptr_val(ptr) __pa(ptr) 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cistatic inline pud_t *p4d_pgtable(p4d_t p4d) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci return (pud_t *)__va(p4d_val(p4d) & ~P4D_MASKED_BITS); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci return (pmd_t *)__va(pud_val(pud) & ~PUD_MASKED_BITS); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci#define pte_ERROR(e) \ 101862306a36Sopenharmony_ci pr_err("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) 101962306a36Sopenharmony_ci#define pmd_ERROR(e) \ 102062306a36Sopenharmony_ci pr_err("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) 102162306a36Sopenharmony_ci#define pud_ERROR(e) \ 102262306a36Sopenharmony_ci pr_err("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e)) 102362306a36Sopenharmony_ci#define pgd_ERROR(e) \ 102462306a36Sopenharmony_ci pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic inline int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci if (radix_enabled()) { 102962306a36Sopenharmony_ci#if defined(CONFIG_PPC_RADIX_MMU) && defined(DEBUG_VM) 103062306a36Sopenharmony_ci unsigned long page_size = 1 << mmu_psize_defs[mmu_io_psize].shift; 103162306a36Sopenharmony_ci WARN((page_size != PAGE_SIZE), "I/O page size != PAGE_SIZE"); 103262306a36Sopenharmony_ci#endif 103362306a36Sopenharmony_ci return radix__map_kernel_page(ea, pa, prot, PAGE_SIZE); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci return hash__map_kernel_page(ea, pa, prot); 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_civoid unmap_kernel_page(unsigned long va); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic inline int __meminit vmemmap_create_mapping(unsigned long start, 104162306a36Sopenharmony_ci unsigned long page_size, 104262306a36Sopenharmony_ci unsigned long phys) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci if (radix_enabled()) 104562306a36Sopenharmony_ci return radix__vmemmap_create_mapping(start, page_size, phys); 104662306a36Sopenharmony_ci return hash__vmemmap_create_mapping(start, page_size, phys); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci#ifdef CONFIG_MEMORY_HOTPLUG 105062306a36Sopenharmony_cistatic inline void vmemmap_remove_mapping(unsigned long start, 105162306a36Sopenharmony_ci unsigned long page_size) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci if (radix_enabled()) 105462306a36Sopenharmony_ci return radix__vmemmap_remove_mapping(start, page_size); 105562306a36Sopenharmony_ci return hash__vmemmap_remove_mapping(start, page_size); 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci#endif 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) 106062306a36Sopenharmony_cistatic inline void __kernel_map_pages(struct page *page, int numpages, int enable) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci if (radix_enabled()) 106362306a36Sopenharmony_ci radix__kernel_map_pages(page, numpages, enable); 106462306a36Sopenharmony_ci else 106562306a36Sopenharmony_ci hash__kernel_map_pages(page, numpages, enable); 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci#endif 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic inline pte_t pmd_pte(pmd_t pmd) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci return __pte_raw(pmd_raw(pmd)); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic inline pmd_t pte_pmd(pte_t pte) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci return __pmd_raw(pte_raw(pte)); 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic inline pte_t *pmdp_ptep(pmd_t *pmd) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci return (pte_t *)pmd; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd)) 108462306a36Sopenharmony_ci#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd)) 108562306a36Sopenharmony_ci#define pmd_young(pmd) pte_young(pmd_pte(pmd)) 108662306a36Sopenharmony_ci#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) 108762306a36Sopenharmony_ci#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) 108862306a36Sopenharmony_ci#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) 108962306a36Sopenharmony_ci#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd))) 109062306a36Sopenharmony_ci#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) 109162306a36Sopenharmony_ci#define pmd_mkwrite_novma(pmd) pte_pmd(pte_mkwrite_novma(pmd_pte(pmd))) 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY 109462306a36Sopenharmony_ci#define pmd_soft_dirty(pmd) pte_soft_dirty(pmd_pte(pmd)) 109562306a36Sopenharmony_ci#define pmd_mksoft_dirty(pmd) pte_pmd(pte_mksoft_dirty(pmd_pte(pmd))) 109662306a36Sopenharmony_ci#define pmd_clear_soft_dirty(pmd) pte_pmd(pte_clear_soft_dirty(pmd_pte(pmd))) 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION 109962306a36Sopenharmony_ci#define pmd_swp_mksoft_dirty(pmd) pte_pmd(pte_swp_mksoft_dirty(pmd_pte(pmd))) 110062306a36Sopenharmony_ci#define pmd_swp_soft_dirty(pmd) pte_swp_soft_dirty(pmd_pte(pmd)) 110162306a36Sopenharmony_ci#define pmd_swp_clear_soft_dirty(pmd) pte_pmd(pte_swp_clear_soft_dirty(pmd_pte(pmd))) 110262306a36Sopenharmony_ci#endif 110362306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING 110662306a36Sopenharmony_cistatic inline int pmd_protnone(pmd_t pmd) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci return pte_protnone(pmd_pte(pmd)); 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci#endif /* CONFIG_NUMA_BALANCING */ 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci#define pmd_write(pmd) pte_write(pmd_pte(pmd)) 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci#define pmd_access_permitted pmd_access_permitted 111562306a36Sopenharmony_cistatic inline bool pmd_access_permitted(pmd_t pmd, bool write) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci /* 111862306a36Sopenharmony_ci * pmdp_invalidate sets this combination (which is not caught by 111962306a36Sopenharmony_ci * !pte_present() check in pte_access_permitted), to prevent 112062306a36Sopenharmony_ci * lock-free lookups, as part of the serialize_against_pte_lookup() 112162306a36Sopenharmony_ci * synchronisation. 112262306a36Sopenharmony_ci * 112362306a36Sopenharmony_ci * This also catches the case where the PTE's hardware PRESENT bit is 112462306a36Sopenharmony_ci * cleared while TLB is flushed, which is suboptimal but should not 112562306a36Sopenharmony_ci * be frequent. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci if (pmd_is_serializing(pmd)) 112862306a36Sopenharmony_ci return false; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return pte_access_permitted(pmd_pte(pmd), write); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 113462306a36Sopenharmony_ciextern pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot); 113562306a36Sopenharmony_ciextern pud_t pfn_pud(unsigned long pfn, pgprot_t pgprot); 113662306a36Sopenharmony_ciextern pmd_t mk_pmd(struct page *page, pgprot_t pgprot); 113762306a36Sopenharmony_ciextern pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot); 113862306a36Sopenharmony_ciextern void set_pmd_at(struct mm_struct *mm, unsigned long addr, 113962306a36Sopenharmony_ci pmd_t *pmdp, pmd_t pmd); 114062306a36Sopenharmony_ciextern void set_pud_at(struct mm_struct *mm, unsigned long addr, 114162306a36Sopenharmony_ci pud_t *pudp, pud_t pud); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic inline void update_mmu_cache_pmd(struct vm_area_struct *vma, 114462306a36Sopenharmony_ci unsigned long addr, pmd_t *pmd) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic inline void update_mmu_cache_pud(struct vm_area_struct *vma, 114962306a36Sopenharmony_ci unsigned long addr, pud_t *pud) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ciextern int hash__has_transparent_hugepage(void); 115462306a36Sopenharmony_cistatic inline int has_transparent_hugepage(void) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci if (radix_enabled()) 115762306a36Sopenharmony_ci return radix__has_transparent_hugepage(); 115862306a36Sopenharmony_ci return hash__has_transparent_hugepage(); 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci#define has_transparent_hugepage has_transparent_hugepage 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_cistatic inline int has_transparent_pud_hugepage(void) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci if (radix_enabled()) 116562306a36Sopenharmony_ci return radix__has_transparent_pud_hugepage(); 116662306a36Sopenharmony_ci return 0; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci#define has_transparent_pud_hugepage has_transparent_pud_hugepage 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic inline unsigned long 117162306a36Sopenharmony_cipmd_hugepage_update(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, 117262306a36Sopenharmony_ci unsigned long clr, unsigned long set) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci if (radix_enabled()) 117562306a36Sopenharmony_ci return radix__pmd_hugepage_update(mm, addr, pmdp, clr, set); 117662306a36Sopenharmony_ci return hash__pmd_hugepage_update(mm, addr, pmdp, clr, set); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic inline unsigned long 118062306a36Sopenharmony_cipud_hugepage_update(struct mm_struct *mm, unsigned long addr, pud_t *pudp, 118162306a36Sopenharmony_ci unsigned long clr, unsigned long set) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci if (radix_enabled()) 118462306a36Sopenharmony_ci return radix__pud_hugepage_update(mm, addr, pudp, clr, set); 118562306a36Sopenharmony_ci BUG(); 118662306a36Sopenharmony_ci return pud_val(*pudp); 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci/* 119062306a36Sopenharmony_ci * returns true for pmd migration entries, THP, devmap, hugetlb 119162306a36Sopenharmony_ci * But compile time dependent on THP config 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_cistatic inline int pmd_large(pmd_t pmd) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci return !!(pmd_raw(pmd) & cpu_to_be64(_PAGE_PTE)); 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic inline int pud_large(pud_t pud) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PTE)); 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci/* 120462306a36Sopenharmony_ci * For radix we should always find H_PAGE_HASHPTE zero. Hence 120562306a36Sopenharmony_ci * the below will work for radix too 120662306a36Sopenharmony_ci */ 120762306a36Sopenharmony_cistatic inline int __pmdp_test_and_clear_young(struct mm_struct *mm, 120862306a36Sopenharmony_ci unsigned long addr, pmd_t *pmdp) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci unsigned long old; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if ((pmd_raw(*pmdp) & cpu_to_be64(_PAGE_ACCESSED | H_PAGE_HASHPTE)) == 0) 121362306a36Sopenharmony_ci return 0; 121462306a36Sopenharmony_ci old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0); 121562306a36Sopenharmony_ci return ((old & _PAGE_ACCESSED) != 0); 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic inline int __pudp_test_and_clear_young(struct mm_struct *mm, 121962306a36Sopenharmony_ci unsigned long addr, pud_t *pudp) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci unsigned long old; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if ((pud_raw(*pudp) & cpu_to_be64(_PAGE_ACCESSED | H_PAGE_HASHPTE)) == 0) 122462306a36Sopenharmony_ci return 0; 122562306a36Sopenharmony_ci old = pud_hugepage_update(mm, addr, pudp, _PAGE_ACCESSED, 0); 122662306a36Sopenharmony_ci return ((old & _PAGE_ACCESSED) != 0); 122762306a36Sopenharmony_ci} 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_WRPROTECT 123062306a36Sopenharmony_cistatic inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr, 123162306a36Sopenharmony_ci pmd_t *pmdp) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci if (pmd_write(*pmdp)) 123462306a36Sopenharmony_ci pmd_hugepage_update(mm, addr, pmdp, _PAGE_WRITE, 0); 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci#define __HAVE_ARCH_PUDP_SET_WRPROTECT 123862306a36Sopenharmony_cistatic inline void pudp_set_wrprotect(struct mm_struct *mm, unsigned long addr, 123962306a36Sopenharmony_ci pud_t *pudp) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci if (pud_write(*pudp)) 124262306a36Sopenharmony_ci pud_hugepage_update(mm, addr, pudp, _PAGE_WRITE, 0); 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci/* 124662306a36Sopenharmony_ci * Only returns true for a THP. False for pmd migration entry. 124762306a36Sopenharmony_ci * We also need to return true when we come across a pte that 124862306a36Sopenharmony_ci * in between a thp split. While splitting THP, we mark the pmd 124962306a36Sopenharmony_ci * invalid (pmdp_invalidate()) before we set it with pte page 125062306a36Sopenharmony_ci * address. A pmd_trans_huge() check against a pmd entry during that time 125162306a36Sopenharmony_ci * should return true. 125262306a36Sopenharmony_ci * We should not call this on a hugetlb entry. We should check for HugeTLB 125362306a36Sopenharmony_ci * entry using vma->vm_flags 125462306a36Sopenharmony_ci * The page table walk rule is explained in Documentation/mm/transhuge.rst 125562306a36Sopenharmony_ci */ 125662306a36Sopenharmony_cistatic inline int pmd_trans_huge(pmd_t pmd) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci if (!pmd_present(pmd)) 125962306a36Sopenharmony_ci return false; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (radix_enabled()) 126262306a36Sopenharmony_ci return radix__pmd_trans_huge(pmd); 126362306a36Sopenharmony_ci return hash__pmd_trans_huge(pmd); 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cistatic inline int pud_trans_huge(pud_t pud) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci if (!pud_present(pud)) 126962306a36Sopenharmony_ci return false; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci if (radix_enabled()) 127262306a36Sopenharmony_ci return radix__pud_trans_huge(pud); 127362306a36Sopenharmony_ci return 0; 127462306a36Sopenharmony_ci} 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci#define __HAVE_ARCH_PMD_SAME 127862306a36Sopenharmony_cistatic inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci if (radix_enabled()) 128162306a36Sopenharmony_ci return radix__pmd_same(pmd_a, pmd_b); 128262306a36Sopenharmony_ci return hash__pmd_same(pmd_a, pmd_b); 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci#define pud_same pud_same 128662306a36Sopenharmony_cistatic inline int pud_same(pud_t pud_a, pud_t pud_b) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci if (radix_enabled()) 128962306a36Sopenharmony_ci return radix__pud_same(pud_a, pud_b); 129062306a36Sopenharmony_ci return hash__pud_same(pud_a, pud_b); 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic inline pmd_t __pmd_mkhuge(pmd_t pmd) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci if (radix_enabled()) 129762306a36Sopenharmony_ci return radix__pmd_mkhuge(pmd); 129862306a36Sopenharmony_ci return hash__pmd_mkhuge(pmd); 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic inline pud_t __pud_mkhuge(pud_t pud) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci if (radix_enabled()) 130462306a36Sopenharmony_ci return radix__pud_mkhuge(pud); 130562306a36Sopenharmony_ci BUG(); 130662306a36Sopenharmony_ci return pud; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci/* 131062306a36Sopenharmony_ci * pfn_pmd return a pmd_t that can be used as pmd pte entry. 131162306a36Sopenharmony_ci */ 131262306a36Sopenharmony_cistatic inline pmd_t pmd_mkhuge(pmd_t pmd) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_VM 131562306a36Sopenharmony_ci if (radix_enabled()) 131662306a36Sopenharmony_ci WARN_ON((pmd_raw(pmd) & cpu_to_be64(_PAGE_PTE)) == 0); 131762306a36Sopenharmony_ci else 131862306a36Sopenharmony_ci WARN_ON((pmd_raw(pmd) & cpu_to_be64(_PAGE_PTE | H_PAGE_THP_HUGE)) != 131962306a36Sopenharmony_ci cpu_to_be64(_PAGE_PTE | H_PAGE_THP_HUGE)); 132062306a36Sopenharmony_ci#endif 132162306a36Sopenharmony_ci return pmd; 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic inline pud_t pud_mkhuge(pud_t pud) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_VM 132762306a36Sopenharmony_ci if (radix_enabled()) 132862306a36Sopenharmony_ci WARN_ON((pud_raw(pud) & cpu_to_be64(_PAGE_PTE)) == 0); 132962306a36Sopenharmony_ci else 133062306a36Sopenharmony_ci WARN_ON(1); 133162306a36Sopenharmony_ci#endif 133262306a36Sopenharmony_ci return pud; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS 133762306a36Sopenharmony_ciextern int pmdp_set_access_flags(struct vm_area_struct *vma, 133862306a36Sopenharmony_ci unsigned long address, pmd_t *pmdp, 133962306a36Sopenharmony_ci pmd_t entry, int dirty); 134062306a36Sopenharmony_ci#define __HAVE_ARCH_PUDP_SET_ACCESS_FLAGS 134162306a36Sopenharmony_ciextern int pudp_set_access_flags(struct vm_area_struct *vma, 134262306a36Sopenharmony_ci unsigned long address, pud_t *pudp, 134362306a36Sopenharmony_ci pud_t entry, int dirty); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG 134662306a36Sopenharmony_ciextern int pmdp_test_and_clear_young(struct vm_area_struct *vma, 134762306a36Sopenharmony_ci unsigned long address, pmd_t *pmdp); 134862306a36Sopenharmony_ci#define __HAVE_ARCH_PUDP_TEST_AND_CLEAR_YOUNG 134962306a36Sopenharmony_ciextern int pudp_test_and_clear_young(struct vm_area_struct *vma, 135062306a36Sopenharmony_ci unsigned long address, pud_t *pudp); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR 135462306a36Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, 135562306a36Sopenharmony_ci unsigned long addr, pmd_t *pmdp) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci if (radix_enabled()) 135862306a36Sopenharmony_ci return radix__pmdp_huge_get_and_clear(mm, addr, pmdp); 135962306a36Sopenharmony_ci return hash__pmdp_huge_get_and_clear(mm, addr, pmdp); 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci#define __HAVE_ARCH_PUDP_HUGE_GET_AND_CLEAR 136362306a36Sopenharmony_cistatic inline pud_t pudp_huge_get_and_clear(struct mm_struct *mm, 136462306a36Sopenharmony_ci unsigned long addr, pud_t *pudp) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci if (radix_enabled()) 136762306a36Sopenharmony_ci return radix__pudp_huge_get_and_clear(mm, addr, pudp); 136862306a36Sopenharmony_ci BUG(); 136962306a36Sopenharmony_ci return *pudp; 137062306a36Sopenharmony_ci} 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_cistatic inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, 137362306a36Sopenharmony_ci unsigned long address, pmd_t *pmdp) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci if (radix_enabled()) 137662306a36Sopenharmony_ci return radix__pmdp_collapse_flush(vma, address, pmdp); 137762306a36Sopenharmony_ci return hash__pmdp_collapse_flush(vma, address, pmdp); 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci#define pmdp_collapse_flush pmdp_collapse_flush 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR_FULL 138262306a36Sopenharmony_cipmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma, 138362306a36Sopenharmony_ci unsigned long addr, 138462306a36Sopenharmony_ci pmd_t *pmdp, int full); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci#define __HAVE_ARCH_PUDP_HUGE_GET_AND_CLEAR_FULL 138762306a36Sopenharmony_cipud_t pudp_huge_get_and_clear_full(struct vm_area_struct *vma, 138862306a36Sopenharmony_ci unsigned long addr, 138962306a36Sopenharmony_ci pud_t *pudp, int full); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci#define __HAVE_ARCH_PGTABLE_DEPOSIT 139262306a36Sopenharmony_cistatic inline void pgtable_trans_huge_deposit(struct mm_struct *mm, 139362306a36Sopenharmony_ci pmd_t *pmdp, pgtable_t pgtable) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci if (radix_enabled()) 139662306a36Sopenharmony_ci return radix__pgtable_trans_huge_deposit(mm, pmdp, pgtable); 139762306a36Sopenharmony_ci return hash__pgtable_trans_huge_deposit(mm, pmdp, pgtable); 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci#define __HAVE_ARCH_PGTABLE_WITHDRAW 140162306a36Sopenharmony_cistatic inline pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, 140262306a36Sopenharmony_ci pmd_t *pmdp) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci if (radix_enabled()) 140562306a36Sopenharmony_ci return radix__pgtable_trans_huge_withdraw(mm, pmdp); 140662306a36Sopenharmony_ci return hash__pgtable_trans_huge_withdraw(mm, pmdp); 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_INVALIDATE 141062306a36Sopenharmony_ciextern pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, 141162306a36Sopenharmony_ci pmd_t *pmdp); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci#define pmd_move_must_withdraw pmd_move_must_withdraw 141462306a36Sopenharmony_cistruct spinlock; 141562306a36Sopenharmony_ciextern int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, 141662306a36Sopenharmony_ci struct spinlock *old_pmd_ptl, 141762306a36Sopenharmony_ci struct vm_area_struct *vma); 141862306a36Sopenharmony_ci/* 141962306a36Sopenharmony_ci * Hash translation mode use the deposited table to store hash pte 142062306a36Sopenharmony_ci * slot information. 142162306a36Sopenharmony_ci */ 142262306a36Sopenharmony_ci#define arch_needs_pgtable_deposit arch_needs_pgtable_deposit 142362306a36Sopenharmony_cistatic inline bool arch_needs_pgtable_deposit(void) 142462306a36Sopenharmony_ci{ 142562306a36Sopenharmony_ci if (radix_enabled()) 142662306a36Sopenharmony_ci return false; 142762306a36Sopenharmony_ci return true; 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ciextern void serialize_against_pte_lookup(struct mm_struct *mm); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic inline pmd_t pmd_mkdevmap(pmd_t pmd) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci if (radix_enabled()) 143562306a36Sopenharmony_ci return radix__pmd_mkdevmap(pmd); 143662306a36Sopenharmony_ci return hash__pmd_mkdevmap(pmd); 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic inline pud_t pud_mkdevmap(pud_t pud) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci if (radix_enabled()) 144262306a36Sopenharmony_ci return radix__pud_mkdevmap(pud); 144362306a36Sopenharmony_ci BUG(); 144462306a36Sopenharmony_ci return pud; 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_cistatic inline int pmd_devmap(pmd_t pmd) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci return pte_devmap(pmd_pte(pmd)); 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cistatic inline int pud_devmap(pud_t pud) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci return pte_devmap(pud_pte(pud)); 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_cistatic inline int pgd_devmap(pgd_t pgd) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci return 0; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION 146462306a36Sopenharmony_cipte_t ptep_modify_prot_start(struct vm_area_struct *, unsigned long, pte_t *); 146562306a36Sopenharmony_civoid ptep_modify_prot_commit(struct vm_area_struct *, unsigned long, 146662306a36Sopenharmony_ci pte_t *, pte_t, pte_t); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci/* 146962306a36Sopenharmony_ci * Returns true for a R -> RW upgrade of pte 147062306a36Sopenharmony_ci */ 147162306a36Sopenharmony_cistatic inline bool is_pte_rw_upgrade(unsigned long old_val, unsigned long new_val) 147262306a36Sopenharmony_ci{ 147362306a36Sopenharmony_ci if (!(old_val & _PAGE_READ)) 147462306a36Sopenharmony_ci return false; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if ((!(old_val & _PAGE_WRITE)) && (new_val & _PAGE_WRITE)) 147762306a36Sopenharmony_ci return true; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci return false; 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci/* 148362306a36Sopenharmony_ci * Like pmd_huge() and pmd_large(), but works regardless of config options 148462306a36Sopenharmony_ci */ 148562306a36Sopenharmony_ci#define pmd_is_leaf pmd_is_leaf 148662306a36Sopenharmony_ci#define pmd_leaf pmd_is_leaf 148762306a36Sopenharmony_cistatic inline bool pmd_is_leaf(pmd_t pmd) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci return !!(pmd_raw(pmd) & cpu_to_be64(_PAGE_PTE)); 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci#define pud_is_leaf pud_is_leaf 149362306a36Sopenharmony_ci#define pud_leaf pud_is_leaf 149462306a36Sopenharmony_cistatic inline bool pud_is_leaf(pud_t pud) 149562306a36Sopenharmony_ci{ 149662306a36Sopenharmony_ci return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PTE)); 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 150062306a36Sopenharmony_ci#endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */ 1501