xref: /linux/arch/x86/mm/init_32.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ad757b6aSThomas Gleixner /*
3ad757b6aSThomas Gleixner  *
4ad757b6aSThomas Gleixner  *  Copyright (C) 1995  Linus Torvalds
5ad757b6aSThomas Gleixner  *
6ad757b6aSThomas Gleixner  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
7ad757b6aSThomas Gleixner  */
8ad757b6aSThomas Gleixner 
9ad757b6aSThomas Gleixner #include <linux/signal.h>
10ad757b6aSThomas Gleixner #include <linux/sched.h>
11ad757b6aSThomas Gleixner #include <linux/kernel.h>
12ad757b6aSThomas Gleixner #include <linux/errno.h>
13ad757b6aSThomas Gleixner #include <linux/string.h>
14ad757b6aSThomas Gleixner #include <linux/types.h>
15ad757b6aSThomas Gleixner #include <linux/ptrace.h>
16ad757b6aSThomas Gleixner #include <linux/mman.h>
17ad757b6aSThomas Gleixner #include <linux/mm.h>
18ad757b6aSThomas Gleixner #include <linux/hugetlb.h>
19ad757b6aSThomas Gleixner #include <linux/swap.h>
20ad757b6aSThomas Gleixner #include <linux/smp.h>
21ad757b6aSThomas Gleixner #include <linux/init.h>
22ad757b6aSThomas Gleixner #include <linux/highmem.h>
23ad757b6aSThomas Gleixner #include <linux/pagemap.h>
24cfb80c9eSJeremy Fitzhardinge #include <linux/pci.h>
25ad757b6aSThomas Gleixner #include <linux/pfn.h>
26ad757b6aSThomas Gleixner #include <linux/poison.h>
27a9ce6bc1SYinghai Lu #include <linux/memblock.h>
28ad757b6aSThomas Gleixner #include <linux/proc_fs.h>
29ad757b6aSThomas Gleixner #include <linux/memory_hotplug.h>
30ad757b6aSThomas Gleixner #include <linux/initrd.h>
31ad757b6aSThomas Gleixner #include <linux/cpumask.h>
325a0e3ad6STejun Heo #include <linux/gfp.h>
33ad757b6aSThomas Gleixner 
34f832ff18SH. Peter Anvin #include <asm/asm.h>
3546eaa670SIngo Molnar #include <asm/bios_ebda.h>
36ad757b6aSThomas Gleixner #include <asm/processor.h>
377c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
38ad757b6aSThomas Gleixner #include <asm/dma.h>
39ad757b6aSThomas Gleixner #include <asm/fixmap.h>
4066441bd3SIngo Molnar #include <asm/e820/api.h>
41ad757b6aSThomas Gleixner #include <asm/apic.h>
428550eb99SIngo Molnar #include <asm/bugs.h>
43ad757b6aSThomas Gleixner #include <asm/tlb.h>
44ad757b6aSThomas Gleixner #include <asm/tlbflush.h>
45c10d1e26SAndres Salomon #include <asm/olpc_ofw.h>
46a5a19c63SJeremy Fitzhardinge #include <asm/pgalloc.h>
47ad757b6aSThomas Gleixner #include <asm/sections.h>
48551889a6SIan Campbell #include <asm/setup.h>
49d1163651SLaura Abbott #include <asm/set_memory.h>
502b72394eSPekka Enberg #include <asm/page_types.h>
5192a0f81dSThomas Gleixner #include <asm/cpu_entry_area.h>
524fcb2083SPekka Enberg #include <asm/init.h>
53186525bdSIngo Molnar #include <asm/pgtable_areas.h>
540cd39f46SPeter Zijlstra #include <asm/numa.h>
55ad757b6aSThomas Gleixner 
565c51bdbeSYinghai Lu #include "mm_internal.h"
575c51bdbeSYinghai Lu 
58ad757b6aSThomas Gleixner unsigned long highstart_pfn, highend_pfn;
59ad757b6aSThomas Gleixner 
60dc16ecf7SJeremy Fitzhardinge bool __read_mostly __vmalloc_start_set = false;
614e29684cSYinghai Lu 
62ad757b6aSThomas Gleixner /*
63ad757b6aSThomas Gleixner  * Creates a middle page table and puts a pointer to it in the
64ad757b6aSThomas Gleixner  * given global directory entry. This only returns the gd entry
65ad757b6aSThomas Gleixner  * in non-PAE compilation mode, since the middle layer is folded.
66ad757b6aSThomas Gleixner  */
one_md_table_init(pgd_t * pgd)67ad757b6aSThomas Gleixner static pmd_t * __init one_md_table_init(pgd_t *pgd)
68ad757b6aSThomas Gleixner {
69e0c4f675SKirill A. Shutemov 	p4d_t *p4d;
70ad757b6aSThomas Gleixner 	pud_t *pud;
71ad757b6aSThomas Gleixner 	pmd_t *pmd_table;
72ad757b6aSThomas Gleixner 
73ad757b6aSThomas Gleixner #ifdef CONFIG_X86_PAE
74ad757b6aSThomas Gleixner 	if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
75d6be89adSJan Beulich 		pmd_table = (pmd_t *)alloc_low_page();
76ad757b6aSThomas Gleixner 		set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
77e0c4f675SKirill A. Shutemov 		p4d = p4d_offset(pgd, 0);
78e0c4f675SKirill A. Shutemov 		pud = pud_offset(p4d, 0);
798550eb99SIngo Molnar 		BUG_ON(pmd_table != pmd_offset(pud, 0));
80a376f30aSZhaolei 
81a376f30aSZhaolei 		return pmd_table;
82ad757b6aSThomas Gleixner 	}
83ad757b6aSThomas Gleixner #endif
84e0c4f675SKirill A. Shutemov 	p4d = p4d_offset(pgd, 0);
85e0c4f675SKirill A. Shutemov 	pud = pud_offset(p4d, 0);
86ad757b6aSThomas Gleixner 	pmd_table = pmd_offset(pud, 0);
878550eb99SIngo Molnar 
88ad757b6aSThomas Gleixner 	return pmd_table;
89ad757b6aSThomas Gleixner }
90ad757b6aSThomas Gleixner 
91ad757b6aSThomas Gleixner /*
92ad757b6aSThomas Gleixner  * Create a page table and place a pointer to it in a middle page
938550eb99SIngo Molnar  * directory entry:
94ad757b6aSThomas Gleixner  */
one_page_table_init(pmd_t * pmd)95ad757b6aSThomas Gleixner static pte_t * __init one_page_table_init(pmd_t *pmd)
96ad757b6aSThomas Gleixner {
97ad757b6aSThomas Gleixner 	if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
984e37a890SYinghai Lu 		pte_t *page_table = (pte_t *)alloc_low_page();
99ad757b6aSThomas Gleixner 
100ad757b6aSThomas Gleixner 		set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
101ad757b6aSThomas Gleixner 		BUG_ON(page_table != pte_offset_kernel(pmd, 0));
102ad757b6aSThomas Gleixner 	}
103ad757b6aSThomas Gleixner 
104ad757b6aSThomas Gleixner 	return pte_offset_kernel(pmd, 0);
105ad757b6aSThomas Gleixner }
106ad757b6aSThomas Gleixner 
populate_extra_pmd(unsigned long vaddr)107458a3e64STejun Heo pmd_t * __init populate_extra_pmd(unsigned long vaddr)
10811124411STejun Heo {
10911124411STejun Heo 	int pgd_idx = pgd_index(vaddr);
11011124411STejun Heo 	int pmd_idx = pmd_index(vaddr);
111458a3e64STejun Heo 
112458a3e64STejun Heo 	return one_md_table_init(swapper_pg_dir + pgd_idx) + pmd_idx;
113458a3e64STejun Heo }
114458a3e64STejun Heo 
populate_extra_pte(unsigned long vaddr)115458a3e64STejun Heo pte_t * __init populate_extra_pte(unsigned long vaddr)
116458a3e64STejun Heo {
117458a3e64STejun Heo 	int pte_idx = pte_index(vaddr);
11811124411STejun Heo 	pmd_t *pmd;
11911124411STejun Heo 
120458a3e64STejun Heo 	pmd = populate_extra_pmd(vaddr);
121458a3e64STejun Heo 	return one_page_table_init(pmd) + pte_idx;
12211124411STejun Heo }
12311124411STejun Heo 
124719272c4SYinghai Lu static unsigned long __init
page_table_range_init_count(unsigned long start,unsigned long end)125719272c4SYinghai Lu page_table_range_init_count(unsigned long start, unsigned long end)
126719272c4SYinghai Lu {
127719272c4SYinghai Lu 	unsigned long count = 0;
128719272c4SYinghai Lu #ifdef CONFIG_HIGHMEM
129719272c4SYinghai Lu 	int pmd_idx_kmap_begin = fix_to_virt(FIX_KMAP_END) >> PMD_SHIFT;
130719272c4SYinghai Lu 	int pmd_idx_kmap_end = fix_to_virt(FIX_KMAP_BEGIN) >> PMD_SHIFT;
131719272c4SYinghai Lu 	int pgd_idx, pmd_idx;
132719272c4SYinghai Lu 	unsigned long vaddr;
133719272c4SYinghai Lu 
134719272c4SYinghai Lu 	if (pmd_idx_kmap_begin == pmd_idx_kmap_end)
135719272c4SYinghai Lu 		return 0;
136719272c4SYinghai Lu 
137719272c4SYinghai Lu 	vaddr = start;
138719272c4SYinghai Lu 	pgd_idx = pgd_index(vaddr);
1399962eea9SMinfei Huang 	pmd_idx = pmd_index(vaddr);
140719272c4SYinghai Lu 
141719272c4SYinghai Lu 	for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd_idx++) {
142719272c4SYinghai Lu 		for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end);
143719272c4SYinghai Lu 							pmd_idx++) {
144719272c4SYinghai Lu 			if ((vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin &&
145719272c4SYinghai Lu 			    (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end)
146719272c4SYinghai Lu 				count++;
147719272c4SYinghai Lu 			vaddr += PMD_SIZE;
148719272c4SYinghai Lu 		}
149719272c4SYinghai Lu 		pmd_idx = 0;
150719272c4SYinghai Lu 	}
151719272c4SYinghai Lu #endif
152719272c4SYinghai Lu 	return count;
153719272c4SYinghai Lu }
154719272c4SYinghai Lu 
page_table_kmap_check(pte_t * pte,pmd_t * pmd,unsigned long vaddr,pte_t * lastpte,void ** adr)155a3c6018eSJan Beulich static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
156719272c4SYinghai Lu 					   unsigned long vaddr, pte_t *lastpte,
157719272c4SYinghai Lu 					   void **adr)
158a3c6018eSJan Beulich {
159a3c6018eSJan Beulich #ifdef CONFIG_HIGHMEM
160a3c6018eSJan Beulich 	/*
161a3c6018eSJan Beulich 	 * Something (early fixmap) may already have put a pte
162a3c6018eSJan Beulich 	 * page here, which causes the page table allocation
163a3c6018eSJan Beulich 	 * to become nonlinear. Attempt to fix it, and if it
164a3c6018eSJan Beulich 	 * is still nonlinear then we have to bug.
165a3c6018eSJan Beulich 	 */
166a3c6018eSJan Beulich 	int pmd_idx_kmap_begin = fix_to_virt(FIX_KMAP_END) >> PMD_SHIFT;
167a3c6018eSJan Beulich 	int pmd_idx_kmap_end = fix_to_virt(FIX_KMAP_BEGIN) >> PMD_SHIFT;
168a3c6018eSJan Beulich 
169a3c6018eSJan Beulich 	if (pmd_idx_kmap_begin != pmd_idx_kmap_end
170a3c6018eSJan Beulich 	    && (vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin
171719272c4SYinghai Lu 	    && (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end) {
172a3c6018eSJan Beulich 		pte_t *newpte;
173a3c6018eSJan Beulich 		int i;
174a3c6018eSJan Beulich 
175c464573cSPekka Enberg 		BUG_ON(after_bootmem);
176719272c4SYinghai Lu 		newpte = *adr;
177a3c6018eSJan Beulich 		for (i = 0; i < PTRS_PER_PTE; i++)
178a3c6018eSJan Beulich 			set_pte(newpte + i, pte[i]);
179719272c4SYinghai Lu 		*adr = (void *)(((unsigned long)(*adr)) + PAGE_SIZE);
180a3c6018eSJan Beulich 
181a3c6018eSJan Beulich 		set_pmd(pmd, __pmd(__pa(newpte)|_PAGE_TABLE));
182a3c6018eSJan Beulich 		BUG_ON(newpte != pte_offset_kernel(pmd, 0));
183a3c6018eSJan Beulich 		__flush_tlb_all();
184a3c6018eSJan Beulich 
185a3c6018eSJan Beulich 		pte = newpte;
186a3c6018eSJan Beulich 	}
187a3c6018eSJan Beulich 	BUG_ON(vaddr < fix_to_virt(FIX_KMAP_BEGIN - 1)
188a3c6018eSJan Beulich 	       && vaddr > fix_to_virt(FIX_KMAP_END)
189a3c6018eSJan Beulich 	       && lastpte && lastpte + PTRS_PER_PTE != pte);
190a3c6018eSJan Beulich #endif
191a3c6018eSJan Beulich 	return pte;
192a3c6018eSJan Beulich }
193a3c6018eSJan Beulich 
194ad757b6aSThomas Gleixner /*
195ad757b6aSThomas Gleixner  * This function initializes a certain range of kernel virtual memory
196ad757b6aSThomas Gleixner  * with new bootmem page tables, everywhere page tables are missing in
197ad757b6aSThomas Gleixner  * the given range.
1988550eb99SIngo Molnar  *
199ad757b6aSThomas Gleixner  * NOTE: The pagetables are allocated contiguous on the physical space
200ad757b6aSThomas Gleixner  * so we can cache the place of the first one and move around without
201ad757b6aSThomas Gleixner  * checking the pgd every time.
202ad757b6aSThomas Gleixner  */
2038550eb99SIngo Molnar static void __init
page_table_range_init(unsigned long start,unsigned long end,pgd_t * pgd_base)2048550eb99SIngo Molnar page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base)
205ad757b6aSThomas Gleixner {
206ad757b6aSThomas Gleixner 	int pgd_idx, pmd_idx;
207ad757b6aSThomas Gleixner 	unsigned long vaddr;
2088550eb99SIngo Molnar 	pgd_t *pgd;
2098550eb99SIngo Molnar 	pmd_t *pmd;
210a3c6018eSJan Beulich 	pte_t *pte = NULL;
211719272c4SYinghai Lu 	unsigned long count = page_table_range_init_count(start, end);
212719272c4SYinghai Lu 	void *adr = NULL;
213719272c4SYinghai Lu 
214719272c4SYinghai Lu 	if (count)
215719272c4SYinghai Lu 		adr = alloc_low_pages(count);
216ad757b6aSThomas Gleixner 
217ad757b6aSThomas Gleixner 	vaddr = start;
218ad757b6aSThomas Gleixner 	pgd_idx = pgd_index(vaddr);
219ad757b6aSThomas Gleixner 	pmd_idx = pmd_index(vaddr);
220ad757b6aSThomas Gleixner 	pgd = pgd_base + pgd_idx;
221ad757b6aSThomas Gleixner 
222ad757b6aSThomas Gleixner 	for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
223ad757b6aSThomas Gleixner 		pmd = one_md_table_init(pgd);
224ad757b6aSThomas Gleixner 		pmd = pmd + pmd_index(vaddr);
2258550eb99SIngo Molnar 		for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end);
2268550eb99SIngo Molnar 							pmd++, pmd_idx++) {
227a3c6018eSJan Beulich 			pte = page_table_kmap_check(one_page_table_init(pmd),
228719272c4SYinghai Lu 						    pmd, vaddr, pte, &adr);
229ad757b6aSThomas Gleixner 
230ad757b6aSThomas Gleixner 			vaddr += PMD_SIZE;
231ad757b6aSThomas Gleixner 		}
232ad757b6aSThomas Gleixner 		pmd_idx = 0;
233ad757b6aSThomas Gleixner 	}
234ad757b6aSThomas Gleixner }
235ad757b6aSThomas Gleixner 
is_x86_32_kernel_text(unsigned long addr)2360a96c902SKefeng Wang static inline int is_x86_32_kernel_text(unsigned long addr)
237ad757b6aSThomas Gleixner {
2385bd5a452SMatthieu Castet 	if (addr >= (unsigned long)_text && addr <= (unsigned long)__init_end)
239ad757b6aSThomas Gleixner 		return 1;
240ad757b6aSThomas Gleixner 	return 0;
241ad757b6aSThomas Gleixner }
242ad757b6aSThomas Gleixner 
243ad757b6aSThomas Gleixner /*
244ad757b6aSThomas Gleixner  * This maps the physical memory to kernel virtual address space, a total
245ad757b6aSThomas Gleixner  * of max_low_pfn pages, by creating page tables starting from address
2468550eb99SIngo Molnar  * PAGE_OFFSET:
247ad757b6aSThomas Gleixner  */
248e53fb04fSPekka Enberg unsigned long __init
kernel_physical_mapping_init(unsigned long start,unsigned long end,unsigned long page_size_mask,pgprot_t prot)249e53fb04fSPekka Enberg kernel_physical_mapping_init(unsigned long start,
250e53fb04fSPekka Enberg 			     unsigned long end,
251c164fbb4SLogan Gunthorpe 			     unsigned long page_size_mask,
252c164fbb4SLogan Gunthorpe 			     pgprot_t prot)
253ad757b6aSThomas Gleixner {
254e53fb04fSPekka Enberg 	int use_pse = page_size_mask == (1<<PG_LEVEL_2M);
255c1fd1b43SPekka Enberg 	unsigned long last_map_addr = end;
256e53fb04fSPekka Enberg 	unsigned long start_pfn, end_pfn;
257e7179853SPekka Enberg 	pgd_t *pgd_base = swapper_pg_dir;
2588550eb99SIngo Molnar 	int pgd_idx, pmd_idx, pte_ofs;
259ad757b6aSThomas Gleixner 	unsigned long pfn;
260ad757b6aSThomas Gleixner 	pgd_t *pgd;
261ad757b6aSThomas Gleixner 	pmd_t *pmd;
262ad757b6aSThomas Gleixner 	pte_t *pte;
263a2699e47SSuresh Siddha 	unsigned pages_2m, pages_4k;
264a2699e47SSuresh Siddha 	int mapping_iter;
265a2699e47SSuresh Siddha 
266e53fb04fSPekka Enberg 	start_pfn = start >> PAGE_SHIFT;
267e53fb04fSPekka Enberg 	end_pfn = end >> PAGE_SHIFT;
268e53fb04fSPekka Enberg 
269a2699e47SSuresh Siddha 	/*
270a2699e47SSuresh Siddha 	 * First iteration will setup identity mapping using large/small pages
271a2699e47SSuresh Siddha 	 * based on use_pse, with other attributes same as set by
272a2699e47SSuresh Siddha 	 * the early code in head_32.S
273a2699e47SSuresh Siddha 	 *
274a2699e47SSuresh Siddha 	 * Second iteration will setup the appropriate attributes (NX, GLOBAL..)
275a2699e47SSuresh Siddha 	 * as desired for the kernel identity mapping.
276a2699e47SSuresh Siddha 	 *
277a2699e47SSuresh Siddha 	 * This two pass mechanism conforms to the TLB app note which says:
278a2699e47SSuresh Siddha 	 *
279a2699e47SSuresh Siddha 	 *     "Software should not write to a paging-structure entry in a way
280a2699e47SSuresh Siddha 	 *      that would change, for any linear address, both the page size
281a2699e47SSuresh Siddha 	 *      and either the page frame or attributes."
282a2699e47SSuresh Siddha 	 */
283a2699e47SSuresh Siddha 	mapping_iter = 1;
284ad757b6aSThomas Gleixner 
28516bf9226SBorislav Petkov 	if (!boot_cpu_has(X86_FEATURE_PSE))
286a04ad82dSYinghai Lu 		use_pse = 0;
287a04ad82dSYinghai Lu 
288a2699e47SSuresh Siddha repeat:
289a2699e47SSuresh Siddha 	pages_2m = pages_4k = 0;
290a04ad82dSYinghai Lu 	pfn = start_pfn;
291a04ad82dSYinghai Lu 	pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
292ad757b6aSThomas Gleixner 	pgd = pgd_base + pgd_idx;
293ad757b6aSThomas Gleixner 	for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
294ad757b6aSThomas Gleixner 		pmd = one_md_table_init(pgd);
2958550eb99SIngo Molnar 
296a04ad82dSYinghai Lu 		if (pfn >= end_pfn)
297a04ad82dSYinghai Lu 			continue;
298a04ad82dSYinghai Lu #ifdef CONFIG_X86_PAE
299a04ad82dSYinghai Lu 		pmd_idx = pmd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
300a04ad82dSYinghai Lu 		pmd += pmd_idx;
301a04ad82dSYinghai Lu #else
302a04ad82dSYinghai Lu 		pmd_idx = 0;
303a04ad82dSYinghai Lu #endif
304a04ad82dSYinghai Lu 		for (; pmd_idx < PTRS_PER_PMD && pfn < end_pfn;
305f3f20de8SJeremy Fitzhardinge 		     pmd++, pmd_idx++) {
3068550eb99SIngo Molnar 			unsigned int addr = pfn * PAGE_SIZE + PAGE_OFFSET;
307ad757b6aSThomas Gleixner 
3088550eb99SIngo Molnar 			/*
3098550eb99SIngo Molnar 			 * Map with big pages if possible, otherwise
3108550eb99SIngo Molnar 			 * create normal page tables:
3118550eb99SIngo Molnar 			 */
312a04ad82dSYinghai Lu 			if (use_pse) {
3138550eb99SIngo Molnar 				unsigned int addr2;
314f3f20de8SJeremy Fitzhardinge 				pgprot_t prot = PAGE_KERNEL_LARGE;
315a2699e47SSuresh Siddha 				/*
316a2699e47SSuresh Siddha 				 * first pass will use the same initial
317a2699e47SSuresh Siddha 				 * identity mapping attribute + _PAGE_PSE.
318a2699e47SSuresh Siddha 				 */
319a2699e47SSuresh Siddha 				pgprot_t init_prot =
320a2699e47SSuresh Siddha 					__pgprot(PTE_IDENT_ATTR |
321a2699e47SSuresh Siddha 						 _PAGE_PSE);
322f3f20de8SJeremy Fitzhardinge 
323960ddb4fSYinghai Lu 				pfn &= PMD_MASK >> PAGE_SHIFT;
3248550eb99SIngo Molnar 				addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE +
325f3f20de8SJeremy Fitzhardinge 					PAGE_OFFSET + PAGE_SIZE-1;
326f3f20de8SJeremy Fitzhardinge 
3270a96c902SKefeng Wang 				if (is_x86_32_kernel_text(addr) ||
3280a96c902SKefeng Wang 				    is_x86_32_kernel_text(addr2))
329f3f20de8SJeremy Fitzhardinge 					prot = PAGE_KERNEL_LARGE_EXEC;
330f3f20de8SJeremy Fitzhardinge 
331ce0c0e50SAndi Kleen 				pages_2m++;
332a2699e47SSuresh Siddha 				if (mapping_iter == 1)
333a2699e47SSuresh Siddha 					set_pmd(pmd, pfn_pmd(pfn, init_prot));
334a2699e47SSuresh Siddha 				else
335f3f20de8SJeremy Fitzhardinge 					set_pmd(pmd, pfn_pmd(pfn, prot));
336ad757b6aSThomas Gleixner 
337ad757b6aSThomas Gleixner 				pfn += PTRS_PER_PTE;
3388550eb99SIngo Molnar 				continue;
3398550eb99SIngo Molnar 			}
340ad757b6aSThomas Gleixner 			pte = one_page_table_init(pmd);
341ad757b6aSThomas Gleixner 
342a04ad82dSYinghai Lu 			pte_ofs = pte_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
343a04ad82dSYinghai Lu 			pte += pte_ofs;
344a04ad82dSYinghai Lu 			for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn;
3458550eb99SIngo Molnar 			     pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) {
346f3f20de8SJeremy Fitzhardinge 				pgprot_t prot = PAGE_KERNEL;
347a2699e47SSuresh Siddha 				/*
348a2699e47SSuresh Siddha 				 * first pass will use the same initial
349a2699e47SSuresh Siddha 				 * identity mapping attribute.
350a2699e47SSuresh Siddha 				 */
351a2699e47SSuresh Siddha 				pgprot_t init_prot = __pgprot(PTE_IDENT_ATTR);
352f3f20de8SJeremy Fitzhardinge 
3530a96c902SKefeng Wang 				if (is_x86_32_kernel_text(addr))
354f3f20de8SJeremy Fitzhardinge 					prot = PAGE_KERNEL_EXEC;
355f3f20de8SJeremy Fitzhardinge 
356ce0c0e50SAndi Kleen 				pages_4k++;
357c1fd1b43SPekka Enberg 				if (mapping_iter == 1) {
358a2699e47SSuresh Siddha 					set_pte(pte, pfn_pte(pfn, init_prot));
359c1fd1b43SPekka Enberg 					last_map_addr = (pfn << PAGE_SHIFT) + PAGE_SIZE;
360c1fd1b43SPekka Enberg 				} else
361f3f20de8SJeremy Fitzhardinge 					set_pte(pte, pfn_pte(pfn, prot));
362ad757b6aSThomas Gleixner 			}
363ad757b6aSThomas Gleixner 		}
364ad757b6aSThomas Gleixner 	}
365a2699e47SSuresh Siddha 	if (mapping_iter == 1) {
366a2699e47SSuresh Siddha 		/*
367a2699e47SSuresh Siddha 		 * update direct mapping page count only in the first
368a2699e47SSuresh Siddha 		 * iteration.
369a2699e47SSuresh Siddha 		 */
370ce0c0e50SAndi Kleen 		update_page_count(PG_LEVEL_2M, pages_2m);
371ce0c0e50SAndi Kleen 		update_page_count(PG_LEVEL_4K, pages_4k);
372a2699e47SSuresh Siddha 
373a2699e47SSuresh Siddha 		/*
374a2699e47SSuresh Siddha 		 * local global flush tlb, which will flush the previous
375a2699e47SSuresh Siddha 		 * mappings present in both small and large page TLB's.
376a2699e47SSuresh Siddha 		 */
377a2699e47SSuresh Siddha 		__flush_tlb_all();
378a2699e47SSuresh Siddha 
379a2699e47SSuresh Siddha 		/*
380a2699e47SSuresh Siddha 		 * Second iteration will set the actual desired PTE attributes.
381a2699e47SSuresh Siddha 		 */
382a2699e47SSuresh Siddha 		mapping_iter = 2;
383a2699e47SSuresh Siddha 		goto repeat;
384a2699e47SSuresh Siddha 	}
385c1fd1b43SPekka Enberg 	return last_map_addr;
386ae531c26SArjan van de Ven }
387ae531c26SArjan van de Ven 
388fd940934SKeith Packard #ifdef CONFIG_HIGHMEM
permanent_kmaps_init(pgd_t * pgd_base)389ad757b6aSThomas Gleixner static void __init permanent_kmaps_init(pgd_t *pgd_base)
390ad757b6aSThomas Gleixner {
391e05c7b1fSMike Rapoport 	unsigned long vaddr = PKMAP_BASE;
392ad757b6aSThomas Gleixner 
393ad757b6aSThomas Gleixner 	page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
394ad757b6aSThomas Gleixner 
395e05c7b1fSMike Rapoport 	pkmap_page_table = virt_to_kpte(vaddr);
396ad757b6aSThomas Gleixner }
397ad757b6aSThomas Gleixner 
add_highpages_with_active_regions(int nid,unsigned long start_pfn,unsigned long end_pfn)3981d931264SYinghai Lu void __init add_highpages_with_active_regions(int nid,
3991d931264SYinghai Lu 			 unsigned long start_pfn, unsigned long end_pfn)
400b5bc6c0eSYinghai Lu {
4018a9ca34cSTejun Heo 	phys_addr_t start, end;
4028a9ca34cSTejun Heo 	u64 i;
4031d931264SYinghai Lu 
404fc6daaf9STony Luck 	for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &start, &end, NULL) {
4058a9ca34cSTejun Heo 		unsigned long pfn = clamp_t(unsigned long, PFN_UP(start),
4068a9ca34cSTejun Heo 					    start_pfn, end_pfn);
4078a9ca34cSTejun Heo 		unsigned long e_pfn = clamp_t(unsigned long, PFN_DOWN(end),
4088a9ca34cSTejun Heo 					      start_pfn, end_pfn);
4098a9ca34cSTejun Heo 		for ( ; pfn < e_pfn; pfn++)
4108a9ca34cSTejun Heo 			if (pfn_valid(pfn))
4115e7ccf86SJiang Liu 				free_highmem_page(pfn_to_page(pfn));
412b5bc6c0eSYinghai Lu 	}
413ad757b6aSThomas Gleixner }
414ad757b6aSThomas Gleixner #else
permanent_kmaps_init(pgd_t * pgd_base)415e8e32326SIngo Brueckl static inline void permanent_kmaps_init(pgd_t *pgd_base)
416e8e32326SIngo Brueckl {
417e8e32326SIngo Brueckl }
418ad757b6aSThomas Gleixner #endif /* CONFIG_HIGHMEM */
419ad757b6aSThomas Gleixner 
sync_initial_page_table(void)420945fd17aSThomas Gleixner void __init sync_initial_page_table(void)
421945fd17aSThomas Gleixner {
422945fd17aSThomas Gleixner 	clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY,
423945fd17aSThomas Gleixner 			swapper_pg_dir     + KERNEL_PGD_BOUNDARY,
424945fd17aSThomas Gleixner 			KERNEL_PGD_PTRS);
425945fd17aSThomas Gleixner 
426945fd17aSThomas Gleixner 	/*
427945fd17aSThomas Gleixner 	 * sync back low identity map too.  It is used for example
428945fd17aSThomas Gleixner 	 * in the 32-bit EFI stub.
429945fd17aSThomas Gleixner 	 */
430945fd17aSThomas Gleixner 	clone_pgd_range(initial_page_table,
431945fd17aSThomas Gleixner 			swapper_pg_dir     + KERNEL_PGD_BOUNDARY,
432945fd17aSThomas Gleixner 			min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY));
433945fd17aSThomas Gleixner }
434945fd17aSThomas Gleixner 
native_pagetable_init(void)4357737b215SAttilio Rao void __init native_pagetable_init(void)
436ad757b6aSThomas Gleixner {
437551889a6SIan Campbell 	unsigned long pfn, va;
43873090f89SAttilio Rao 	pgd_t *pgd, *base = swapper_pg_dir;
439e0c4f675SKirill A. Shutemov 	p4d_t *p4d;
440551889a6SIan Campbell 	pud_t *pud;
441551889a6SIan Campbell 	pmd_t *pmd;
442551889a6SIan Campbell 	pte_t *pte;
443ad757b6aSThomas Gleixner 
444ad757b6aSThomas Gleixner 	/*
445551889a6SIan Campbell 	 * Remove any mappings which extend past the end of physical
44611ed9e92SYinghai Lu 	 * memory from the boot time page table.
44711ed9e92SYinghai Lu 	 * In virtual address space, we should have at least two pages
44811ed9e92SYinghai Lu 	 * from VMALLOC_END to pkmap or fixmap according to VMALLOC_END
44911ed9e92SYinghai Lu 	 * definition. And max_low_pfn is set to VMALLOC_END physical
45011ed9e92SYinghai Lu 	 * address. If initial memory mapping is doing right job, we
45111ed9e92SYinghai Lu 	 * should have pte used near max_low_pfn or one pmd is not present.
452ad757b6aSThomas Gleixner 	 */
45311ed9e92SYinghai Lu 	for (pfn = max_low_pfn; pfn < 1<<(32-PAGE_SHIFT); pfn++) {
454551889a6SIan Campbell 		va = PAGE_OFFSET + (pfn<<PAGE_SHIFT);
455551889a6SIan Campbell 		pgd = base + pgd_index(va);
456551889a6SIan Campbell 		if (!pgd_present(*pgd))
457551889a6SIan Campbell 			break;
458ad757b6aSThomas Gleixner 
459e0c4f675SKirill A. Shutemov 		p4d = p4d_offset(pgd, va);
460e0c4f675SKirill A. Shutemov 		pud = pud_offset(p4d, va);
461551889a6SIan Campbell 		pmd = pmd_offset(pud, va);
462551889a6SIan Campbell 		if (!pmd_present(*pmd))
463551889a6SIan Campbell 			break;
464551889a6SIan Campbell 
46511ed9e92SYinghai Lu 		/* should not be large page here */
466*2f709f7bSPeter Xu 		if (pmd_leaf(*pmd)) {
46711ed9e92SYinghai Lu 			pr_warn("try to clear pte for ram above max_low_pfn: pfn: %lx pmd: %p pmd phys: %lx, but pmd is big page and is not using pte !\n",
46811ed9e92SYinghai Lu 				pfn, pmd, __pa(pmd));
46911ed9e92SYinghai Lu 			BUG_ON(1);
47011ed9e92SYinghai Lu 		}
47111ed9e92SYinghai Lu 
472551889a6SIan Campbell 		pte = pte_offset_kernel(pmd, va);
473551889a6SIan Campbell 		if (!pte_present(*pte))
474551889a6SIan Campbell 			break;
475551889a6SIan Campbell 
47611ed9e92SYinghai Lu 		printk(KERN_DEBUG "clearing pte for ram above max_low_pfn: pfn: %lx pmd: %p pmd phys: %lx pte: %p pte phys: %lx\n",
47711ed9e92SYinghai Lu 				pfn, pmd, __pa(pmd), pte, __pa(pte));
478551889a6SIan Campbell 		pte_clear(NULL, va, pte);
479551889a6SIan Campbell 	}
480843b8ed2SAttilio Rao 	paging_init();
481ad757b6aSThomas Gleixner }
482ad757b6aSThomas Gleixner 
483ad757b6aSThomas Gleixner /*
484ad757b6aSThomas Gleixner  * Build a proper pagetable for the kernel mappings.  Up until this
485ad757b6aSThomas Gleixner  * point, we've been running on some set of pagetables constructed by
486ad757b6aSThomas Gleixner  * the boot process.
487ad757b6aSThomas Gleixner  *
48878841cd1SJuergen Gross  * This will be a pagetable constructed in arch/x86/kernel/head_32.S.
48978841cd1SJuergen Gross  * The root of the pagetable will be swapper_pg_dir.
490ad757b6aSThomas Gleixner  *
491ad757b6aSThomas Gleixner  * In general, pagetable_init() assumes that the pagetable may already
492ad757b6aSThomas Gleixner  * be partially populated, and so it avoids stomping on any existing
493ad757b6aSThomas Gleixner  * mappings.
494ad757b6aSThomas Gleixner  */
early_ioremap_page_table_range_init(void)495f765090aSPekka Enberg void __init early_ioremap_page_table_range_init(void)
496ad757b6aSThomas Gleixner {
497e7179853SPekka Enberg 	pgd_t *pgd_base = swapper_pg_dir;
4988550eb99SIngo Molnar 	unsigned long vaddr, end;
499ad757b6aSThomas Gleixner 
500ad757b6aSThomas Gleixner 	/*
501ad757b6aSThomas Gleixner 	 * Fixed mappings, only the page table structure has to be
502ad757b6aSThomas Gleixner 	 * created - mappings will be set by set_fixmap():
503ad757b6aSThomas Gleixner 	 */
504ad757b6aSThomas Gleixner 	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
505ad757b6aSThomas Gleixner 	end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
506ad757b6aSThomas Gleixner 	page_table_range_init(vaddr, end, pgd_base);
507beacfaacSHuang, Ying 	early_ioremap_reset();
508e7b37895SYinghai Lu }
509e7b37895SYinghai Lu 
pagetable_init(void)510e7b37895SYinghai Lu static void __init pagetable_init(void)
511e7b37895SYinghai Lu {
512e7b37895SYinghai Lu 	pgd_t *pgd_base = swapper_pg_dir;
513e7b37895SYinghai Lu 
514ad757b6aSThomas Gleixner 	permanent_kmaps_init(pgd_base);
515ad757b6aSThomas Gleixner }
516ad757b6aSThomas Gleixner 
5178a57f484SDave Hansen #define DEFAULT_PTE_MASK ~(_PAGE_NX | _PAGE_GLOBAL)
5188a57f484SDave Hansen /* Bits supported by the hardware: */
5198a57f484SDave Hansen pteval_t __supported_pte_mask __read_mostly = DEFAULT_PTE_MASK;
5208a57f484SDave Hansen /* Bits allowed in normal kernel mappings: */
5218a57f484SDave Hansen pteval_t __default_kernel_pte_mask __read_mostly = DEFAULT_PTE_MASK;
5226fdc05d4SJeremy Fitzhardinge EXPORT_SYMBOL_GPL(__supported_pte_mask);
5238a57f484SDave Hansen /* Used in PAGE_KERNEL_* macros which are reasonably used out-of-tree: */
5248a57f484SDave Hansen EXPORT_SYMBOL(__default_kernel_pte_mask);
5256fdc05d4SJeremy Fitzhardinge 
52690d967e0SYinghai Lu /* user-defined highmem size */
52790d967e0SYinghai Lu static unsigned int highmem_pages = -1;
52890d967e0SYinghai Lu 
52990d967e0SYinghai Lu /*
53090d967e0SYinghai Lu  * highmem=size forces highmem to be exactly 'size' bytes.
53190d967e0SYinghai Lu  * This works even on boxes that have no highmem otherwise.
53290d967e0SYinghai Lu  * This also works to reduce highmem size on bigger boxes.
53390d967e0SYinghai Lu  */
parse_highmem(char * arg)53490d967e0SYinghai Lu static int __init parse_highmem(char *arg)
53590d967e0SYinghai Lu {
53690d967e0SYinghai Lu 	if (!arg)
53790d967e0SYinghai Lu 		return -EINVAL;
53890d967e0SYinghai Lu 
53990d967e0SYinghai Lu 	highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT;
54090d967e0SYinghai Lu 	return 0;
54190d967e0SYinghai Lu }
54290d967e0SYinghai Lu early_param("highmem", parse_highmem);
54390d967e0SYinghai Lu 
5444769843bSIngo Molnar #define MSG_HIGHMEM_TOO_BIG \
5454769843bSIngo Molnar 	"highmem size (%luMB) is bigger than pages available (%luMB)!\n"
5464769843bSIngo Molnar 
5474769843bSIngo Molnar #define MSG_LOWMEM_TOO_SMALL \
5484769843bSIngo Molnar 	"highmem size (%luMB) results in <64MB lowmem, ignoring it!\n"
54990d967e0SYinghai Lu /*
5504769843bSIngo Molnar  * All of RAM fits into lowmem - but if user wants highmem
5514769843bSIngo Molnar  * artificially via the highmem=x boot parameter then create
5524769843bSIngo Molnar  * it:
55390d967e0SYinghai Lu  */
lowmem_pfn_init(void)554f836e35aSYinghai Lu static void __init lowmem_pfn_init(void)
55590d967e0SYinghai Lu {
556346cafecSYinghai Lu 	/* max_low_pfn is 0, we already have early_res support */
55790d967e0SYinghai Lu 	max_low_pfn = max_pfn;
558d88316c2SIngo Molnar 
5594769843bSIngo Molnar 	if (highmem_pages == -1)
5604769843bSIngo Molnar 		highmem_pages = 0;
5614769843bSIngo Molnar #ifdef CONFIG_HIGHMEM
5624769843bSIngo Molnar 	if (highmem_pages >= max_pfn) {
5634769843bSIngo Molnar 		printk(KERN_ERR MSG_HIGHMEM_TOO_BIG,
5644769843bSIngo Molnar 			pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
5654769843bSIngo Molnar 		highmem_pages = 0;
5664769843bSIngo Molnar 	}
5674769843bSIngo Molnar 	if (highmem_pages) {
5684769843bSIngo Molnar 		if (max_low_pfn - highmem_pages < 64*1024*1024/PAGE_SIZE) {
5694769843bSIngo Molnar 			printk(KERN_ERR MSG_LOWMEM_TOO_SMALL,
5704769843bSIngo Molnar 				pages_to_mb(highmem_pages));
5714769843bSIngo Molnar 			highmem_pages = 0;
5724769843bSIngo Molnar 		}
5734769843bSIngo Molnar 		max_low_pfn -= highmem_pages;
5744769843bSIngo Molnar 	}
5754769843bSIngo Molnar #else
5764769843bSIngo Molnar 	if (highmem_pages)
5774769843bSIngo Molnar 		printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n");
5784769843bSIngo Molnar #endif
5794769843bSIngo Molnar }
5804769843bSIngo Molnar 
5814769843bSIngo Molnar #define MSG_HIGHMEM_TOO_SMALL \
5824769843bSIngo Molnar 	"only %luMB highmem pages available, ignoring highmem size of %luMB!\n"
5834769843bSIngo Molnar 
5844769843bSIngo Molnar #define MSG_HIGHMEM_TRIMMED \
5854769843bSIngo Molnar 	"Warning: only 4GB will be used. Use a HIGHMEM64G enabled kernel!\n"
5864769843bSIngo Molnar /*
5874769843bSIngo Molnar  * We have more RAM than fits into lowmem - we try to put it into
5884769843bSIngo Molnar  * highmem, also taking the highmem=x boot parameter into account:
5894769843bSIngo Molnar  */
highmem_pfn_init(void)590f836e35aSYinghai Lu static void __init highmem_pfn_init(void)
5914769843bSIngo Molnar {
592d88316c2SIngo Molnar 	max_low_pfn = MAXMEM_PFN;
593d88316c2SIngo Molnar 
59490d967e0SYinghai Lu 	if (highmem_pages == -1)
59590d967e0SYinghai Lu 		highmem_pages = max_pfn - MAXMEM_PFN;
5964769843bSIngo Molnar 
59790d967e0SYinghai Lu 	if (highmem_pages + MAXMEM_PFN < max_pfn)
59890d967e0SYinghai Lu 		max_pfn = MAXMEM_PFN + highmem_pages;
5994769843bSIngo Molnar 
60090d967e0SYinghai Lu 	if (highmem_pages + MAXMEM_PFN > max_pfn) {
6014769843bSIngo Molnar 		printk(KERN_WARNING MSG_HIGHMEM_TOO_SMALL,
60290d967e0SYinghai Lu 			pages_to_mb(max_pfn - MAXMEM_PFN),
60390d967e0SYinghai Lu 			pages_to_mb(highmem_pages));
60490d967e0SYinghai Lu 		highmem_pages = 0;
60590d967e0SYinghai Lu 	}
60690d967e0SYinghai Lu #ifndef CONFIG_HIGHMEM
60790d967e0SYinghai Lu 	/* Maximum memory usable is what is directly addressable */
6084769843bSIngo Molnar 	printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20);
60990d967e0SYinghai Lu 	if (max_pfn > MAX_NONPAE_PFN)
6104769843bSIngo Molnar 		printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
61190d967e0SYinghai Lu 	else
61290d967e0SYinghai Lu 		printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
61390d967e0SYinghai Lu 	max_pfn = MAXMEM_PFN;
61490d967e0SYinghai Lu #else /* !CONFIG_HIGHMEM */
61590d967e0SYinghai Lu #ifndef CONFIG_HIGHMEM64G
61690d967e0SYinghai Lu 	if (max_pfn > MAX_NONPAE_PFN) {
61790d967e0SYinghai Lu 		max_pfn = MAX_NONPAE_PFN;
6184769843bSIngo Molnar 		printk(KERN_WARNING MSG_HIGHMEM_TRIMMED);
61990d967e0SYinghai Lu 	}
62090d967e0SYinghai Lu #endif /* !CONFIG_HIGHMEM64G */
62190d967e0SYinghai Lu #endif /* !CONFIG_HIGHMEM */
62290d967e0SYinghai Lu }
6234769843bSIngo Molnar 
62490d967e0SYinghai Lu /*
62590d967e0SYinghai Lu  * Determine low and high memory ranges:
62690d967e0SYinghai Lu  */
find_low_pfn_range(void)62790d967e0SYinghai Lu void __init find_low_pfn_range(void)
62890d967e0SYinghai Lu {
62990d967e0SYinghai Lu 	/* it could update max_pfn */
63090d967e0SYinghai Lu 
631d88316c2SIngo Molnar 	if (max_pfn <= MAXMEM_PFN)
6324769843bSIngo Molnar 		lowmem_pfn_init();
633d88316c2SIngo Molnar 	else
634d88316c2SIngo Molnar 		highmem_pfn_init();
63590d967e0SYinghai Lu }
63690d967e0SYinghai Lu 
637a9ee6cf5SMike Rapoport #ifndef CONFIG_NUMA
initmem_init(void)638d8fc3afcSTejun Heo void __init initmem_init(void)
639b2ac82a0SYinghai Lu {
640b2ac82a0SYinghai Lu #ifdef CONFIG_HIGHMEM
641b2ac82a0SYinghai Lu 	highstart_pfn = highend_pfn = max_pfn;
642b2ac82a0SYinghai Lu 	if (max_pfn > max_low_pfn)
643b2ac82a0SYinghai Lu 		highstart_pfn = max_low_pfn;
644b2ac82a0SYinghai Lu 	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
645b2ac82a0SYinghai Lu 		pages_to_mb(highend_pfn - highstart_pfn));
646b2ac82a0SYinghai Lu 	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
647b2ac82a0SYinghai Lu #else
648b2ac82a0SYinghai Lu 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
649b2ac82a0SYinghai Lu #endif
6500608f70cSTejun Heo 
651d7dc899aSStefan Agner 	memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
6520608f70cSTejun Heo 
653b2ac82a0SYinghai Lu #ifdef CONFIG_FLATMEM
65446a84132SJiang Liu 	max_mapnr = IS_ENABLED(CONFIG_HIGHMEM) ? highend_pfn : max_low_pfn;
655b2ac82a0SYinghai Lu #endif
656dc16ecf7SJeremy Fitzhardinge 	__vmalloc_start_set = true;
657dc16ecf7SJeremy Fitzhardinge 
658b2ac82a0SYinghai Lu 	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
659b2ac82a0SYinghai Lu 			pages_to_mb(max_low_pfn));
660b2ac82a0SYinghai Lu 
661b2ac82a0SYinghai Lu 	setup_bootmem_allocator();
662b2ac82a0SYinghai Lu }
663a9ee6cf5SMike Rapoport #endif /* !CONFIG_NUMA */
664b2ac82a0SYinghai Lu 
setup_bootmem_allocator(void)665b2ac82a0SYinghai Lu void __init setup_bootmem_allocator(void)
666b2ac82a0SYinghai Lu {
667b2ac82a0SYinghai Lu 	printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
668b2ac82a0SYinghai Lu 		 max_pfn_mapped<<PAGE_SHIFT);
669fc5efe39SYinghai Lu 	printk(KERN_INFO "  low ram: 0 - %08lx\n", max_low_pfn<<PAGE_SHIFT);
6704e29684cSYinghai Lu }
6714e29684cSYinghai Lu 
672a04ad82dSYinghai Lu /*
673ad757b6aSThomas Gleixner  * paging_init() sets up the page tables - note that the first 8MB are
674ad757b6aSThomas Gleixner  * already mapped by head.S.
675ad757b6aSThomas Gleixner  *
676ad757b6aSThomas Gleixner  * This routines also unmaps the page at virtual kernel address 0, so
677ad757b6aSThomas Gleixner  * that we can trap those pesky NULL-reference errors in the kernel.
678ad757b6aSThomas Gleixner  */
paging_init(void)679ad757b6aSThomas Gleixner void __init paging_init(void)
680ad757b6aSThomas Gleixner {
681ad757b6aSThomas Gleixner 	pagetable_init();
682ad757b6aSThomas Gleixner 
683ad757b6aSThomas Gleixner 	__flush_tlb_all();
684ad757b6aSThomas Gleixner 
68511cd0bc1SYinghai Lu 	/*
68611cd0bc1SYinghai Lu 	 * NOTE: at this point the bootmem allocator is fully available.
68711cd0bc1SYinghai Lu 	 */
688c10d1e26SAndres Salomon 	olpc_dt_build_devicetree();
68911cd0bc1SYinghai Lu 	sparse_init();
69011cd0bc1SYinghai Lu 	zone_sizes_init();
691ad757b6aSThomas Gleixner }
692ad757b6aSThomas Gleixner 
693ad757b6aSThomas Gleixner /*
694ad757b6aSThomas Gleixner  * Test if the WP bit works in supervisor mode. It isn't supported on 386's
695f7f17a67SDmitri Vorobiev  * and also on some strange 486's. All 586+'s are OK. This used to involve
696f7f17a67SDmitri Vorobiev  * black magic jumps to work around some nasty CPU bugs, but fortunately the
697f7f17a67SDmitri Vorobiev  * switch to using exceptions got rid of all that.
698ad757b6aSThomas Gleixner  */
test_wp_bit(void)699ad757b6aSThomas Gleixner static void __init test_wp_bit(void)
700ad757b6aSThomas Gleixner {
7014af17110SAndy Lutomirski 	char z = 0;
7026415813bSMathias Krause 
703952a6c2cSBorislav Petkov 	printk(KERN_INFO "Checking if this processor honours the WP bit even in supervisor mode...");
704ad757b6aSThomas Gleixner 
7054af17110SAndy Lutomirski 	__set_fixmap(FIX_WP_TEST, __pa_symbol(empty_zero_page), PAGE_KERNEL_RO);
706ad757b6aSThomas Gleixner 
707fe557319SChristoph Hellwig 	if (copy_to_kernel_nofault((char *)fix_to_virt(FIX_WP_TEST), &z, 1)) {
708952a6c2cSBorislav Petkov 		clear_fixmap(FIX_WP_TEST);
709952a6c2cSBorislav Petkov 		printk(KERN_CONT "Ok.\n");
710952a6c2cSBorislav Petkov 		return;
711ad757b6aSThomas Gleixner 	}
7124af17110SAndy Lutomirski 
713952a6c2cSBorislav Petkov 	printk(KERN_CONT "No.\n");
714952a6c2cSBorislav Petkov 	panic("Linux doesn't support CPUs with broken WP.");
715ad757b6aSThomas Gleixner }
716ad757b6aSThomas Gleixner 
mem_init(void)717ad757b6aSThomas Gleixner void __init mem_init(void)
718ad757b6aSThomas Gleixner {
719cfb80c9eSJeremy Fitzhardinge 	pci_iommu_alloc();
720cfb80c9eSJeremy Fitzhardinge 
721ad757b6aSThomas Gleixner #ifdef CONFIG_FLATMEM
722ad757b6aSThomas Gleixner 	BUG_ON(!mem_map);
723ad757b6aSThomas Gleixner #endif
724855c743aSStanislaw Gruszka 	/*
725855c743aSStanislaw Gruszka 	 * With CONFIG_DEBUG_PAGEALLOC initialization of highmem pages has to
726c6ffc5caSMike Rapoport 	 * be done before memblock_free_all(). Memblock use free low memory for
727855c743aSStanislaw Gruszka 	 * temporary data (see find_range_array()) and for this purpose can use
728855c743aSStanislaw Gruszka 	 * pages that was already passed to the buddy allocator, hence marked as
729855c743aSStanislaw Gruszka 	 * not accessible in the page tables when compiled with
730855c743aSStanislaw Gruszka 	 * CONFIG_DEBUG_PAGEALLOC. Otherwise order of initialization is not
731855c743aSStanislaw Gruszka 	 * important here.
732855c743aSStanislaw Gruszka 	 */
733855c743aSStanislaw Gruszka 	set_highmem_pages_init();
734855c743aSStanislaw Gruszka 
735ad757b6aSThomas Gleixner 	/* this will put all low memory onto the freelists */
736c6ffc5caSMike Rapoport 	memblock_free_all();
737ad757b6aSThomas Gleixner 
7384e37a890SYinghai Lu 	after_bootmem = 1;
7396f84f8d1SPavel Tatashin 	x86_init.hyper.init_after_bootmem();
7404e37a890SYinghai Lu 
741beeb4195SJan Beulich 	/*
742beeb4195SJan Beulich 	 * Check boundaries twice: Some fundamental inconsistencies can
743beeb4195SJan Beulich 	 * be detected at build time already.
744beeb4195SJan Beulich 	 */
745beeb4195SJan Beulich #define __FIXADDR_TOP (-PAGE_SIZE)
746beeb4195SJan Beulich #ifdef CONFIG_HIGHMEM
747beeb4195SJan Beulich 	BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE	> FIXADDR_START);
748beeb4195SJan Beulich 	BUILD_BUG_ON(VMALLOC_END			> PKMAP_BASE);
749beeb4195SJan Beulich #endif
750beeb4195SJan Beulich #define high_memory (-128UL << 20)
751beeb4195SJan Beulich 	BUILD_BUG_ON(VMALLOC_START			>= VMALLOC_END);
752beeb4195SJan Beulich #undef high_memory
753beeb4195SJan Beulich #undef __FIXADDR_TOP
754beeb4195SJan Beulich 
755ad757b6aSThomas Gleixner #ifdef CONFIG_HIGHMEM
756ad757b6aSThomas Gleixner 	BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE	> FIXADDR_START);
757ad757b6aSThomas Gleixner 	BUG_ON(VMALLOC_END				> PKMAP_BASE);
758ad757b6aSThomas Gleixner #endif
759beeb4195SJan Beulich 	BUG_ON(VMALLOC_START				>= VMALLOC_END);
760ad757b6aSThomas Gleixner 	BUG_ON((unsigned long)high_memory		> VMALLOC_START);
761ad757b6aSThomas Gleixner 
762ad757b6aSThomas Gleixner 	test_wp_bit();
763ad757b6aSThomas Gleixner }
764ad757b6aSThomas Gleixner 
765502f6604SSuresh Siddha int kernel_set_to_readonly __read_mostly;
76616239630SSteven Rostedt 
mark_nxdata_nx(void)7675bd5a452SMatthieu Castet static void mark_nxdata_nx(void)
7685bd5a452SMatthieu Castet {
7695bd5a452SMatthieu Castet 	/*
7705bd5a452SMatthieu Castet 	 * When this called, init has already been executed and released,
7710d2eb44fSLucas De Marchi 	 * so everything past _etext should be NX.
7725bd5a452SMatthieu Castet 	 */
7735bd5a452SMatthieu Castet 	unsigned long start = PFN_ALIGN(_etext);
7745bd5a452SMatthieu Castet 	/*
7750a96c902SKefeng Wang 	 * This comes from is_x86_32_kernel_text upper limit. Also HPAGE where used:
7765bd5a452SMatthieu Castet 	 */
7775bd5a452SMatthieu Castet 	unsigned long size = (((unsigned long)__init_end + HPAGE_SIZE) & HPAGE_MASK) - start;
7785bd5a452SMatthieu Castet 
7795bd5a452SMatthieu Castet 	if (__supported_pte_mask & _PAGE_NX)
7805bd5a452SMatthieu Castet 		printk(KERN_INFO "NX-protecting the kernel data: %luk\n", size >> 10);
781185be151SChristoph Hellwig 	set_memory_nx(start, size >> PAGE_SHIFT);
7825bd5a452SMatthieu Castet }
7835bd5a452SMatthieu Castet 
mark_rodata_ro(void)784ad757b6aSThomas Gleixner void mark_rodata_ro(void)
785ad757b6aSThomas Gleixner {
786ad757b6aSThomas Gleixner 	unsigned long start = PFN_ALIGN(_text);
7872a25dc7cSThomas Gleixner 	unsigned long size = (unsigned long)__end_rodata - start;
788ad757b6aSThomas Gleixner 
7896d238cc4SArjan van de Ven 	set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
7902a25dc7cSThomas Gleixner 	pr_info("Write protecting kernel text and read-only data: %luk\n",
791d7d119d7SIngo Molnar 		size >> 10);
7920c42f392SAndi Kleen 
79316239630SSteven Rostedt 	kernel_set_to_readonly = 1;
79416239630SSteven Rostedt 
7950c42f392SAndi Kleen #ifdef CONFIG_CPA_DEBUG
7962a25dc7cSThomas Gleixner 	pr_info("Testing CPA: Reverting %lx-%lx\n", start, start + size);
7976d238cc4SArjan van de Ven 	set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT);
7980c42f392SAndi Kleen 
7992a25dc7cSThomas Gleixner 	pr_info("Testing CPA: write protecting again\n");
8006d238cc4SArjan van de Ven 	set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT);
8010c42f392SAndi Kleen #endif
8025bd5a452SMatthieu Castet 	mark_nxdata_nx();
803ad757b6aSThomas Gleixner }
804