1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2ad757b6aSThomas Gleixner /*
3ad757b6aSThomas Gleixner * IA-32 Huge TLB Page Support for Kernel.
4ad757b6aSThomas Gleixner *
5ad757b6aSThomas Gleixner * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com>
6ad757b6aSThomas Gleixner */
7ad757b6aSThomas Gleixner
8ad757b6aSThomas Gleixner #include <linux/init.h>
9ad757b6aSThomas Gleixner #include <linux/fs.h>
10ad757b6aSThomas Gleixner #include <linux/mm.h>
1101042607SIngo Molnar #include <linux/sched/mm.h>
12ad757b6aSThomas Gleixner #include <linux/hugetlb.h>
13ad757b6aSThomas Gleixner #include <linux/pagemap.h>
14ad757b6aSThomas Gleixner #include <linux/err.h>
15ad757b6aSThomas Gleixner #include <linux/sysctl.h>
16e13b73ddSDmitry Safonov #include <linux/compat.h>
17ad757b6aSThomas Gleixner #include <asm/mman.h>
18ad757b6aSThomas Gleixner #include <asm/tlb.h>
19ad757b6aSThomas Gleixner #include <asm/tlbflush.h>
20e13b73ddSDmitry Safonov #include <asm/elf.h>
21ad757b6aSThomas Gleixner
22cbef8478SNaoya Horiguchi /*
23cbef8478SNaoya Horiguchi * pmd_huge() returns 1 if @pmd is hugetlb related entry, that is normal
24cbef8478SNaoya Horiguchi * hugetlb entry or non-present (migration or hwpoisoned) hugetlb entry.
25cbef8478SNaoya Horiguchi * Otherwise, returns 0.
26cbef8478SNaoya Horiguchi */
pmd_huge(pmd_t pmd)27ad757b6aSThomas Gleixner int pmd_huge(pmd_t pmd)
28ad757b6aSThomas Gleixner {
29cbef8478SNaoya Horiguchi return !pmd_none(pmd) &&
30cbef8478SNaoya Horiguchi (pmd_val(pmd) & (_PAGE_PRESENT|_PAGE_PSE)) != _PAGE_PRESENT;
31ad757b6aSThomas Gleixner }
32ad757b6aSThomas Gleixner
333a194f3fSNaoya Horiguchi /*
343a194f3fSNaoya Horiguchi * pud_huge() returns 1 if @pud is hugetlb related entry, that is normal
353a194f3fSNaoya Horiguchi * hugetlb entry or non-present (migration or hwpoisoned) hugetlb entry.
363a194f3fSNaoya Horiguchi * Otherwise, returns 0.
373a194f3fSNaoya Horiguchi */
pud_huge(pud_t pud)38ceb86879SAndi Kleen int pud_huge(pud_t pud)
39ceb86879SAndi Kleen {
40*1fdbed65SNaoya Horiguchi #if CONFIG_PGTABLE_LEVELS > 2
413a194f3fSNaoya Horiguchi return !pud_none(pud) &&
423a194f3fSNaoya Horiguchi (pud_val(pud) & (_PAGE_PRESENT|_PAGE_PSE)) != _PAGE_PRESENT;
43*1fdbed65SNaoya Horiguchi #else
44*1fdbed65SNaoya Horiguchi return 0;
45*1fdbed65SNaoya Horiguchi #endif
46ceb86879SAndi Kleen }
47ad757b6aSThomas Gleixner
48fd8526adSKirill A. Shutemov #ifdef CONFIG_HUGETLB_PAGE
hugetlb_get_unmapped_area_bottomup(struct file * file,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)49ad757b6aSThomas Gleixner static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file,
50ad757b6aSThomas Gleixner unsigned long addr, unsigned long len,
51ad757b6aSThomas Gleixner unsigned long pgoff, unsigned long flags)
52ad757b6aSThomas Gleixner {
5339c11e6cSAndi Kleen struct hstate *h = hstate_file(file);
54cdc17344SMichel Lespinasse struct vm_unmapped_area_info info;
55ad757b6aSThomas Gleixner
56cdc17344SMichel Lespinasse info.flags = 0;
57cdc17344SMichel Lespinasse info.length = len;
58e13b73ddSDmitry Safonov info.low_limit = get_mmap_base(1);
59b569bab7SKirill A. Shutemov
60b569bab7SKirill A. Shutemov /*
61b569bab7SKirill A. Shutemov * If hint address is above DEFAULT_MAP_WINDOW, look for unmapped area
62b569bab7SKirill A. Shutemov * in the full address space.
63b569bab7SKirill A. Shutemov */
64a846446bSDmitry Safonov info.high_limit = in_32bit_syscall() ?
65b569bab7SKirill A. Shutemov task_size_32bit() : task_size_64bit(addr > DEFAULT_MAP_WINDOW);
66b569bab7SKirill A. Shutemov
67cdc17344SMichel Lespinasse info.align_mask = PAGE_MASK & ~huge_page_mask(h);
68cdc17344SMichel Lespinasse info.align_offset = 0;
69cdc17344SMichel Lespinasse return vm_unmapped_area(&info);
70ad757b6aSThomas Gleixner }
71ad757b6aSThomas Gleixner
hugetlb_get_unmapped_area_topdown(struct file * file,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)72ad757b6aSThomas Gleixner static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
73b569bab7SKirill A. Shutemov unsigned long addr, unsigned long len,
74ad757b6aSThomas Gleixner unsigned long pgoff, unsigned long flags)
75ad757b6aSThomas Gleixner {
7639c11e6cSAndi Kleen struct hstate *h = hstate_file(file);
77cdc17344SMichel Lespinasse struct vm_unmapped_area_info info;
78ad757b6aSThomas Gleixner
79cdc17344SMichel Lespinasse info.flags = VM_UNMAPPED_AREA_TOPDOWN;
80cdc17344SMichel Lespinasse info.length = len;
81cdc17344SMichel Lespinasse info.low_limit = PAGE_SIZE;
82e13b73ddSDmitry Safonov info.high_limit = get_mmap_base(0);
83b569bab7SKirill A. Shutemov
84b569bab7SKirill A. Shutemov /*
85b569bab7SKirill A. Shutemov * If hint address is above DEFAULT_MAP_WINDOW, look for unmapped area
86b569bab7SKirill A. Shutemov * in the full address space.
87b569bab7SKirill A. Shutemov */
88a846446bSDmitry Safonov if (addr > DEFAULT_MAP_WINDOW && !in_32bit_syscall())
89b569bab7SKirill A. Shutemov info.high_limit += TASK_SIZE_MAX - DEFAULT_MAP_WINDOW;
90b569bab7SKirill A. Shutemov
91cdc17344SMichel Lespinasse info.align_mask = PAGE_MASK & ~huge_page_mask(h);
92cdc17344SMichel Lespinasse info.align_offset = 0;
93cdc17344SMichel Lespinasse addr = vm_unmapped_area(&info);
94ad757b6aSThomas Gleixner
95ad757b6aSThomas Gleixner /*
96ad757b6aSThomas Gleixner * A failed mmap() very likely causes application failure,
97ad757b6aSThomas Gleixner * so fall back to the bottom-up function here. This scenario
98ad757b6aSThomas Gleixner * can happen with large stack limits and large mmap()
99ad757b6aSThomas Gleixner * allocations.
100ad757b6aSThomas Gleixner */
101cdc17344SMichel Lespinasse if (addr & ~PAGE_MASK) {
102cdc17344SMichel Lespinasse VM_BUG_ON(addr != -ENOMEM);
103cdc17344SMichel Lespinasse info.flags = 0;
104cdc17344SMichel Lespinasse info.low_limit = TASK_UNMAPPED_BASE;
105b569bab7SKirill A. Shutemov info.high_limit = TASK_SIZE_LOW;
106cdc17344SMichel Lespinasse addr = vm_unmapped_area(&info);
107cdc17344SMichel Lespinasse }
108ad757b6aSThomas Gleixner
109ad757b6aSThomas Gleixner return addr;
110ad757b6aSThomas Gleixner }
111ad757b6aSThomas Gleixner
112ad757b6aSThomas Gleixner unsigned long
hugetlb_get_unmapped_area(struct file * file,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)113ad757b6aSThomas Gleixner hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
114ad757b6aSThomas Gleixner unsigned long len, unsigned long pgoff, unsigned long flags)
115ad757b6aSThomas Gleixner {
11639c11e6cSAndi Kleen struct hstate *h = hstate_file(file);
117ad757b6aSThomas Gleixner struct mm_struct *mm = current->mm;
118ad757b6aSThomas Gleixner struct vm_area_struct *vma;
119ad757b6aSThomas Gleixner
12039c11e6cSAndi Kleen if (len & ~huge_page_mask(h))
121ad757b6aSThomas Gleixner return -EINVAL;
12244b04912SKirill A. Shutemov
123ad757b6aSThomas Gleixner if (len > TASK_SIZE)
124ad757b6aSThomas Gleixner return -ENOMEM;
125ad757b6aSThomas Gleixner
1261e0f25dbSKirill A. Shutemov /* No address checking. See comment at mmap_address_hint_valid() */
127ad757b6aSThomas Gleixner if (flags & MAP_FIXED) {
128a5516438SAndi Kleen if (prepare_hugepage_range(file, addr, len))
129ad757b6aSThomas Gleixner return -EINVAL;
130ad757b6aSThomas Gleixner return addr;
131ad757b6aSThomas Gleixner }
132ad757b6aSThomas Gleixner
133ad757b6aSThomas Gleixner if (addr) {
1341e0f25dbSKirill A. Shutemov addr &= huge_page_mask(h);
1351e0f25dbSKirill A. Shutemov if (!mmap_address_hint_valid(addr, len))
1361e0f25dbSKirill A. Shutemov goto get_unmapped_area;
1371e0f25dbSKirill A. Shutemov
138ad757b6aSThomas Gleixner vma = find_vma(mm, addr);
1391e0f25dbSKirill A. Shutemov if (!vma || addr + len <= vm_start_gap(vma))
140ad757b6aSThomas Gleixner return addr;
141ad757b6aSThomas Gleixner }
1421e0f25dbSKirill A. Shutemov
1431e0f25dbSKirill A. Shutemov get_unmapped_area:
144ad757b6aSThomas Gleixner if (mm->get_unmapped_area == arch_get_unmapped_area)
145ad757b6aSThomas Gleixner return hugetlb_get_unmapped_area_bottomup(file, addr, len,
146ad757b6aSThomas Gleixner pgoff, flags);
147ad757b6aSThomas Gleixner else
148ad757b6aSThomas Gleixner return hugetlb_get_unmapped_area_topdown(file, addr, len,
149ad757b6aSThomas Gleixner pgoff, flags);
150ad757b6aSThomas Gleixner }
151fd8526adSKirill A. Shutemov #endif /* CONFIG_HUGETLB_PAGE */
152ad757b6aSThomas Gleixner
153b4718e62SAndi Kleen #ifdef CONFIG_X86_64
arch_hugetlb_valid_size(unsigned long size)154ae94da89SMike Kravetz bool __init arch_hugetlb_valid_size(unsigned long size)
155ae94da89SMike Kravetz {
156ae94da89SMike Kravetz if (size == PMD_SIZE)
157ae94da89SMike Kravetz return true;
158ae94da89SMike Kravetz else if (size == PUD_SIZE && boot_cpu_has(X86_FEATURE_GBPAGES))
159ae94da89SMike Kravetz return true;
160ae94da89SMike Kravetz else
161ae94da89SMike Kravetz return false;
162ae94da89SMike Kravetz }
163ae94da89SMike Kravetz
1648df995f6SAlexandre Ghiti #ifdef CONFIG_CONTIG_ALLOC
gigantic_pages_init(void)165ece84b39SKirill A. Shutemov static __init int gigantic_pages_init(void)
166ece84b39SKirill A. Shutemov {
167080fe206SVlastimil Babka /* With compaction or CMA we can allocate gigantic pages at runtime */
16838237830SMike Kravetz if (boot_cpu_has(X86_FEATURE_GBPAGES))
169ece84b39SKirill A. Shutemov hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
170ece84b39SKirill A. Shutemov return 0;
171ece84b39SKirill A. Shutemov }
172ece84b39SKirill A. Shutemov arch_initcall(gigantic_pages_init);
173ece84b39SKirill A. Shutemov #endif
174b4718e62SAndi Kleen #endif
175