diff options
Diffstat (limited to 'arch/x86/mm/init.c')
-rw-r--r-- | arch/x86/mm/init.c | 85 |
1 files changed, 39 insertions, 46 deletions
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index b278535b14aa..30326443ab81 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/initrd.h> | 2 | #include <linux/initrd.h> |
3 | #include <linux/ioport.h> | 3 | #include <linux/ioport.h> |
4 | #include <linux/swap.h> | 4 | #include <linux/swap.h> |
5 | #include <linux/memblock.h> | ||
5 | 6 | ||
6 | #include <asm/cacheflush.h> | 7 | #include <asm/cacheflush.h> |
7 | #include <asm/e820.h> | 8 | #include <asm/e820.h> |
@@ -15,11 +16,9 @@ | |||
15 | #include <asm/tlb.h> | 16 | #include <asm/tlb.h> |
16 | #include <asm/proto.h> | 17 | #include <asm/proto.h> |
17 | 18 | ||
18 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 19 | unsigned long __initdata pgt_buf_start; |
19 | 20 | unsigned long __meminitdata pgt_buf_end; | |
20 | unsigned long __initdata e820_table_start; | 21 | unsigned long __meminitdata pgt_buf_top; |
21 | unsigned long __meminitdata e820_table_end; | ||
22 | unsigned long __meminitdata e820_table_top; | ||
23 | 22 | ||
24 | int after_bootmem; | 23 | int after_bootmem; |
25 | 24 | ||
@@ -32,7 +31,8 @@ int direct_gbpages | |||
32 | static void __init find_early_table_space(unsigned long end, int use_pse, | 31 | static void __init find_early_table_space(unsigned long end, int use_pse, |
33 | int use_gbpages) | 32 | int use_gbpages) |
34 | { | 33 | { |
35 | unsigned long puds, pmds, ptes, tables, start; | 34 | unsigned long puds, pmds, ptes, tables, start = 0, good_end = end; |
35 | phys_addr_t base; | ||
36 | 36 | ||
37 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; | 37 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; |
38 | tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); | 38 | tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); |
@@ -63,29 +63,25 @@ static void __init find_early_table_space(unsigned long end, int use_pse, | |||
63 | #ifdef CONFIG_X86_32 | 63 | #ifdef CONFIG_X86_32 |
64 | /* for fixmap */ | 64 | /* for fixmap */ |
65 | tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE); | 65 | tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE); |
66 | #endif | ||
67 | 66 | ||
68 | /* | 67 | good_end = max_pfn_mapped << PAGE_SHIFT; |
69 | * RED-PEN putting page tables only on node 0 could | ||
70 | * cause a hotspot and fill up ZONE_DMA. The page tables | ||
71 | * need roughly 0.5KB per GB. | ||
72 | */ | ||
73 | #ifdef CONFIG_X86_32 | ||
74 | start = 0x7000; | ||
75 | #else | ||
76 | start = 0x8000; | ||
77 | #endif | 68 | #endif |
78 | e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT, | 69 | |
79 | tables, PAGE_SIZE); | 70 | base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE); |
80 | if (e820_table_start == -1UL) | 71 | if (base == MEMBLOCK_ERROR) |
81 | panic("Cannot find space for the kernel page tables"); | 72 | panic("Cannot find space for the kernel page tables"); |
82 | 73 | ||
83 | e820_table_start >>= PAGE_SHIFT; | 74 | pgt_buf_start = base >> PAGE_SHIFT; |
84 | e820_table_end = e820_table_start; | 75 | pgt_buf_end = pgt_buf_start; |
85 | e820_table_top = e820_table_start + (tables >> PAGE_SHIFT); | 76 | pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT); |
86 | 77 | ||
87 | printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n", | 78 | printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n", |
88 | end, e820_table_start << PAGE_SHIFT, e820_table_top << PAGE_SHIFT); | 79 | end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT); |
80 | } | ||
81 | |||
82 | void __init native_pagetable_reserve(u64 start, u64 end) | ||
83 | { | ||
84 | memblock_x86_reserve_range(start, end, "PGTABLE"); | ||
89 | } | 85 | } |
90 | 86 | ||
91 | struct map_range { | 87 | struct map_range { |
@@ -277,30 +273,26 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
277 | load_cr3(swapper_pg_dir); | 273 | load_cr3(swapper_pg_dir); |
278 | #endif | 274 | #endif |
279 | 275 | ||
280 | #ifdef CONFIG_X86_64 | ||
281 | if (!after_bootmem && !start) { | ||
282 | pud_t *pud; | ||
283 | pmd_t *pmd; | ||
284 | |||
285 | mmu_cr4_features = read_cr4(); | ||
286 | |||
287 | /* | ||
288 | * _brk_end cannot change anymore, but it and _end may be | ||
289 | * located on different 2M pages. cleanup_highmap(), however, | ||
290 | * can only consider _end when it runs, so destroy any | ||
291 | * mappings beyond _brk_end here. | ||
292 | */ | ||
293 | pud = pud_offset(pgd_offset_k(_brk_end), _brk_end); | ||
294 | pmd = pmd_offset(pud, _brk_end - 1); | ||
295 | while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1)) | ||
296 | pmd_clear(pmd); | ||
297 | } | ||
298 | #endif | ||
299 | __flush_tlb_all(); | 276 | __flush_tlb_all(); |
300 | 277 | ||
301 | if (!after_bootmem && e820_table_end > e820_table_start) | 278 | /* |
302 | reserve_early(e820_table_start << PAGE_SHIFT, | 279 | * Reserve the kernel pagetable pages we used (pgt_buf_start - |
303 | e820_table_end << PAGE_SHIFT, "PGTABLE"); | 280 | * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top) |
281 | * so that they can be reused for other purposes. | ||
282 | * | ||
283 | * On native it just means calling memblock_x86_reserve_range, on Xen it | ||
284 | * also means marking RW the pagetable pages that we allocated before | ||
285 | * but that haven't been used. | ||
286 | * | ||
287 | * In fact on xen we mark RO the whole range pgt_buf_start - | ||
288 | * pgt_buf_top, because we have to make sure that when | ||
289 | * init_memory_mapping reaches the pagetable pages area, it maps | ||
290 | * RO all the pagetable pages, including the ones that are beyond | ||
291 | * pgt_buf_end at that time. | ||
292 | */ | ||
293 | if (!after_bootmem && pgt_buf_end > pgt_buf_start) | ||
294 | x86_init.mapping.pagetable_reserve(PFN_PHYS(pgt_buf_start), | ||
295 | PFN_PHYS(pgt_buf_end)); | ||
304 | 296 | ||
305 | if (!after_bootmem) | 297 | if (!after_bootmem) |
306 | early_memtest(start, end); | 298 | early_memtest(start, end); |
@@ -362,8 +354,9 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) | |||
362 | /* | 354 | /* |
363 | * We just marked the kernel text read only above, now that | 355 | * We just marked the kernel text read only above, now that |
364 | * we are going to free part of that, we need to make that | 356 | * we are going to free part of that, we need to make that |
365 | * writeable first. | 357 | * writeable and non-executable first. |
366 | */ | 358 | */ |
359 | set_memory_nx(begin, (end - begin) >> PAGE_SHIFT); | ||
367 | set_memory_rw(begin, (end - begin) >> PAGE_SHIFT); | 360 | set_memory_rw(begin, (end - begin) >> PAGE_SHIFT); |
368 | 361 | ||
369 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); | 362 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); |