18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mm/pgtable-generic.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Generic pgtable methods declared in linux/pgtable.h 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Linus Torvalds 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 118c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 128c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 138c2ecf20Sopenharmony_ci#include <asm/tlb.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * If a p?d_bad entry is found while walking page tables, report 178c2ecf20Sopenharmony_ci * the error, before resetting entry to p?d_none. Usually (but 188c2ecf20Sopenharmony_ci * very seldom) called out from the p?d_none_or_clear_bad macros. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_civoid pgd_clear_bad(pgd_t *pgd) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci pgd_ERROR(*pgd); 248c2ecf20Sopenharmony_ci pgd_clear(pgd); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#ifndef __PAGETABLE_P4D_FOLDED 288c2ecf20Sopenharmony_civoid p4d_clear_bad(p4d_t *p4d) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci p4d_ERROR(*p4d); 318c2ecf20Sopenharmony_ci p4d_clear(p4d); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED 368c2ecf20Sopenharmony_civoid pud_clear_bad(pud_t *pud) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci pud_ERROR(*pud); 398c2ecf20Sopenharmony_ci pud_clear(pud); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * Note that the pmd variant below can't be stub'ed out just as for p4d/pud 458c2ecf20Sopenharmony_ci * above. pmd folding is special and typically pmd_* macros refer to upper 468c2ecf20Sopenharmony_ci * level even when folded 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_civoid pmd_clear_bad(pmd_t *pmd) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci pmd_ERROR(*pmd); 518c2ecf20Sopenharmony_ci pmd_clear(pmd); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Only sets the access flags (dirty, accessed), as well as write 578c2ecf20Sopenharmony_ci * permission. Furthermore, we know it always gets set to a "more 588c2ecf20Sopenharmony_ci * permissive" setting, which allows most architectures to optimize 598c2ecf20Sopenharmony_ci * this. We return whether the PTE actually changed, which in turn 608c2ecf20Sopenharmony_ci * instructs the caller to do things like update__mmu_cache. This 618c2ecf20Sopenharmony_ci * used to be done in the caller, but sparc needs minor faults to 628c2ecf20Sopenharmony_ci * force that call on sun4c so we changed this macro slightly 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ciint ptep_set_access_flags(struct vm_area_struct *vma, 658c2ecf20Sopenharmony_ci unsigned long address, pte_t *ptep, 668c2ecf20Sopenharmony_ci pte_t entry, int dirty) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int changed = !pte_same(*ptep, entry); 698c2ecf20Sopenharmony_ci if (changed) { 708c2ecf20Sopenharmony_ci set_pte_at(vma->vm_mm, address, ptep, entry); 718c2ecf20Sopenharmony_ci flush_tlb_fix_spurious_fault(vma, address); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci return changed; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci#endif 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH 788c2ecf20Sopenharmony_ciint ptep_clear_flush_young(struct vm_area_struct *vma, 798c2ecf20Sopenharmony_ci unsigned long address, pte_t *ptep) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int young; 828c2ecf20Sopenharmony_ci young = ptep_test_and_clear_young(vma, address, ptep); 838c2ecf20Sopenharmony_ci if (young) 848c2ecf20Sopenharmony_ci flush_tlb_page(vma, address); 858c2ecf20Sopenharmony_ci return young; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci#endif 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH 908c2ecf20Sopenharmony_cipte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, 918c2ecf20Sopenharmony_ci pte_t *ptep) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct mm_struct *mm = (vma)->vm_mm; 948c2ecf20Sopenharmony_ci pte_t pte; 958c2ecf20Sopenharmony_ci pte = ptep_get_and_clear(mm, address, ptep); 968c2ecf20Sopenharmony_ci if (pte_accessible(mm, pte)) 978c2ecf20Sopenharmony_ci flush_tlb_page(vma, address); 988c2ecf20Sopenharmony_ci return pte; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS 1058c2ecf20Sopenharmony_ciint pmdp_set_access_flags(struct vm_area_struct *vma, 1068c2ecf20Sopenharmony_ci unsigned long address, pmd_t *pmdp, 1078c2ecf20Sopenharmony_ci pmd_t entry, int dirty) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int changed = !pmd_same(*pmdp, entry); 1108c2ecf20Sopenharmony_ci VM_BUG_ON(address & ~HPAGE_PMD_MASK); 1118c2ecf20Sopenharmony_ci if (changed) { 1128c2ecf20Sopenharmony_ci set_pmd_at(vma->vm_mm, address, pmdp, entry); 1138c2ecf20Sopenharmony_ci flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci return changed; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH 1208c2ecf20Sopenharmony_ciint pmdp_clear_flush_young(struct vm_area_struct *vma, 1218c2ecf20Sopenharmony_ci unsigned long address, pmd_t *pmdp) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int young; 1248c2ecf20Sopenharmony_ci VM_BUG_ON(address & ~HPAGE_PMD_MASK); 1258c2ecf20Sopenharmony_ci young = pmdp_test_and_clear_young(vma, address, pmdp); 1268c2ecf20Sopenharmony_ci if (young) 1278c2ecf20Sopenharmony_ci flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 1288c2ecf20Sopenharmony_ci return young; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH 1338c2ecf20Sopenharmony_cipmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address, 1348c2ecf20Sopenharmony_ci pmd_t *pmdp) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci pmd_t pmd; 1378c2ecf20Sopenharmony_ci VM_BUG_ON(address & ~HPAGE_PMD_MASK); 1388c2ecf20Sopenharmony_ci VM_BUG_ON(pmd_present(*pmdp) && !pmd_trans_huge(*pmdp) && 1398c2ecf20Sopenharmony_ci !pmd_devmap(*pmdp)); 1408c2ecf20Sopenharmony_ci pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); 1418c2ecf20Sopenharmony_ci flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 1428c2ecf20Sopenharmony_ci return pmd; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD 1468c2ecf20Sopenharmony_cipud_t pudp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address, 1478c2ecf20Sopenharmony_ci pud_t *pudp) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci pud_t pud; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci VM_BUG_ON(address & ~HPAGE_PUD_MASK); 1528c2ecf20Sopenharmony_ci VM_BUG_ON(!pud_trans_huge(*pudp) && !pud_devmap(*pudp)); 1538c2ecf20Sopenharmony_ci pud = pudp_huge_get_and_clear(vma->vm_mm, address, pudp); 1548c2ecf20Sopenharmony_ci flush_pud_tlb_range(vma, address, address + HPAGE_PUD_SIZE); 1558c2ecf20Sopenharmony_ci return pud; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci#endif 1588c2ecf20Sopenharmony_ci#endif 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PGTABLE_DEPOSIT 1618c2ecf20Sopenharmony_civoid pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, 1628c2ecf20Sopenharmony_ci pgtable_t pgtable) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci assert_spin_locked(pmd_lockptr(mm, pmdp)); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* FIFO */ 1678c2ecf20Sopenharmony_ci if (!pmd_huge_pte(mm, pmdp)) 1688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pgtable->lru); 1698c2ecf20Sopenharmony_ci else 1708c2ecf20Sopenharmony_ci list_add(&pgtable->lru, &pmd_huge_pte(mm, pmdp)->lru); 1718c2ecf20Sopenharmony_ci pmd_huge_pte(mm, pmdp) = pgtable; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci#endif 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PGTABLE_WITHDRAW 1768c2ecf20Sopenharmony_ci/* no "address" argument so destroys page coloring of some arch */ 1778c2ecf20Sopenharmony_cipgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci pgtable_t pgtable; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci assert_spin_locked(pmd_lockptr(mm, pmdp)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* FIFO */ 1848c2ecf20Sopenharmony_ci pgtable = pmd_huge_pte(mm, pmdp); 1858c2ecf20Sopenharmony_ci pmd_huge_pte(mm, pmdp) = list_first_entry_or_null(&pgtable->lru, 1868c2ecf20Sopenharmony_ci struct page, lru); 1878c2ecf20Sopenharmony_ci if (pmd_huge_pte(mm, pmdp)) 1888c2ecf20Sopenharmony_ci list_del(&pgtable->lru); 1898c2ecf20Sopenharmony_ci return pgtable; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci#endif 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PMDP_INVALIDATE 1948c2ecf20Sopenharmony_cipmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, 1958c2ecf20Sopenharmony_ci pmd_t *pmdp) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci pmd_t old = pmdp_establish(vma, address, pmdp, pmd_mkinvalid(*pmdp)); 1988c2ecf20Sopenharmony_ci flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 1998c2ecf20Sopenharmony_ci return old; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci#endif 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#ifndef pmdp_collapse_flush 2048c2ecf20Sopenharmony_cipmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address, 2058c2ecf20Sopenharmony_ci pmd_t *pmdp) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * pmd and hugepage pte format are same. So we could 2098c2ecf20Sopenharmony_ci * use the same function. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci pmd_t pmd; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci VM_BUG_ON(address & ~HPAGE_PMD_MASK); 2148c2ecf20Sopenharmony_ci VM_BUG_ON(pmd_trans_huge(*pmdp)); 2158c2ecf20Sopenharmony_ci pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* collapse entails shooting down ptes not pmd */ 2188c2ecf20Sopenharmony_ci flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); 2198c2ecf20Sopenharmony_ci return pmd; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci#endif 2228c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 223