18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef __ASM_PGTABLE_H 68c2ecf20Sopenharmony_ci#define __ASM_PGTABLE_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <asm/bug.h> 98c2ecf20Sopenharmony_ci#include <asm/proc-fns.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <asm/memory.h> 128c2ecf20Sopenharmony_ci#include <asm/mte.h> 138c2ecf20Sopenharmony_ci#include <asm/pgtable-hwdef.h> 148c2ecf20Sopenharmony_ci#include <asm/pgtable-prot.h> 158c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * VMALLOC range. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * VMALLOC_START: beginning of the kernel vmalloc space 218c2ecf20Sopenharmony_ci * VMALLOC_END: extends to the available space below vmemmap, PCI I/O space 228c2ecf20Sopenharmony_ci * and fixed mappings 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci#define VMALLOC_START (MODULES_END) 258c2ecf20Sopenharmony_ci#define VMALLOC_END (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define FIRST_USER_ADDRESS 0UL 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 348c2ecf20Sopenharmony_ci#include <asm/fixmap.h> 358c2ecf20Sopenharmony_ci#include <linux/mmdebug.h> 368c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 378c2ecf20Sopenharmony_ci#include <linux/sched.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 408c2ecf20Sopenharmony_ci#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Set stride and tlb_level in flush_*_tlb_range */ 438c2ecf20Sopenharmony_ci#define flush_pmd_tlb_range(vma, addr, end) \ 448c2ecf20Sopenharmony_ci __flush_tlb_range(vma, addr, end, PMD_SIZE, false, 2) 458c2ecf20Sopenharmony_ci#define flush_pud_tlb_range(vma, addr, end) \ 468c2ecf20Sopenharmony_ci __flush_tlb_range(vma, addr, end, PUD_SIZE, false, 1) 478c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * Outside of a few very special situations (e.g. hibernation), we always 518c2ecf20Sopenharmony_ci * use broadcast TLB invalidation instructions, therefore a spurious page 528c2ecf20Sopenharmony_ci * fault on one CPU which has been handled concurrently by another CPU 538c2ecf20Sopenharmony_ci * does not need to perform additional invalidation. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci#define flush_tlb_fix_spurious_fault(vma, address) do { } while (0) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * ZERO_PAGE is a global shared page that is always zero: used 598c2ecf20Sopenharmony_ci * for zero-mapped memory areas etc.. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciextern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; 628c2ecf20Sopenharmony_ci#define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page)) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define pte_ERROR(e) \ 658c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pte %016llx.\n", __FILE__, __LINE__, pte_val(e)) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Macros to convert between a physical address and its placement in a 698c2ecf20Sopenharmony_ci * page table entry, taking care of 52-bit addresses. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_PA_BITS_52 728c2ecf20Sopenharmony_cistatic inline phys_addr_t __pte_to_phys(pte_t pte) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return (pte_val(pte) & PTE_ADDR_LOW) | 758c2ecf20Sopenharmony_ci ((pte_val(pte) & PTE_ADDR_HIGH) << 36); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_cistatic inline pteval_t __phys_to_pte_val(phys_addr_t phys) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return (phys | (phys >> 36)) & PTE_ADDR_MASK; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci#else 828c2ecf20Sopenharmony_ci#define __pte_to_phys(pte) (pte_val(pte) & PTE_ADDR_MASK) 838c2ecf20Sopenharmony_ci#define __phys_to_pte_val(phys) (phys) 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define pte_pfn(pte) (__pte_to_phys(pte) >> PAGE_SHIFT) 878c2ecf20Sopenharmony_ci#define pfn_pte(pfn,prot) \ 888c2ecf20Sopenharmony_ci __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define pte_none(pte) (!pte_val(pte)) 918c2ecf20Sopenharmony_ci#define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) 928c2ecf20Sopenharmony_ci#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * The following only work if pte_present(). Undefined behaviour otherwise. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))) 988c2ecf20Sopenharmony_ci#define pte_young(pte) (!!(pte_val(pte) & PTE_AF)) 998c2ecf20Sopenharmony_ci#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL)) 1008c2ecf20Sopenharmony_ci#define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE)) 1018c2ecf20Sopenharmony_ci#define pte_user_exec(pte) (!(pte_val(pte) & PTE_UXN)) 1028c2ecf20Sopenharmony_ci#define pte_cont(pte) (!!(pte_val(pte) & PTE_CONT)) 1038c2ecf20Sopenharmony_ci#define pte_devmap(pte) (!!(pte_val(pte) & PTE_DEVMAP)) 1048c2ecf20Sopenharmony_ci#define pte_tagged(pte) ((pte_val(pte) & PTE_ATTRINDX_MASK) == \ 1058c2ecf20Sopenharmony_ci PTE_ATTRINDX(MT_NORMAL_TAGGED)) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define pte_cont_addr_end(addr, end) \ 1088c2ecf20Sopenharmony_ci({ unsigned long __boundary = ((addr) + CONT_PTE_SIZE) & CONT_PTE_MASK; \ 1098c2ecf20Sopenharmony_ci (__boundary - 1 < (end) - 1) ? __boundary : (end); \ 1108c2ecf20Sopenharmony_ci}) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define pmd_cont_addr_end(addr, end) \ 1138c2ecf20Sopenharmony_ci({ unsigned long __boundary = ((addr) + CONT_PMD_SIZE) & CONT_PMD_MASK; \ 1148c2ecf20Sopenharmony_ci (__boundary - 1 < (end) - 1) ? __boundary : (end); \ 1158c2ecf20Sopenharmony_ci}) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define pte_hw_dirty(pte) (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY)) 1188c2ecf20Sopenharmony_ci#define pte_sw_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY)) 1198c2ecf20Sopenharmony_ci#define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte)) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID)) 1228c2ecf20Sopenharmony_ci#define pte_valid_not_user(pte) \ 1238c2ecf20Sopenharmony_ci ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID) 1248c2ecf20Sopenharmony_ci#define pte_valid_user(pte) \ 1258c2ecf20Sopenharmony_ci ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * Could the pte be present in the TLB? We must check mm_tlb_flush_pending 1298c2ecf20Sopenharmony_ci * so that we don't erroneously return false for pages that have been 1308c2ecf20Sopenharmony_ci * remapped as PROT_NONE but are yet to be flushed from the TLB. 1318c2ecf20Sopenharmony_ci * Note that we can't make any assumptions based on the state of the access 1328c2ecf20Sopenharmony_ci * flag, since ptep_clear_flush_young() elides a DSB when invalidating the 1338c2ecf20Sopenharmony_ci * TLB. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci#define pte_accessible(mm, pte) \ 1368c2ecf20Sopenharmony_ci (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte)) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * p??_access_permitted() is true for valid user mappings (subject to the 1408c2ecf20Sopenharmony_ci * write permission check). PROT_NONE mappings do not have the PTE_VALID bit 1418c2ecf20Sopenharmony_ci * set. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci#define pte_access_permitted(pte, write) \ 1448c2ecf20Sopenharmony_ci (pte_valid_user(pte) && (!(write) || pte_write(pte))) 1458c2ecf20Sopenharmony_ci#define pmd_access_permitted(pmd, write) \ 1468c2ecf20Sopenharmony_ci (pte_access_permitted(pmd_pte(pmd), (write))) 1478c2ecf20Sopenharmony_ci#define pud_access_permitted(pud, write) \ 1488c2ecf20Sopenharmony_ci (pte_access_permitted(pud_pte(pud), (write))) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci pte_val(pte) &= ~pgprot_val(prot); 1538c2ecf20Sopenharmony_ci return pte; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline pte_t set_pte_bit(pte_t pte, pgprot_t prot) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci pte_val(pte) |= pgprot_val(prot); 1598c2ecf20Sopenharmony_ci return pte; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic inline pmd_t clear_pmd_bit(pmd_t pmd, pgprot_t prot) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci pmd_val(pmd) &= ~pgprot_val(prot); 1658c2ecf20Sopenharmony_ci return pmd; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline pmd_t set_pmd_bit(pmd_t pmd, pgprot_t prot) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci pmd_val(pmd) |= pgprot_val(prot); 1718c2ecf20Sopenharmony_ci return pmd; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic inline pte_t pte_mkwrite(pte_t pte) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci pte = set_pte_bit(pte, __pgprot(PTE_WRITE)); 1778c2ecf20Sopenharmony_ci pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY)); 1788c2ecf20Sopenharmony_ci return pte; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY)); 1848c2ecf20Sopenharmony_ci pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return pte; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci pte = set_pte_bit(pte, __pgprot(PTE_DIRTY)); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (pte_write(pte)) 1948c2ecf20Sopenharmony_ci pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY)); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return pte; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY 2038c2ecf20Sopenharmony_ci * clear), set the PTE_DIRTY bit. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci if (pte_hw_dirty(pte)) 2068c2ecf20Sopenharmony_ci pte = pte_mkdirty(pte); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci pte = clear_pte_bit(pte, __pgprot(PTE_WRITE)); 2098c2ecf20Sopenharmony_ci pte = set_pte_bit(pte, __pgprot(PTE_RDONLY)); 2108c2ecf20Sopenharmony_ci return pte; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci return clear_pte_bit(pte, __pgprot(PTE_AF)); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci return set_pte_bit(pte, __pgprot(PTE_AF)); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci return set_pte_bit(pte, __pgprot(PTE_SPECIAL)); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic inline pte_t pte_mkcont(pte_t pte) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci pte = set_pte_bit(pte, __pgprot(PTE_CONT)); 2318c2ecf20Sopenharmony_ci return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE)); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic inline pte_t pte_mknoncont(pte_t pte) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci return clear_pte_bit(pte, __pgprot(PTE_CONT)); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic inline pte_t pte_mkpresent(pte_t pte) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return set_pte_bit(pte, __pgprot(PTE_VALID)); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic inline pmd_t pmd_mkcont(pmd_t pmd) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return __pmd(pmd_val(pmd) | PMD_SECT_CONT); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline pte_t pte_mkdevmap(pte_t pte) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci return set_pte_bit(pte, __pgprot(PTE_DEVMAP | PTE_SPECIAL)); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic inline void set_pte(pte_t *ptep, pte_t pte) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci WRITE_ONCE(*ptep, pte); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * Only if the new pte is valid and kernel, otherwise TLB maintenance 2608c2ecf20Sopenharmony_ci * or update_mmu_cache() have the necessary barriers. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci if (pte_valid_not_user(pte)) { 2638c2ecf20Sopenharmony_ci dsb(ishst); 2648c2ecf20Sopenharmony_ci isb(); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ciextern void __sync_icache_dcache(pte_t pteval); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * PTE bits configuration in the presence of hardware Dirty Bit Management 2728c2ecf20Sopenharmony_ci * (PTE_WRITE == PTE_DBM): 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * Dirty Writable | PTE_RDONLY PTE_WRITE PTE_DIRTY (sw) 2758c2ecf20Sopenharmony_ci * 0 0 | 1 0 0 2768c2ecf20Sopenharmony_ci * 0 1 | 1 1 0 2778c2ecf20Sopenharmony_ci * 1 0 | 1 0 1 2788c2ecf20Sopenharmony_ci * 1 1 | 0 1 x 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via 2818c2ecf20Sopenharmony_ci * the page fault mechanism. Checking the dirty status of a pte becomes: 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY) 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic inline void __check_racy_pte_update(struct mm_struct *mm, pte_t *ptep, 2878c2ecf20Sopenharmony_ci pte_t pte) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci pte_t old_pte; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_DEBUG_VM)) 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci old_pte = READ_ONCE(*ptep); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!pte_valid(old_pte) || !pte_valid(pte)) 2978c2ecf20Sopenharmony_ci return; 2988c2ecf20Sopenharmony_ci if (mm != current->active_mm && atomic_read(&mm->mm_users) <= 1) 2998c2ecf20Sopenharmony_ci return; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * Check for potential race with hardware updates of the pte 3038c2ecf20Sopenharmony_ci * (ptep_set_access_flags safely changes valid ptes without going 3048c2ecf20Sopenharmony_ci * through an invalid entry). 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci VM_WARN_ONCE(!pte_young(pte), 3078c2ecf20Sopenharmony_ci "%s: racy access flag clearing: 0x%016llx -> 0x%016llx", 3088c2ecf20Sopenharmony_ci __func__, pte_val(old_pte), pte_val(pte)); 3098c2ecf20Sopenharmony_ci VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte), 3108c2ecf20Sopenharmony_ci "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx", 3118c2ecf20Sopenharmony_ci __func__, pte_val(old_pte), pte_val(pte)); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic inline void set_pte_at(struct mm_struct *mm, unsigned long addr, 3158c2ecf20Sopenharmony_ci pte_t *ptep, pte_t pte) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte)) 3188c2ecf20Sopenharmony_ci __sync_icache_dcache(pte); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (system_supports_mte() && 3218c2ecf20Sopenharmony_ci pte_present(pte) && pte_tagged(pte) && !pte_special(pte)) 3228c2ecf20Sopenharmony_ci mte_sync_tags(ptep, pte); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci __check_racy_pte_update(mm, ptep, pte); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci set_pte(ptep, pte); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* 3308c2ecf20Sopenharmony_ci * Huge pte definitions. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT)) 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * Hugetlb definitions. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci#define HUGE_MAX_HSTATE 4 3388c2ecf20Sopenharmony_ci#define HPAGE_SHIFT PMD_SHIFT 3398c2ecf20Sopenharmony_ci#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) 3408c2ecf20Sopenharmony_ci#define HPAGE_MASK (~(HPAGE_SIZE - 1)) 3418c2ecf20Sopenharmony_ci#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic inline pte_t pgd_pte(pgd_t pgd) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci return __pte(pgd_val(pgd)); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic inline pte_t p4d_pte(p4d_t p4d) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci return __pte(p4d_val(p4d)); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic inline pte_t pud_pte(pud_t pud) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci return __pte(pud_val(pud)); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic inline pud_t pte_pud(pte_t pte) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci return __pud(pte_val(pte)); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic inline pmd_t pud_pmd(pud_t pud) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci return __pmd(pud_val(pud)); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic inline pte_t pmd_pte(pmd_t pmd) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci return __pte(pmd_val(pmd)); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic inline pmd_t pte_pmd(pte_t pte) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci return __pmd(pte_val(pte)); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic inline pgprot_t mk_pud_sect_prot(pgprot_t prot) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci return __pgprot((pgprot_val(prot) & ~PUD_TABLE_BIT) | PUD_TYPE_SECT); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic inline pgprot_t mk_pmd_sect_prot(pgprot_t prot) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci return __pgprot((pgprot_val(prot) & ~PMD_TABLE_BIT) | PMD_TYPE_SECT); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci#ifdef CONFIG_NUMA_BALANCING 3898c2ecf20Sopenharmony_ci/* 3908c2ecf20Sopenharmony_ci * See the comment in include/linux/pgtable.h 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic inline int pte_protnone(pte_t pte) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci return (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) == PTE_PROT_NONE; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic inline int pmd_protnone(pmd_t pmd) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci return pte_protnone(pmd_pte(pmd)); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci#endif 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci#define pmd_present_invalid(pmd) (!!(pmd_val(pmd) & PMD_PRESENT_INVALID)) 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic inline int pmd_present(pmd_t pmd) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci return pte_present(pmd_pte(pmd)) || pmd_present_invalid(pmd); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/* 4118c2ecf20Sopenharmony_ci * THP definitions. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 4158c2ecf20Sopenharmony_cistatic inline int pmd_trans_huge(pmd_t pmd) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci return pmd_val(pmd) && pmd_present(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd)) 4228c2ecf20Sopenharmony_ci#define pmd_young(pmd) pte_young(pmd_pte(pmd)) 4238c2ecf20Sopenharmony_ci#define pmd_valid(pmd) pte_valid(pmd_pte(pmd)) 4248c2ecf20Sopenharmony_ci#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) 4258c2ecf20Sopenharmony_ci#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) 4268c2ecf20Sopenharmony_ci#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) 4278c2ecf20Sopenharmony_ci#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd))) 4288c2ecf20Sopenharmony_ci#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) 4298c2ecf20Sopenharmony_ci#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic inline pmd_t pmd_mkinvalid(pmd_t pmd) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci pmd = set_pmd_bit(pmd, __pgprot(PMD_PRESENT_INVALID)); 4348c2ecf20Sopenharmony_ci pmd = clear_pmd_bit(pmd, __pgprot(PMD_SECT_VALID)); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return pmd; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd)) 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci#define pmd_write(pmd) pte_write(pmd_pte(pmd)) 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT)) 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 4468c2ecf20Sopenharmony_ci#define pmd_devmap(pmd) pte_devmap(pmd_pte(pmd)) 4478c2ecf20Sopenharmony_ci#endif 4488c2ecf20Sopenharmony_cistatic inline pmd_t pmd_mkdevmap(pmd_t pmd) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci return pte_pmd(set_pte_bit(pmd_pte(pmd), __pgprot(PTE_DEVMAP))); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci#define __pmd_to_phys(pmd) __pte_to_phys(pmd_pte(pmd)) 4548c2ecf20Sopenharmony_ci#define __phys_to_pmd_val(phys) __phys_to_pte_val(phys) 4558c2ecf20Sopenharmony_ci#define pmd_pfn(pmd) ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT) 4568c2ecf20Sopenharmony_ci#define pfn_pmd(pfn,prot) __pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) 4578c2ecf20Sopenharmony_ci#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci#define pud_young(pud) pte_young(pud_pte(pud)) 4608c2ecf20Sopenharmony_ci#define pud_mkyoung(pud) pte_pud(pte_mkyoung(pud_pte(pud))) 4618c2ecf20Sopenharmony_ci#define pud_write(pud) pte_write(pud_pte(pud)) 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci#define pud_mkhuge(pud) (__pud(pud_val(pud) & ~PUD_TABLE_BIT)) 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#define __pud_to_phys(pud) __pte_to_phys(pud_pte(pud)) 4668c2ecf20Sopenharmony_ci#define __phys_to_pud_val(phys) __phys_to_pte_val(phys) 4678c2ecf20Sopenharmony_ci#define pud_pfn(pud) ((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT) 4688c2ecf20Sopenharmony_ci#define pfn_pud(pfn,prot) __pud(__phys_to_pud_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci#define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)) 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci#define __p4d_to_phys(p4d) __pte_to_phys(p4d_pte(p4d)) 4738c2ecf20Sopenharmony_ci#define __phys_to_p4d_val(phys) __phys_to_pte_val(phys) 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci#define __pgd_to_phys(pgd) __pte_to_phys(pgd_pte(pgd)) 4768c2ecf20Sopenharmony_ci#define __phys_to_pgd_val(phys) __phys_to_pte_val(phys) 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci#define __pgprot_modify(prot,mask,bits) \ 4798c2ecf20Sopenharmony_ci __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci#define pgprot_nx(prot) \ 4828c2ecf20Sopenharmony_ci __pgprot_modify(prot, PTE_MAYBE_GP, PTE_PXN) 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* 4858c2ecf20Sopenharmony_ci * Mark the prot value as uncacheable and unbufferable. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci#define pgprot_noncached(prot) \ 4888c2ecf20Sopenharmony_ci __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN) 4898c2ecf20Sopenharmony_ci#define pgprot_writecombine(prot) \ 4908c2ecf20Sopenharmony_ci __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN) 4918c2ecf20Sopenharmony_ci#define pgprot_device(prot) \ 4928c2ecf20Sopenharmony_ci __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN) 4938c2ecf20Sopenharmony_ci#define pgprot_tagged(prot) \ 4948c2ecf20Sopenharmony_ci __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_TAGGED)) 4958c2ecf20Sopenharmony_ci#define pgprot_mhp pgprot_tagged 4968c2ecf20Sopenharmony_ci/* 4978c2ecf20Sopenharmony_ci * DMA allocations for non-coherent devices use what the Arm architecture calls 4988c2ecf20Sopenharmony_ci * "Normal non-cacheable" memory, which permits speculation, unaligned accesses 4998c2ecf20Sopenharmony_ci * and merging of writes. This is different from "Device-nGnR[nE]" memory which 5008c2ecf20Sopenharmony_ci * is intended for MMIO and thus forbids speculation, preserves access size, 5018c2ecf20Sopenharmony_ci * requires strict alignment and can also force write responses to come from the 5028c2ecf20Sopenharmony_ci * endpoint. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci#define pgprot_dmacoherent(prot) \ 5058c2ecf20Sopenharmony_ci __pgprot_modify(prot, PTE_ATTRINDX_MASK, \ 5068c2ecf20Sopenharmony_ci PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN) 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci#define __HAVE_PHYS_MEM_ACCESS_PROT 5098c2ecf20Sopenharmony_cistruct file; 5108c2ecf20Sopenharmony_ciextern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, 5118c2ecf20Sopenharmony_ci unsigned long size, pgprot_t vma_prot); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci#define pmd_none(pmd) (!pmd_val(pmd)) 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \ 5168c2ecf20Sopenharmony_ci PMD_TYPE_TABLE) 5178c2ecf20Sopenharmony_ci#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \ 5188c2ecf20Sopenharmony_ci PMD_TYPE_SECT) 5198c2ecf20Sopenharmony_ci#define pmd_leaf(pmd) (pmd_present(pmd) && !pmd_table(pmd)) 5208c2ecf20Sopenharmony_ci#define pmd_bad(pmd) (!pmd_table(pmd)) 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci#if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3 5238c2ecf20Sopenharmony_cistatic inline bool pud_sect(pud_t pud) { return false; } 5248c2ecf20Sopenharmony_cistatic inline bool pud_table(pud_t pud) { return true; } 5258c2ecf20Sopenharmony_ci#else 5268c2ecf20Sopenharmony_ci#define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \ 5278c2ecf20Sopenharmony_ci PUD_TYPE_SECT) 5288c2ecf20Sopenharmony_ci#define pud_table(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \ 5298c2ecf20Sopenharmony_ci PUD_TYPE_TABLE) 5308c2ecf20Sopenharmony_ci#endif 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ciextern pgd_t init_pg_dir[PTRS_PER_PGD]; 5338c2ecf20Sopenharmony_ciextern pgd_t init_pg_end[]; 5348c2ecf20Sopenharmony_ciextern pgd_t swapper_pg_dir[PTRS_PER_PGD]; 5358c2ecf20Sopenharmony_ciextern pgd_t idmap_pg_dir[PTRS_PER_PGD]; 5368c2ecf20Sopenharmony_ciextern pgd_t idmap_pg_end[]; 5378c2ecf20Sopenharmony_ciextern pgd_t tramp_pg_dir[PTRS_PER_PGD]; 5388c2ecf20Sopenharmony_ciextern pgd_t reserved_pg_dir[PTRS_PER_PGD]; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ciextern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic inline bool in_swapper_pgdir(void *addr) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci return ((unsigned long)addr & PAGE_MASK) == 5458c2ecf20Sopenharmony_ci ((unsigned long)swapper_pg_dir & PAGE_MASK); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic inline void set_pmd(pmd_t *pmdp, pmd_t pmd) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci#ifdef __PAGETABLE_PMD_FOLDED 5518c2ecf20Sopenharmony_ci if (in_swapper_pgdir(pmdp)) { 5528c2ecf20Sopenharmony_ci set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd))); 5538c2ecf20Sopenharmony_ci return; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci#endif /* __PAGETABLE_PMD_FOLDED */ 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci WRITE_ONCE(*pmdp, pmd); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (pmd_valid(pmd)) { 5608c2ecf20Sopenharmony_ci dsb(ishst); 5618c2ecf20Sopenharmony_ci isb(); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic inline void pmd_clear(pmd_t *pmdp) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci set_pmd(pmdp, __pmd(0)); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic inline phys_addr_t pmd_page_paddr(pmd_t pmd) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci return __pmd_to_phys(pmd); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic inline unsigned long pmd_page_vaddr(pmd_t pmd) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci return (unsigned long)__va(pmd_page_paddr(pmd)); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/* Find an entry in the third-level page table. */ 5818c2ecf20Sopenharmony_ci#define pte_offset_phys(dir,addr) (pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t)) 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci#define pte_set_fixmap(addr) ((pte_t *)set_fixmap_offset(FIX_PTE, addr)) 5848c2ecf20Sopenharmony_ci#define pte_set_fixmap_offset(pmd, addr) pte_set_fixmap(pte_offset_phys(pmd, addr)) 5858c2ecf20Sopenharmony_ci#define pte_clear_fixmap() clear_fixmap(FIX_PTE) 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci#define pmd_page(pmd) phys_to_page(__pmd_to_phys(pmd)) 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci/* use ONLY for statically allocated translation tables */ 5908c2ecf20Sopenharmony_ci#define pte_offset_kimg(dir,addr) ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr)))) 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/* 5938c2ecf20Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry, 5948c2ecf20Sopenharmony_ci * and a page entry and page directory to the page they refer to. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci#define pmd_ERROR(e) \ 6018c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e)) 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci#define pud_none(pud) (!pud_val(pud)) 6048c2ecf20Sopenharmony_ci#define pud_bad(pud) (!pud_table(pud)) 6058c2ecf20Sopenharmony_ci#define pud_present(pud) pte_present(pud_pte(pud)) 6068c2ecf20Sopenharmony_ci#define pud_leaf(pud) (pud_present(pud) && !pud_table(pud)) 6078c2ecf20Sopenharmony_ci#define pud_valid(pud) pte_valid(pud_pte(pud)) 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic inline void set_pud(pud_t *pudp, pud_t pud) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci#ifdef __PAGETABLE_PUD_FOLDED 6128c2ecf20Sopenharmony_ci if (in_swapper_pgdir(pudp)) { 6138c2ecf20Sopenharmony_ci set_swapper_pgd((pgd_t *)pudp, __pgd(pud_val(pud))); 6148c2ecf20Sopenharmony_ci return; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci#endif /* __PAGETABLE_PUD_FOLDED */ 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci WRITE_ONCE(*pudp, pud); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (pud_valid(pud)) { 6218c2ecf20Sopenharmony_ci dsb(ishst); 6228c2ecf20Sopenharmony_ci isb(); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic inline void pud_clear(pud_t *pudp) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci set_pud(pudp, __pud(0)); 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic inline phys_addr_t pud_page_paddr(pud_t pud) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci return __pud_to_phys(pud); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci return (pmd_t *)__va(pud_page_paddr(pud)); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/* Find an entry in the second-level page table. */ 6428c2ecf20Sopenharmony_ci#define pmd_offset_phys(dir, addr) (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t)) 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci#define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr)) 6458c2ecf20Sopenharmony_ci#define pmd_set_fixmap_offset(pud, addr) pmd_set_fixmap(pmd_offset_phys(pud, addr)) 6468c2ecf20Sopenharmony_ci#define pmd_clear_fixmap() clear_fixmap(FIX_PMD) 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci#define pud_page(pud) phys_to_page(__pud_to_phys(pud)) 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci/* use ONLY for statically allocated translation tables */ 6518c2ecf20Sopenharmony_ci#define pmd_offset_kimg(dir,addr) ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr)))) 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci#else 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci#define pud_page_paddr(pud) ({ BUILD_BUG(); 0; }) 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci/* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */ 6588c2ecf20Sopenharmony_ci#define pmd_set_fixmap(addr) NULL 6598c2ecf20Sopenharmony_ci#define pmd_set_fixmap_offset(pudp, addr) ((pmd_t *)pudp) 6608c2ecf20Sopenharmony_ci#define pmd_clear_fixmap() 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci#define pmd_offset_kimg(dir,addr) ((pmd_t *)dir) 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci#endif /* CONFIG_PGTABLE_LEVELS > 2 */ 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci#define pud_ERROR(e) \ 6698c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pud %016llx.\n", __FILE__, __LINE__, pud_val(e)) 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci#define p4d_none(p4d) (!p4d_val(p4d)) 6728c2ecf20Sopenharmony_ci#define p4d_bad(p4d) (!(p4d_val(p4d) & 2)) 6738c2ecf20Sopenharmony_ci#define p4d_present(p4d) (p4d_val(p4d)) 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic inline void set_p4d(p4d_t *p4dp, p4d_t p4d) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci if (in_swapper_pgdir(p4dp)) { 6788c2ecf20Sopenharmony_ci set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d))); 6798c2ecf20Sopenharmony_ci return; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci WRITE_ONCE(*p4dp, p4d); 6838c2ecf20Sopenharmony_ci dsb(ishst); 6848c2ecf20Sopenharmony_ci isb(); 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic inline void p4d_clear(p4d_t *p4dp) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci set_p4d(p4dp, __p4d(0)); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic inline phys_addr_t p4d_page_paddr(p4d_t p4d) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci return __p4d_to_phys(p4d); 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic inline pud_t *p4d_pgtable(p4d_t p4d) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci return (pud_t *)__va(p4d_page_paddr(p4d)); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci/* Find an entry in the frst-level page table. */ 7038c2ecf20Sopenharmony_ci#define pud_offset_phys(dir, addr) (p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t)) 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci#define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr)) 7068c2ecf20Sopenharmony_ci#define pud_set_fixmap_offset(p4d, addr) pud_set_fixmap(pud_offset_phys(p4d, addr)) 7078c2ecf20Sopenharmony_ci#define pud_clear_fixmap() clear_fixmap(FIX_PUD) 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci#define p4d_page(p4d) pfn_to_page(__phys_to_pfn(__p4d_to_phys(p4d))) 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* use ONLY for statically allocated translation tables */ 7128c2ecf20Sopenharmony_ci#define pud_offset_kimg(dir,addr) ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr)))) 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci#else 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci#define p4d_page_paddr(p4d) ({ BUILD_BUG(); 0;}) 7178c2ecf20Sopenharmony_ci#define pgd_page_paddr(pgd) ({ BUILD_BUG(); 0;}) 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */ 7208c2ecf20Sopenharmony_ci#define pud_set_fixmap(addr) NULL 7218c2ecf20Sopenharmony_ci#define pud_set_fixmap_offset(pgdp, addr) ((pud_t *)pgdp) 7228c2ecf20Sopenharmony_ci#define pud_clear_fixmap() 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci#define pud_offset_kimg(dir,addr) ((pud_t *)dir) 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci#endif /* CONFIG_PGTABLE_LEVELS > 3 */ 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci#define pgd_ERROR(e) \ 7298c2ecf20Sopenharmony_ci pr_err("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e)) 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci#define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr)) 7328c2ecf20Sopenharmony_ci#define pgd_clear_fixmap() clear_fixmap(FIX_PGD) 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * Normal and Normal-Tagged are two different memory types and indices 7388c2ecf20Sopenharmony_ci * in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK. 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_ci const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | 7418c2ecf20Sopenharmony_ci PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP | 7428c2ecf20Sopenharmony_ci PTE_ATTRINDX_MASK; 7438c2ecf20Sopenharmony_ci /* preserve the hardware dirty information */ 7448c2ecf20Sopenharmony_ci if (pte_hw_dirty(pte)) 7458c2ecf20Sopenharmony_ci pte = pte_mkdirty(pte); 7468c2ecf20Sopenharmony_ci pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); 7478c2ecf20Sopenharmony_ci /* 7488c2ecf20Sopenharmony_ci * If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware 7498c2ecf20Sopenharmony_ci * dirtiness again. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci if (pte_sw_dirty(pte)) 7528c2ecf20Sopenharmony_ci pte = pte_mkdirty(pte); 7538c2ecf20Sopenharmony_ci return pte; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci return pte_pmd(pte_modify(pmd_pte(pmd), newprot)); 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS 7628c2ecf20Sopenharmony_ciextern int ptep_set_access_flags(struct vm_area_struct *vma, 7638c2ecf20Sopenharmony_ci unsigned long address, pte_t *ptep, 7648c2ecf20Sopenharmony_ci pte_t entry, int dirty); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 7678c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS 7688c2ecf20Sopenharmony_cistatic inline int pmdp_set_access_flags(struct vm_area_struct *vma, 7698c2ecf20Sopenharmony_ci unsigned long address, pmd_t *pmdp, 7708c2ecf20Sopenharmony_ci pmd_t entry, int dirty) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic inline int pud_devmap(pud_t pud) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic inline int pgd_devmap(pgd_t pgd) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci#endif 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/* 7878c2ecf20Sopenharmony_ci * Atomic pte/pmd modifications. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG 7908c2ecf20Sopenharmony_cistatic inline int __ptep_test_and_clear_young(pte_t *ptep) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci pte_t old_pte, pte; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci pte = READ_ONCE(*ptep); 7958c2ecf20Sopenharmony_ci do { 7968c2ecf20Sopenharmony_ci old_pte = pte; 7978c2ecf20Sopenharmony_ci pte = pte_mkold(pte); 7988c2ecf20Sopenharmony_ci pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), 7998c2ecf20Sopenharmony_ci pte_val(old_pte), pte_val(pte)); 8008c2ecf20Sopenharmony_ci } while (pte_val(pte) != pte_val(old_pte)); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return pte_young(pte); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic inline int ptep_test_and_clear_young(struct vm_area_struct *vma, 8068c2ecf20Sopenharmony_ci unsigned long address, 8078c2ecf20Sopenharmony_ci pte_t *ptep) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci return __ptep_test_and_clear_young(ptep); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH 8138c2ecf20Sopenharmony_cistatic inline int ptep_clear_flush_young(struct vm_area_struct *vma, 8148c2ecf20Sopenharmony_ci unsigned long address, pte_t *ptep) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci int young = ptep_test_and_clear_young(vma, address, ptep); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (young) { 8198c2ecf20Sopenharmony_ci /* 8208c2ecf20Sopenharmony_ci * We can elide the trailing DSB here since the worst that can 8218c2ecf20Sopenharmony_ci * happen is that a CPU continues to use the young entry in its 8228c2ecf20Sopenharmony_ci * TLB and we mistakenly reclaim the associated page. The 8238c2ecf20Sopenharmony_ci * window for such an event is bounded by the next 8248c2ecf20Sopenharmony_ci * context-switch, which provides a DSB to complete the TLB 8258c2ecf20Sopenharmony_ci * invalidation. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci flush_tlb_page_nosync(vma, address); 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci return young; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 8348c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG 8358c2ecf20Sopenharmony_cistatic inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, 8368c2ecf20Sopenharmony_ci unsigned long address, 8378c2ecf20Sopenharmony_ci pmd_t *pmdp) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_GET_AND_CLEAR 8448c2ecf20Sopenharmony_cistatic inline pte_t ptep_get_and_clear(struct mm_struct *mm, 8458c2ecf20Sopenharmony_ci unsigned long address, pte_t *ptep) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci return __pte(xchg_relaxed(&pte_val(*ptep), 0)); 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 8518c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR 8528c2ecf20Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, 8538c2ecf20Sopenharmony_ci unsigned long address, pmd_t *pmdp) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp)); 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci/* 8608c2ecf20Sopenharmony_ci * ptep_set_wrprotect - mark read-only while trasferring potential hardware 8618c2ecf20Sopenharmony_ci * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit. 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PTEP_SET_WRPROTECT 8648c2ecf20Sopenharmony_cistatic inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci pte_t old_pte, pte; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci pte = READ_ONCE(*ptep); 8698c2ecf20Sopenharmony_ci do { 8708c2ecf20Sopenharmony_ci old_pte = pte; 8718c2ecf20Sopenharmony_ci pte = pte_wrprotect(pte); 8728c2ecf20Sopenharmony_ci pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), 8738c2ecf20Sopenharmony_ci pte_val(old_pte), pte_val(pte)); 8748c2ecf20Sopenharmony_ci } while (pte_val(pte) != pte_val(old_pte)); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 8788c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PMDP_SET_WRPROTECT 8798c2ecf20Sopenharmony_cistatic inline void pmdp_set_wrprotect(struct mm_struct *mm, 8808c2ecf20Sopenharmony_ci unsigned long address, pmd_t *pmdp) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci ptep_set_wrprotect(mm, address, (pte_t *)pmdp); 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci#define pmdp_establish pmdp_establish 8868c2ecf20Sopenharmony_cistatic inline pmd_t pmdp_establish(struct vm_area_struct *vma, 8878c2ecf20Sopenharmony_ci unsigned long address, pmd_t *pmdp, pmd_t pmd) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd))); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci#endif 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci/* 8948c2ecf20Sopenharmony_ci * Encode and decode a swap entry: 8958c2ecf20Sopenharmony_ci * bits 0-1: present (must be zero) 8968c2ecf20Sopenharmony_ci * bits 2-7: swap type 8978c2ecf20Sopenharmony_ci * bits 8-57: swap offset 8988c2ecf20Sopenharmony_ci * bit 58: PTE_PROT_NONE (must be zero) 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci#define __SWP_TYPE_SHIFT 2 9018c2ecf20Sopenharmony_ci#define __SWP_TYPE_BITS 6 9028c2ecf20Sopenharmony_ci#define __SWP_OFFSET_BITS 50 9038c2ecf20Sopenharmony_ci#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) 9048c2ecf20Sopenharmony_ci#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) 9058c2ecf20Sopenharmony_ci#define __SWP_OFFSET_MASK ((1UL << __SWP_OFFSET_BITS) - 1) 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) 9088c2ecf20Sopenharmony_ci#define __swp_offset(x) (((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK) 9098c2ecf20Sopenharmony_ci#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) }) 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) 9128c2ecf20Sopenharmony_ci#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION 9158c2ecf20Sopenharmony_ci#define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val(pmd) }) 9168c2ecf20Sopenharmony_ci#define __swp_entry_to_pmd(swp) __pmd((swp).val) 9178c2ecf20Sopenharmony_ci#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */ 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci/* 9208c2ecf20Sopenharmony_ci * Ensure that there are not more swap files than can be encoded in the kernel 9218c2ecf20Sopenharmony_ci * PTEs. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ciextern int kern_addr_valid(unsigned long addr); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_MTE 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci#define __HAVE_ARCH_PREPARE_TO_SWAP 9308c2ecf20Sopenharmony_cistatic inline int arch_prepare_to_swap(struct page *page) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci if (system_supports_mte()) 9338c2ecf20Sopenharmony_ci return mte_save_tags(page); 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci#define __HAVE_ARCH_SWAP_INVALIDATE 9388c2ecf20Sopenharmony_cistatic inline void arch_swap_invalidate_page(int type, pgoff_t offset) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci if (system_supports_mte()) 9418c2ecf20Sopenharmony_ci mte_invalidate_tags(type, offset); 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic inline void arch_swap_invalidate_area(int type) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci if (system_supports_mte()) 9478c2ecf20Sopenharmony_ci mte_invalidate_tags_area(type); 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci#define __HAVE_ARCH_SWAP_RESTORE 9518c2ecf20Sopenharmony_cistatic inline void arch_swap_restore(swp_entry_t entry, struct page *page) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci if (system_supports_mte() && mte_restore_tags(entry, page)) 9548c2ecf20Sopenharmony_ci set_bit(PG_mte_tagged, &page->flags); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci#endif /* CONFIG_ARM64_MTE */ 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/* 9608c2ecf20Sopenharmony_ci * On AArch64, the cache coherency is handled via the set_pte_at() function. 9618c2ecf20Sopenharmony_ci */ 9628c2ecf20Sopenharmony_cistatic inline void update_mmu_cache(struct vm_area_struct *vma, 9638c2ecf20Sopenharmony_ci unsigned long addr, pte_t *ptep) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci /* 9668c2ecf20Sopenharmony_ci * We don't do anything here, so there's a very small chance of 9678c2ecf20Sopenharmony_ci * us retaking a user fault which we just fixed up. The alternative 9688c2ecf20Sopenharmony_ci * is doing a dsb(ishst), but that penalises the fastpath. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_PA_BITS_52 9758c2ecf20Sopenharmony_ci#define phys_to_ttbr(addr) (((addr) | ((addr) >> 46)) & TTBR_BADDR_MASK_52) 9768c2ecf20Sopenharmony_ci#else 9778c2ecf20Sopenharmony_ci#define phys_to_ttbr(addr) (addr) 9788c2ecf20Sopenharmony_ci#endif 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci/* 9818c2ecf20Sopenharmony_ci * On arm64 without hardware Access Flag, copying from user will fail because 9828c2ecf20Sopenharmony_ci * the pte is old and cannot be marked young. So we always end up with zeroed 9838c2ecf20Sopenharmony_ci * page after fork() + CoW for pfn mappings. We don't always have a 9848c2ecf20Sopenharmony_ci * hardware-managed access flag on arm64. 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_cistatic inline bool arch_faults_on_old_pte(void) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci WARN_ON(preemptible()); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return !cpu_has_hw_af(); 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci#define arch_faults_on_old_pte arch_faults_on_old_pte 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci#endif /* __ASM_PGTABLE_H */ 997