18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IBM System z Huge TLB Page Support for Kernel. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2007,2020 68c2ecf20Sopenharmony_ci * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "hugetlb" 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/mm.h> 138c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 148c2ecf20Sopenharmony_ci#include <linux/mman.h> 158c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 168c2ecf20Sopenharmony_ci#include <linux/security.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* 198c2ecf20Sopenharmony_ci * If the bit selected by single-bit bitmask "a" is set within "x", move 208c2ecf20Sopenharmony_ci * it to the position indicated by single-bit bitmask "b". 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#define move_set_bit(x, a, b) (((x) & (a)) >> ilog2(a) << ilog2(b)) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic inline unsigned long __pte_to_rste(pte_t pte) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci unsigned long rste; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* 298c2ecf20Sopenharmony_ci * Convert encoding pte bits pmd / pud bits 308c2ecf20Sopenharmony_ci * lIR.uswrdy.p dy..R...I...wr 318c2ecf20Sopenharmony_ci * empty 010.000000.0 -> 00..0...1...00 328c2ecf20Sopenharmony_ci * prot-none, clean, old 111.000000.1 -> 00..1...1...00 338c2ecf20Sopenharmony_ci * prot-none, clean, young 111.000001.1 -> 01..1...1...00 348c2ecf20Sopenharmony_ci * prot-none, dirty, old 111.000010.1 -> 10..1...1...00 358c2ecf20Sopenharmony_ci * prot-none, dirty, young 111.000011.1 -> 11..1...1...00 368c2ecf20Sopenharmony_ci * read-only, clean, old 111.000100.1 -> 00..1...1...01 378c2ecf20Sopenharmony_ci * read-only, clean, young 101.000101.1 -> 01..1...0...01 388c2ecf20Sopenharmony_ci * read-only, dirty, old 111.000110.1 -> 10..1...1...01 398c2ecf20Sopenharmony_ci * read-only, dirty, young 101.000111.1 -> 11..1...0...01 408c2ecf20Sopenharmony_ci * read-write, clean, old 111.001100.1 -> 00..1...1...11 418c2ecf20Sopenharmony_ci * read-write, clean, young 101.001101.1 -> 01..1...0...11 428c2ecf20Sopenharmony_ci * read-write, dirty, old 110.001110.1 -> 10..0...1...11 438c2ecf20Sopenharmony_ci * read-write, dirty, young 100.001111.1 -> 11..0...0...11 448c2ecf20Sopenharmony_ci * HW-bits: R read-only, I invalid 458c2ecf20Sopenharmony_ci * SW-bits: p present, y young, d dirty, r read, w write, s special, 468c2ecf20Sopenharmony_ci * u unused, l large 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci if (pte_present(pte)) { 498c2ecf20Sopenharmony_ci rste = pte_val(pte) & PAGE_MASK; 508c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_READ, 518c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_READ); 528c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_WRITE, 538c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_WRITE); 548c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_INVALID, 558c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_INVALID); 568c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_PROTECT, 578c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_PROTECT); 588c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_DIRTY, 598c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_DIRTY); 608c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_YOUNG, 618c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_YOUNG); 628c2ecf20Sopenharmony_ci#ifdef CONFIG_MEM_SOFT_DIRTY 638c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_SOFT_DIRTY, 648c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_SOFT_DIRTY); 658c2ecf20Sopenharmony_ci#endif 668c2ecf20Sopenharmony_ci rste |= move_set_bit(pte_val(pte), _PAGE_NOEXEC, 678c2ecf20Sopenharmony_ci _SEGMENT_ENTRY_NOEXEC); 688c2ecf20Sopenharmony_ci } else 698c2ecf20Sopenharmony_ci rste = _SEGMENT_ENTRY_EMPTY; 708c2ecf20Sopenharmony_ci return rste; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline pte_t __rste_to_pte(unsigned long rste) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int present; 768c2ecf20Sopenharmony_ci pte_t pte; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) 798c2ecf20Sopenharmony_ci present = pud_present(__pud(rste)); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci present = pmd_present(__pmd(rste)); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * Convert encoding pmd / pud bits pte bits 858c2ecf20Sopenharmony_ci * dy..R...I...wr lIR.uswrdy.p 868c2ecf20Sopenharmony_ci * empty 00..0...1...00 -> 010.000000.0 878c2ecf20Sopenharmony_ci * prot-none, clean, old 00..1...1...00 -> 111.000000.1 888c2ecf20Sopenharmony_ci * prot-none, clean, young 01..1...1...00 -> 111.000001.1 898c2ecf20Sopenharmony_ci * prot-none, dirty, old 10..1...1...00 -> 111.000010.1 908c2ecf20Sopenharmony_ci * prot-none, dirty, young 11..1...1...00 -> 111.000011.1 918c2ecf20Sopenharmony_ci * read-only, clean, old 00..1...1...01 -> 111.000100.1 928c2ecf20Sopenharmony_ci * read-only, clean, young 01..1...0...01 -> 101.000101.1 938c2ecf20Sopenharmony_ci * read-only, dirty, old 10..1...1...01 -> 111.000110.1 948c2ecf20Sopenharmony_ci * read-only, dirty, young 11..1...0...01 -> 101.000111.1 958c2ecf20Sopenharmony_ci * read-write, clean, old 00..1...1...11 -> 111.001100.1 968c2ecf20Sopenharmony_ci * read-write, clean, young 01..1...0...11 -> 101.001101.1 978c2ecf20Sopenharmony_ci * read-write, dirty, old 10..0...1...11 -> 110.001110.1 988c2ecf20Sopenharmony_ci * read-write, dirty, young 11..0...0...11 -> 100.001111.1 998c2ecf20Sopenharmony_ci * HW-bits: R read-only, I invalid 1008c2ecf20Sopenharmony_ci * SW-bits: p present, y young, d dirty, r read, w write, s special, 1018c2ecf20Sopenharmony_ci * u unused, l large 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci if (present) { 1048c2ecf20Sopenharmony_ci pte_val(pte) = rste & _SEGMENT_ENTRY_ORIGIN_LARGE; 1058c2ecf20Sopenharmony_ci pte_val(pte) |= _PAGE_LARGE | _PAGE_PRESENT; 1068c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_READ, 1078c2ecf20Sopenharmony_ci _PAGE_READ); 1088c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_WRITE, 1098c2ecf20Sopenharmony_ci _PAGE_WRITE); 1108c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_INVALID, 1118c2ecf20Sopenharmony_ci _PAGE_INVALID); 1128c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_PROTECT, 1138c2ecf20Sopenharmony_ci _PAGE_PROTECT); 1148c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_DIRTY, 1158c2ecf20Sopenharmony_ci _PAGE_DIRTY); 1168c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_YOUNG, 1178c2ecf20Sopenharmony_ci _PAGE_YOUNG); 1188c2ecf20Sopenharmony_ci#ifdef CONFIG_MEM_SOFT_DIRTY 1198c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_SOFT_DIRTY, 1208c2ecf20Sopenharmony_ci _PAGE_SOFT_DIRTY); 1218c2ecf20Sopenharmony_ci#endif 1228c2ecf20Sopenharmony_ci pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_NOEXEC, 1238c2ecf20Sopenharmony_ci _PAGE_NOEXEC); 1248c2ecf20Sopenharmony_ci } else 1258c2ecf20Sopenharmony_ci pte_val(pte) = _PAGE_INVALID; 1268c2ecf20Sopenharmony_ci return pte; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void clear_huge_pte_skeys(struct mm_struct *mm, unsigned long rste) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct page *page; 1328c2ecf20Sopenharmony_ci unsigned long size, paddr; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!mm_uses_skeys(mm) || 1358c2ecf20Sopenharmony_ci rste & _SEGMENT_ENTRY_INVALID) 1368c2ecf20Sopenharmony_ci return; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) { 1398c2ecf20Sopenharmony_ci page = pud_page(__pud(rste)); 1408c2ecf20Sopenharmony_ci size = PUD_SIZE; 1418c2ecf20Sopenharmony_ci paddr = rste & PUD_MASK; 1428c2ecf20Sopenharmony_ci } else { 1438c2ecf20Sopenharmony_ci page = pmd_page(__pmd(rste)); 1448c2ecf20Sopenharmony_ci size = PMD_SIZE; 1458c2ecf20Sopenharmony_ci paddr = rste & PMD_MASK; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (!test_and_set_bit(PG_arch_1, &page->flags)) 1498c2ecf20Sopenharmony_ci __storage_key_init_range(paddr, paddr + size - 1); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_civoid set_huge_pte_at(struct mm_struct *mm, unsigned long addr, 1538c2ecf20Sopenharmony_ci pte_t *ptep, pte_t pte) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci unsigned long rste; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci rste = __pte_to_rste(pte); 1588c2ecf20Sopenharmony_ci if (!MACHINE_HAS_NX) 1598c2ecf20Sopenharmony_ci rste &= ~_SEGMENT_ENTRY_NOEXEC; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Set correct table type for 2G hugepages */ 1628c2ecf20Sopenharmony_ci if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) { 1638c2ecf20Sopenharmony_ci if (likely(pte_present(pte))) 1648c2ecf20Sopenharmony_ci rste |= _REGION3_ENTRY_LARGE; 1658c2ecf20Sopenharmony_ci rste |= _REGION_ENTRY_TYPE_R3; 1668c2ecf20Sopenharmony_ci } else if (likely(pte_present(pte))) 1678c2ecf20Sopenharmony_ci rste |= _SEGMENT_ENTRY_LARGE; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci clear_huge_pte_skeys(mm, rste); 1708c2ecf20Sopenharmony_ci pte_val(*ptep) = rste; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cipte_t huge_ptep_get(pte_t *ptep) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci return __rste_to_pte(pte_val(*ptep)); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cipte_t huge_ptep_get_and_clear(struct mm_struct *mm, 1798c2ecf20Sopenharmony_ci unsigned long addr, pte_t *ptep) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci pte_t pte = huge_ptep_get(ptep); 1828c2ecf20Sopenharmony_ci pmd_t *pmdp = (pmd_t *) ptep; 1838c2ecf20Sopenharmony_ci pud_t *pudp = (pud_t *) ptep; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) 1868c2ecf20Sopenharmony_ci pudp_xchg_direct(mm, addr, pudp, __pud(_REGION3_ENTRY_EMPTY)); 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY)); 1898c2ecf20Sopenharmony_ci return pte; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cipte_t *huge_pte_alloc(struct mm_struct *mm, 1938c2ecf20Sopenharmony_ci unsigned long addr, unsigned long sz) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci pgd_t *pgdp; 1968c2ecf20Sopenharmony_ci p4d_t *p4dp; 1978c2ecf20Sopenharmony_ci pud_t *pudp; 1988c2ecf20Sopenharmony_ci pmd_t *pmdp = NULL; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci pgdp = pgd_offset(mm, addr); 2018c2ecf20Sopenharmony_ci p4dp = p4d_alloc(mm, pgdp, addr); 2028c2ecf20Sopenharmony_ci if (p4dp) { 2038c2ecf20Sopenharmony_ci pudp = pud_alloc(mm, p4dp, addr); 2048c2ecf20Sopenharmony_ci if (pudp) { 2058c2ecf20Sopenharmony_ci if (sz == PUD_SIZE) 2068c2ecf20Sopenharmony_ci return (pte_t *) pudp; 2078c2ecf20Sopenharmony_ci else if (sz == PMD_SIZE) 2088c2ecf20Sopenharmony_ci pmdp = pmd_alloc(mm, pudp, addr); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci return (pte_t *) pmdp; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cipte_t *huge_pte_offset(struct mm_struct *mm, 2158c2ecf20Sopenharmony_ci unsigned long addr, unsigned long sz) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci pgd_t *pgdp; 2188c2ecf20Sopenharmony_ci p4d_t *p4dp; 2198c2ecf20Sopenharmony_ci pud_t *pudp; 2208c2ecf20Sopenharmony_ci pmd_t *pmdp = NULL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci pgdp = pgd_offset(mm, addr); 2238c2ecf20Sopenharmony_ci if (pgd_present(*pgdp)) { 2248c2ecf20Sopenharmony_ci p4dp = p4d_offset(pgdp, addr); 2258c2ecf20Sopenharmony_ci if (p4d_present(*p4dp)) { 2268c2ecf20Sopenharmony_ci pudp = pud_offset(p4dp, addr); 2278c2ecf20Sopenharmony_ci if (pud_present(*pudp)) { 2288c2ecf20Sopenharmony_ci if (pud_large(*pudp)) 2298c2ecf20Sopenharmony_ci return (pte_t *) pudp; 2308c2ecf20Sopenharmony_ci pmdp = pmd_offset(pudp, addr); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci return (pte_t *) pmdp; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint pmd_huge(pmd_t pmd) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci return pmd_large(pmd); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciint pud_huge(pud_t pud) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci return pud_large(pud); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct page * 2488c2ecf20Sopenharmony_cifollow_huge_pud(struct mm_struct *mm, unsigned long address, 2498c2ecf20Sopenharmony_ci pud_t *pud, int flags) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci if (flags & FOLL_GET) 2528c2ecf20Sopenharmony_ci return NULL; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return pud_page(*pud) + ((address & ~PUD_MASK) >> PAGE_SHIFT); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cibool __init arch_hugetlb_valid_size(unsigned long size) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci if (MACHINE_HAS_EDAT1 && size == PMD_SIZE) 2608c2ecf20Sopenharmony_ci return true; 2618c2ecf20Sopenharmony_ci else if (MACHINE_HAS_EDAT2 && size == PUD_SIZE) 2628c2ecf20Sopenharmony_ci return true; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci return false; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, 2688c2ecf20Sopenharmony_ci unsigned long addr, unsigned long len, 2698c2ecf20Sopenharmony_ci unsigned long pgoff, unsigned long flags) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct hstate *h = hstate_file(file); 2728c2ecf20Sopenharmony_ci struct vm_unmapped_area_info info; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci info.flags = 0; 2758c2ecf20Sopenharmony_ci info.length = len; 2768c2ecf20Sopenharmony_ci info.low_limit = current->mm->mmap_base; 2778c2ecf20Sopenharmony_ci info.high_limit = TASK_SIZE; 2788c2ecf20Sopenharmony_ci info.align_mask = PAGE_MASK & ~huge_page_mask(h); 2798c2ecf20Sopenharmony_ci info.align_offset = 0; 2808c2ecf20Sopenharmony_ci return vm_unmapped_area(&info); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, 2848c2ecf20Sopenharmony_ci unsigned long addr0, unsigned long len, 2858c2ecf20Sopenharmony_ci unsigned long pgoff, unsigned long flags) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct hstate *h = hstate_file(file); 2888c2ecf20Sopenharmony_ci struct vm_unmapped_area_info info; 2898c2ecf20Sopenharmony_ci unsigned long addr; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci info.flags = VM_UNMAPPED_AREA_TOPDOWN; 2928c2ecf20Sopenharmony_ci info.length = len; 2938c2ecf20Sopenharmony_ci info.low_limit = max(PAGE_SIZE, mmap_min_addr); 2948c2ecf20Sopenharmony_ci info.high_limit = current->mm->mmap_base; 2958c2ecf20Sopenharmony_ci info.align_mask = PAGE_MASK & ~huge_page_mask(h); 2968c2ecf20Sopenharmony_ci info.align_offset = 0; 2978c2ecf20Sopenharmony_ci addr = vm_unmapped_area(&info); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * A failed mmap() very likely causes application failure, 3018c2ecf20Sopenharmony_ci * so fall back to the bottom-up function here. This scenario 3028c2ecf20Sopenharmony_ci * can happen with large stack limits and large mmap() 3038c2ecf20Sopenharmony_ci * allocations. 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci if (addr & ~PAGE_MASK) { 3068c2ecf20Sopenharmony_ci VM_BUG_ON(addr != -ENOMEM); 3078c2ecf20Sopenharmony_ci info.flags = 0; 3088c2ecf20Sopenharmony_ci info.low_limit = TASK_UNMAPPED_BASE; 3098c2ecf20Sopenharmony_ci info.high_limit = TASK_SIZE; 3108c2ecf20Sopenharmony_ci addr = vm_unmapped_area(&info); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return addr; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciunsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, 3178c2ecf20Sopenharmony_ci unsigned long len, unsigned long pgoff, unsigned long flags) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct hstate *h = hstate_file(file); 3208c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 3218c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (len & ~huge_page_mask(h)) 3248c2ecf20Sopenharmony_ci return -EINVAL; 3258c2ecf20Sopenharmony_ci if (len > TASK_SIZE - mmap_min_addr) 3268c2ecf20Sopenharmony_ci return -ENOMEM; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (flags & MAP_FIXED) { 3298c2ecf20Sopenharmony_ci if (prepare_hugepage_range(file, addr, len)) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci goto check_asce_limit; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (addr) { 3358c2ecf20Sopenharmony_ci addr = ALIGN(addr, huge_page_size(h)); 3368c2ecf20Sopenharmony_ci vma = find_vma(mm, addr); 3378c2ecf20Sopenharmony_ci if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && 3388c2ecf20Sopenharmony_ci (!vma || addr + len <= vm_start_gap(vma))) 3398c2ecf20Sopenharmony_ci goto check_asce_limit; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (mm->get_unmapped_area == arch_get_unmapped_area) 3438c2ecf20Sopenharmony_ci addr = hugetlb_get_unmapped_area_bottomup(file, addr, len, 3448c2ecf20Sopenharmony_ci pgoff, flags); 3458c2ecf20Sopenharmony_ci else 3468c2ecf20Sopenharmony_ci addr = hugetlb_get_unmapped_area_topdown(file, addr, len, 3478c2ecf20Sopenharmony_ci pgoff, flags); 3488c2ecf20Sopenharmony_ci if (offset_in_page(addr)) 3498c2ecf20Sopenharmony_ci return addr; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cicheck_asce_limit: 3528c2ecf20Sopenharmony_ci return check_asce_limit(mm, addr, len); 3538c2ecf20Sopenharmony_ci} 354