diff options
Diffstat (limited to 'arch/x86/mm/init_32.c')
-rw-r--r-- | arch/x86/mm/init_32.c | 527 |
1 files changed, 431 insertions, 96 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index ec30d10154b6..9689a5138e64 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -50,6 +50,7 @@ | |||
50 | 50 | ||
51 | unsigned int __VMALLOC_RESERVE = 128 << 20; | 51 | unsigned int __VMALLOC_RESERVE = 128 << 20; |
52 | 52 | ||
53 | unsigned long max_low_pfn_mapped; | ||
53 | unsigned long max_pfn_mapped; | 54 | unsigned long max_pfn_mapped; |
54 | 55 | ||
55 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 56 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
@@ -57,6 +58,27 @@ unsigned long highstart_pfn, highend_pfn; | |||
57 | 58 | ||
58 | static noinline int do_test_wp_bit(void); | 59 | static noinline int do_test_wp_bit(void); |
59 | 60 | ||
61 | |||
62 | static unsigned long __initdata table_start; | ||
63 | static unsigned long __meminitdata table_end; | ||
64 | static unsigned long __meminitdata table_top; | ||
65 | |||
66 | static int __initdata after_init_bootmem; | ||
67 | |||
68 | static __init void *alloc_low_page(unsigned long *phys) | ||
69 | { | ||
70 | unsigned long pfn = table_end++; | ||
71 | void *adr; | ||
72 | |||
73 | if (pfn >= table_top) | ||
74 | panic("alloc_low_page: ran out of memory"); | ||
75 | |||
76 | adr = __va(pfn * PAGE_SIZE); | ||
77 | memset(adr, 0, PAGE_SIZE); | ||
78 | *phys = pfn * PAGE_SIZE; | ||
79 | return adr; | ||
80 | } | ||
81 | |||
60 | /* | 82 | /* |
61 | * Creates a middle page table and puts a pointer to it in the | 83 | * Creates a middle page table and puts a pointer to it in the |
62 | * given global directory entry. This only returns the gd entry | 84 | * given global directory entry. This only returns the gd entry |
@@ -68,9 +90,12 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) | |||
68 | pmd_t *pmd_table; | 90 | pmd_t *pmd_table; |
69 | 91 | ||
70 | #ifdef CONFIG_X86_PAE | 92 | #ifdef CONFIG_X86_PAE |
93 | unsigned long phys; | ||
71 | if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { | 94 | if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { |
72 | pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); | 95 | if (after_init_bootmem) |
73 | 96 | pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE); | |
97 | else | ||
98 | pmd_table = (pmd_t *)alloc_low_page(&phys); | ||
74 | paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); | 99 | paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); |
75 | set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); | 100 | set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); |
76 | pud = pud_offset(pgd, 0); | 101 | pud = pud_offset(pgd, 0); |
@@ -92,12 +117,16 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) | |||
92 | if (!(pmd_val(*pmd) & _PAGE_PRESENT)) { | 117 | if (!(pmd_val(*pmd) & _PAGE_PRESENT)) { |
93 | pte_t *page_table = NULL; | 118 | pte_t *page_table = NULL; |
94 | 119 | ||
120 | if (after_init_bootmem) { | ||
95 | #ifdef CONFIG_DEBUG_PAGEALLOC | 121 | #ifdef CONFIG_DEBUG_PAGEALLOC |
96 | page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); | 122 | page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); |
97 | #endif | 123 | #endif |
98 | if (!page_table) { | 124 | if (!page_table) |
99 | page_table = | 125 | page_table = |
100 | (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); | 126 | (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); |
127 | } else { | ||
128 | unsigned long phys; | ||
129 | page_table = (pte_t *)alloc_low_page(&phys); | ||
101 | } | 130 | } |
102 | 131 | ||
103 | paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT); | 132 | paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT); |
@@ -155,38 +184,44 @@ static inline int is_kernel_text(unsigned long addr) | |||
155 | * of max_low_pfn pages, by creating page tables starting from address | 184 | * of max_low_pfn pages, by creating page tables starting from address |
156 | * PAGE_OFFSET: | 185 | * PAGE_OFFSET: |
157 | */ | 186 | */ |
158 | static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | 187 | static void __init kernel_physical_mapping_init(pgd_t *pgd_base, |
188 | unsigned long start_pfn, | ||
189 | unsigned long end_pfn, | ||
190 | int use_pse) | ||
159 | { | 191 | { |
160 | int pgd_idx, pmd_idx, pte_ofs; | 192 | int pgd_idx, pmd_idx, pte_ofs; |
161 | unsigned long pfn; | 193 | unsigned long pfn; |
162 | pgd_t *pgd; | 194 | pgd_t *pgd; |
163 | pmd_t *pmd; | 195 | pmd_t *pmd; |
164 | pte_t *pte; | 196 | pte_t *pte; |
197 | unsigned pages_2m = 0, pages_4k = 0; | ||
165 | 198 | ||
166 | pgd_idx = pgd_index(PAGE_OFFSET); | 199 | if (!cpu_has_pse) |
167 | pgd = pgd_base + pgd_idx; | 200 | use_pse = 0; |
168 | pfn = 0; | ||
169 | 201 | ||
202 | pfn = start_pfn; | ||
203 | pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); | ||
204 | pgd = pgd_base + pgd_idx; | ||
170 | for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { | 205 | for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { |
171 | pmd = one_md_table_init(pgd); | 206 | pmd = one_md_table_init(pgd); |
172 | if (pfn >= max_low_pfn) | ||
173 | continue; | ||
174 | 207 | ||
175 | for (pmd_idx = 0; | 208 | if (pfn >= end_pfn) |
176 | pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; | 209 | continue; |
210 | #ifdef CONFIG_X86_PAE | ||
211 | pmd_idx = pmd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); | ||
212 | pmd += pmd_idx; | ||
213 | #else | ||
214 | pmd_idx = 0; | ||
215 | #endif | ||
216 | for (; pmd_idx < PTRS_PER_PMD && pfn < end_pfn; | ||
177 | pmd++, pmd_idx++) { | 217 | pmd++, pmd_idx++) { |
178 | unsigned int addr = pfn * PAGE_SIZE + PAGE_OFFSET; | 218 | unsigned int addr = pfn * PAGE_SIZE + PAGE_OFFSET; |
179 | 219 | ||
180 | /* | 220 | /* |
181 | * Map with big pages if possible, otherwise | 221 | * Map with big pages if possible, otherwise |
182 | * create normal page tables: | 222 | * create normal page tables: |
183 | * | ||
184 | * Don't use a large page for the first 2/4MB of memory | ||
185 | * because there are often fixed size MTRRs in there | ||
186 | * and overlapping MTRRs into large pages can cause | ||
187 | * slowdowns. | ||
188 | */ | 223 | */ |
189 | if (cpu_has_pse && !(pgd_idx == 0 && pmd_idx == 0)) { | 224 | if (use_pse) { |
190 | unsigned int addr2; | 225 | unsigned int addr2; |
191 | pgprot_t prot = PAGE_KERNEL_LARGE; | 226 | pgprot_t prot = PAGE_KERNEL_LARGE; |
192 | 227 | ||
@@ -197,34 +232,30 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
197 | is_kernel_text(addr2)) | 232 | is_kernel_text(addr2)) |
198 | prot = PAGE_KERNEL_LARGE_EXEC; | 233 | prot = PAGE_KERNEL_LARGE_EXEC; |
199 | 234 | ||
235 | pages_2m++; | ||
200 | set_pmd(pmd, pfn_pmd(pfn, prot)); | 236 | set_pmd(pmd, pfn_pmd(pfn, prot)); |
201 | 237 | ||
202 | pfn += PTRS_PER_PTE; | 238 | pfn += PTRS_PER_PTE; |
203 | max_pfn_mapped = pfn; | ||
204 | continue; | 239 | continue; |
205 | } | 240 | } |
206 | pte = one_page_table_init(pmd); | 241 | pte = one_page_table_init(pmd); |
207 | 242 | ||
208 | for (pte_ofs = 0; | 243 | pte_ofs = pte_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); |
209 | pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; | 244 | pte += pte_ofs; |
245 | for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn; | ||
210 | pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) { | 246 | pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) { |
211 | pgprot_t prot = PAGE_KERNEL; | 247 | pgprot_t prot = PAGE_KERNEL; |
212 | 248 | ||
213 | if (is_kernel_text(addr)) | 249 | if (is_kernel_text(addr)) |
214 | prot = PAGE_KERNEL_EXEC; | 250 | prot = PAGE_KERNEL_EXEC; |
215 | 251 | ||
252 | pages_4k++; | ||
216 | set_pte(pte, pfn_pte(pfn, prot)); | 253 | set_pte(pte, pfn_pte(pfn, prot)); |
217 | } | 254 | } |
218 | max_pfn_mapped = pfn; | ||
219 | } | 255 | } |
220 | } | 256 | } |
221 | } | 257 | update_page_count(PG_LEVEL_2M, pages_2m); |
222 | 258 | update_page_count(PG_LEVEL_4K, pages_4k); | |
223 | static inline int page_kills_ppro(unsigned long pagenr) | ||
224 | { | ||
225 | if (pagenr >= 0x70000 && pagenr <= 0x7003F) | ||
226 | return 1; | ||
227 | return 0; | ||
228 | } | 259 | } |
229 | 260 | ||
230 | /* | 261 | /* |
@@ -287,29 +318,62 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base) | |||
287 | pkmap_page_table = pte; | 318 | pkmap_page_table = pte; |
288 | } | 319 | } |
289 | 320 | ||
290 | void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro) | 321 | static void __init add_one_highpage_init(struct page *page, int pfn) |
291 | { | 322 | { |
292 | if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) { | 323 | ClearPageReserved(page); |
293 | ClearPageReserved(page); | 324 | init_page_count(page); |
294 | init_page_count(page); | 325 | __free_page(page); |
295 | __free_page(page); | 326 | totalhigh_pages++; |
296 | totalhigh_pages++; | ||
297 | } else | ||
298 | SetPageReserved(page); | ||
299 | } | 327 | } |
300 | 328 | ||
301 | #ifndef CONFIG_NUMA | 329 | struct add_highpages_data { |
302 | static void __init set_highmem_pages_init(int bad_ppro) | 330 | unsigned long start_pfn; |
331 | unsigned long end_pfn; | ||
332 | }; | ||
333 | |||
334 | static int __init add_highpages_work_fn(unsigned long start_pfn, | ||
335 | unsigned long end_pfn, void *datax) | ||
303 | { | 336 | { |
304 | int pfn; | 337 | int node_pfn; |
338 | struct page *page; | ||
339 | unsigned long final_start_pfn, final_end_pfn; | ||
340 | struct add_highpages_data *data; | ||
305 | 341 | ||
306 | for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) { | 342 | data = (struct add_highpages_data *)datax; |
307 | /* | 343 | |
308 | * Holes under sparsemem might not have no mem_map[]: | 344 | final_start_pfn = max(start_pfn, data->start_pfn); |
309 | */ | 345 | final_end_pfn = min(end_pfn, data->end_pfn); |
310 | if (pfn_valid(pfn)) | 346 | if (final_start_pfn >= final_end_pfn) |
311 | add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro); | 347 | return 0; |
348 | |||
349 | for (node_pfn = final_start_pfn; node_pfn < final_end_pfn; | ||
350 | node_pfn++) { | ||
351 | if (!pfn_valid(node_pfn)) | ||
352 | continue; | ||
353 | page = pfn_to_page(node_pfn); | ||
354 | add_one_highpage_init(page, node_pfn); | ||
312 | } | 355 | } |
356 | |||
357 | return 0; | ||
358 | |||
359 | } | ||
360 | |||
361 | void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn, | ||
362 | unsigned long end_pfn) | ||
363 | { | ||
364 | struct add_highpages_data data; | ||
365 | |||
366 | data.start_pfn = start_pfn; | ||
367 | data.end_pfn = end_pfn; | ||
368 | |||
369 | work_with_active_regions(nid, add_highpages_work_fn, &data); | ||
370 | } | ||
371 | |||
372 | #ifndef CONFIG_NUMA | ||
373 | static void __init set_highmem_pages_init(void) | ||
374 | { | ||
375 | add_highpages_with_active_regions(0, highstart_pfn, highend_pfn); | ||
376 | |||
313 | totalram_pages += totalhigh_pages; | 377 | totalram_pages += totalhigh_pages; |
314 | } | 378 | } |
315 | #endif /* !CONFIG_NUMA */ | 379 | #endif /* !CONFIG_NUMA */ |
@@ -317,14 +381,9 @@ static void __init set_highmem_pages_init(int bad_ppro) | |||
317 | #else | 381 | #else |
318 | # define kmap_init() do { } while (0) | 382 | # define kmap_init() do { } while (0) |
319 | # define permanent_kmaps_init(pgd_base) do { } while (0) | 383 | # define permanent_kmaps_init(pgd_base) do { } while (0) |
320 | # define set_highmem_pages_init(bad_ppro) do { } while (0) | 384 | # define set_highmem_pages_init() do { } while (0) |
321 | #endif /* CONFIG_HIGHMEM */ | 385 | #endif /* CONFIG_HIGHMEM */ |
322 | 386 | ||
323 | pteval_t __PAGE_KERNEL = _PAGE_KERNEL; | ||
324 | EXPORT_SYMBOL(__PAGE_KERNEL); | ||
325 | |||
326 | pteval_t __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC; | ||
327 | |||
328 | void __init native_pagetable_setup_start(pgd_t *base) | 387 | void __init native_pagetable_setup_start(pgd_t *base) |
329 | { | 388 | { |
330 | unsigned long pfn, va; | 389 | unsigned long pfn, va; |
@@ -380,27 +439,10 @@ void __init native_pagetable_setup_done(pgd_t *base) | |||
380 | * be partially populated, and so it avoids stomping on any existing | 439 | * be partially populated, and so it avoids stomping on any existing |
381 | * mappings. | 440 | * mappings. |
382 | */ | 441 | */ |
383 | static void __init pagetable_init(void) | 442 | static void __init early_ioremap_page_table_range_init(pgd_t *pgd_base) |
384 | { | 443 | { |
385 | pgd_t *pgd_base = swapper_pg_dir; | ||
386 | unsigned long vaddr, end; | 444 | unsigned long vaddr, end; |
387 | 445 | ||
388 | paravirt_pagetable_setup_start(pgd_base); | ||
389 | |||
390 | /* Enable PSE if available */ | ||
391 | if (cpu_has_pse) | ||
392 | set_in_cr4(X86_CR4_PSE); | ||
393 | |||
394 | /* Enable PGE if available */ | ||
395 | if (cpu_has_pge) { | ||
396 | set_in_cr4(X86_CR4_PGE); | ||
397 | __PAGE_KERNEL |= _PAGE_GLOBAL; | ||
398 | __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL; | ||
399 | } | ||
400 | |||
401 | kernel_physical_mapping_init(pgd_base); | ||
402 | remap_numa_kva(); | ||
403 | |||
404 | /* | 446 | /* |
405 | * Fixed mappings, only the page table structure has to be | 447 | * Fixed mappings, only the page table structure has to be |
406 | * created - mappings will be set by set_fixmap(): | 448 | * created - mappings will be set by set_fixmap(): |
@@ -410,6 +452,13 @@ static void __init pagetable_init(void) | |||
410 | end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; | 452 | end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; |
411 | page_table_range_init(vaddr, end, pgd_base); | 453 | page_table_range_init(vaddr, end, pgd_base); |
412 | early_ioremap_reset(); | 454 | early_ioremap_reset(); |
455 | } | ||
456 | |||
457 | static void __init pagetable_init(void) | ||
458 | { | ||
459 | pgd_t *pgd_base = swapper_pg_dir; | ||
460 | |||
461 | paravirt_pagetable_setup_start(pgd_base); | ||
413 | 462 | ||
414 | permanent_kmaps_init(pgd_base); | 463 | permanent_kmaps_init(pgd_base); |
415 | 464 | ||
@@ -456,7 +505,7 @@ void zap_low_mappings(void) | |||
456 | 505 | ||
457 | int nx_enabled; | 506 | int nx_enabled; |
458 | 507 | ||
459 | pteval_t __supported_pte_mask __read_mostly = ~_PAGE_NX; | 508 | pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL); |
460 | EXPORT_SYMBOL_GPL(__supported_pte_mask); | 509 | EXPORT_SYMBOL_GPL(__supported_pte_mask); |
461 | 510 | ||
462 | #ifdef CONFIG_X86_PAE | 511 | #ifdef CONFIG_X86_PAE |
@@ -509,27 +558,318 @@ static void __init set_nx(void) | |||
509 | } | 558 | } |
510 | #endif | 559 | #endif |
511 | 560 | ||
561 | /* user-defined highmem size */ | ||
562 | static unsigned int highmem_pages = -1; | ||
563 | |||
512 | /* | 564 | /* |
513 | * paging_init() sets up the page tables - note that the first 8MB are | 565 | * highmem=size forces highmem to be exactly 'size' bytes. |
514 | * already mapped by head.S. | 566 | * This works even on boxes that have no highmem otherwise. |
515 | * | 567 | * This also works to reduce highmem size on bigger boxes. |
516 | * This routines also unmaps the page at virtual kernel address 0, so | ||
517 | * that we can trap those pesky NULL-reference errors in the kernel. | ||
518 | */ | 568 | */ |
519 | void __init paging_init(void) | 569 | static int __init parse_highmem(char *arg) |
570 | { | ||
571 | if (!arg) | ||
572 | return -EINVAL; | ||
573 | |||
574 | highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT; | ||
575 | return 0; | ||
576 | } | ||
577 | early_param("highmem", parse_highmem); | ||
578 | |||
579 | /* | ||
580 | * Determine low and high memory ranges: | ||
581 | */ | ||
582 | void __init find_low_pfn_range(void) | ||
583 | { | ||
584 | /* it could update max_pfn */ | ||
585 | |||
586 | /* max_low_pfn is 0, we already have early_res support */ | ||
587 | |||
588 | max_low_pfn = max_pfn; | ||
589 | if (max_low_pfn > MAXMEM_PFN) { | ||
590 | if (highmem_pages == -1) | ||
591 | highmem_pages = max_pfn - MAXMEM_PFN; | ||
592 | if (highmem_pages + MAXMEM_PFN < max_pfn) | ||
593 | max_pfn = MAXMEM_PFN + highmem_pages; | ||
594 | if (highmem_pages + MAXMEM_PFN > max_pfn) { | ||
595 | printk(KERN_WARNING "only %luMB highmem pages " | ||
596 | "available, ignoring highmem size of %uMB.\n", | ||
597 | pages_to_mb(max_pfn - MAXMEM_PFN), | ||
598 | pages_to_mb(highmem_pages)); | ||
599 | highmem_pages = 0; | ||
600 | } | ||
601 | max_low_pfn = MAXMEM_PFN; | ||
602 | #ifndef CONFIG_HIGHMEM | ||
603 | /* Maximum memory usable is what is directly addressable */ | ||
604 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", | ||
605 | MAXMEM>>20); | ||
606 | if (max_pfn > MAX_NONPAE_PFN) | ||
607 | printk(KERN_WARNING | ||
608 | "Use a HIGHMEM64G enabled kernel.\n"); | ||
609 | else | ||
610 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); | ||
611 | max_pfn = MAXMEM_PFN; | ||
612 | #else /* !CONFIG_HIGHMEM */ | ||
613 | #ifndef CONFIG_HIGHMEM64G | ||
614 | if (max_pfn > MAX_NONPAE_PFN) { | ||
615 | max_pfn = MAX_NONPAE_PFN; | ||
616 | printk(KERN_WARNING "Warning only 4GB will be used." | ||
617 | "Use a HIGHMEM64G enabled kernel.\n"); | ||
618 | } | ||
619 | #endif /* !CONFIG_HIGHMEM64G */ | ||
620 | #endif /* !CONFIG_HIGHMEM */ | ||
621 | } else { | ||
622 | if (highmem_pages == -1) | ||
623 | highmem_pages = 0; | ||
624 | #ifdef CONFIG_HIGHMEM | ||
625 | if (highmem_pages >= max_pfn) { | ||
626 | printk(KERN_ERR "highmem size specified (%uMB) is " | ||
627 | "bigger than pages available (%luMB)!.\n", | ||
628 | pages_to_mb(highmem_pages), | ||
629 | pages_to_mb(max_pfn)); | ||
630 | highmem_pages = 0; | ||
631 | } | ||
632 | if (highmem_pages) { | ||
633 | if (max_low_pfn - highmem_pages < | ||
634 | 64*1024*1024/PAGE_SIZE){ | ||
635 | printk(KERN_ERR "highmem size %uMB results in " | ||
636 | "smaller than 64MB lowmem, ignoring it.\n" | ||
637 | , pages_to_mb(highmem_pages)); | ||
638 | highmem_pages = 0; | ||
639 | } | ||
640 | max_low_pfn -= highmem_pages; | ||
641 | } | ||
642 | #else | ||
643 | if (highmem_pages) | ||
644 | printk(KERN_ERR "ignoring highmem size on non-highmem" | ||
645 | " kernel!\n"); | ||
646 | #endif | ||
647 | } | ||
648 | } | ||
649 | |||
650 | #ifndef CONFIG_NEED_MULTIPLE_NODES | ||
651 | void __init initmem_init(unsigned long start_pfn, | ||
652 | unsigned long end_pfn) | ||
520 | { | 653 | { |
654 | #ifdef CONFIG_HIGHMEM | ||
655 | highstart_pfn = highend_pfn = max_pfn; | ||
656 | if (max_pfn > max_low_pfn) | ||
657 | highstart_pfn = max_low_pfn; | ||
658 | memory_present(0, 0, highend_pfn); | ||
659 | e820_register_active_regions(0, 0, highend_pfn); | ||
660 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", | ||
661 | pages_to_mb(highend_pfn - highstart_pfn)); | ||
662 | num_physpages = highend_pfn; | ||
663 | high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; | ||
664 | #else | ||
665 | memory_present(0, 0, max_low_pfn); | ||
666 | e820_register_active_regions(0, 0, max_low_pfn); | ||
667 | num_physpages = max_low_pfn; | ||
668 | high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; | ||
669 | #endif | ||
670 | #ifdef CONFIG_FLATMEM | ||
671 | max_mapnr = num_physpages; | ||
672 | #endif | ||
673 | printk(KERN_NOTICE "%ldMB LOWMEM available.\n", | ||
674 | pages_to_mb(max_low_pfn)); | ||
675 | |||
676 | setup_bootmem_allocator(); | ||
677 | } | ||
678 | #endif /* !CONFIG_NEED_MULTIPLE_NODES */ | ||
679 | |||
680 | static void __init zone_sizes_init(void) | ||
681 | { | ||
682 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | ||
683 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); | ||
684 | max_zone_pfns[ZONE_DMA] = | ||
685 | virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; | ||
686 | max_zone_pfns[ZONE_NORMAL] = max_low_pfn; | ||
687 | #ifdef CONFIG_HIGHMEM | ||
688 | max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; | ||
689 | #endif | ||
690 | |||
691 | free_area_init_nodes(max_zone_pfns); | ||
692 | } | ||
693 | |||
694 | void __init setup_bootmem_allocator(void) | ||
695 | { | ||
696 | int i; | ||
697 | unsigned long bootmap_size, bootmap; | ||
698 | /* | ||
699 | * Initialize the boot-time allocator (with low memory only): | ||
700 | */ | ||
701 | bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT; | ||
702 | bootmap = find_e820_area(min_low_pfn<<PAGE_SHIFT, | ||
703 | max_pfn_mapped<<PAGE_SHIFT, bootmap_size, | ||
704 | PAGE_SIZE); | ||
705 | if (bootmap == -1L) | ||
706 | panic("Cannot find bootmem map of size %ld\n", bootmap_size); | ||
707 | reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP"); | ||
708 | |||
709 | /* don't touch min_low_pfn */ | ||
710 | bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT, | ||
711 | min_low_pfn, max_low_pfn); | ||
712 | printk(KERN_INFO " mapped low ram: 0 - %08lx\n", | ||
713 | max_pfn_mapped<<PAGE_SHIFT); | ||
714 | printk(KERN_INFO " low ram: %08lx - %08lx\n", | ||
715 | min_low_pfn<<PAGE_SHIFT, max_low_pfn<<PAGE_SHIFT); | ||
716 | printk(KERN_INFO " bootmap %08lx - %08lx\n", | ||
717 | bootmap, bootmap + bootmap_size); | ||
718 | for_each_online_node(i) | ||
719 | free_bootmem_with_active_regions(i, max_low_pfn); | ||
720 | early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT); | ||
721 | |||
722 | after_init_bootmem = 1; | ||
723 | } | ||
724 | |||
725 | static void __init find_early_table_space(unsigned long end) | ||
726 | { | ||
727 | unsigned long puds, pmds, ptes, tables, start; | ||
728 | |||
729 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; | ||
730 | tables = PAGE_ALIGN(puds * sizeof(pud_t)); | ||
731 | |||
732 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; | ||
733 | tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); | ||
734 | |||
735 | if (cpu_has_pse) { | ||
736 | unsigned long extra; | ||
737 | |||
738 | extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); | ||
739 | extra += PMD_SIZE; | ||
740 | ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
741 | } else | ||
742 | ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
743 | |||
744 | tables += PAGE_ALIGN(ptes * sizeof(pte_t)); | ||
745 | |||
746 | /* for fixmap */ | ||
747 | tables += PAGE_SIZE * 2; | ||
748 | |||
749 | /* | ||
750 | * RED-PEN putting page tables only on node 0 could | ||
751 | * cause a hotspot and fill up ZONE_DMA. The page tables | ||
752 | * need roughly 0.5KB per GB. | ||
753 | */ | ||
754 | start = 0x7000; | ||
755 | table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT, | ||
756 | tables, PAGE_SIZE); | ||
757 | if (table_start == -1UL) | ||
758 | panic("Cannot find space for the kernel page tables"); | ||
759 | |||
760 | table_start >>= PAGE_SHIFT; | ||
761 | table_end = table_start; | ||
762 | table_top = table_start + (tables>>PAGE_SHIFT); | ||
763 | |||
764 | printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n", | ||
765 | end, table_start << PAGE_SHIFT, | ||
766 | (table_start << PAGE_SHIFT) + tables); | ||
767 | } | ||
768 | |||
769 | unsigned long __init_refok init_memory_mapping(unsigned long start, | ||
770 | unsigned long end) | ||
771 | { | ||
772 | pgd_t *pgd_base = swapper_pg_dir; | ||
773 | unsigned long start_pfn, end_pfn; | ||
774 | unsigned long big_page_start; | ||
775 | |||
776 | /* | ||
777 | * Find space for the kernel direct mapping tables. | ||
778 | */ | ||
779 | if (!after_init_bootmem) | ||
780 | find_early_table_space(end); | ||
781 | |||
521 | #ifdef CONFIG_X86_PAE | 782 | #ifdef CONFIG_X86_PAE |
522 | set_nx(); | 783 | set_nx(); |
523 | if (nx_enabled) | 784 | if (nx_enabled) |
524 | printk(KERN_INFO "NX (Execute Disable) protection: active\n"); | 785 | printk(KERN_INFO "NX (Execute Disable) protection: active\n"); |
525 | #endif | 786 | #endif |
526 | pagetable_init(); | 787 | |
788 | /* Enable PSE if available */ | ||
789 | if (cpu_has_pse) | ||
790 | set_in_cr4(X86_CR4_PSE); | ||
791 | |||
792 | /* Enable PGE if available */ | ||
793 | if (cpu_has_pge) { | ||
794 | set_in_cr4(X86_CR4_PGE); | ||
795 | __supported_pte_mask |= _PAGE_GLOBAL; | ||
796 | } | ||
797 | |||
798 | /* | ||
799 | * Don't use a large page for the first 2/4MB of memory | ||
800 | * because there are often fixed size MTRRs in there | ||
801 | * and overlapping MTRRs into large pages can cause | ||
802 | * slowdowns. | ||
803 | */ | ||
804 | big_page_start = PMD_SIZE; | ||
805 | |||
806 | if (start < big_page_start) { | ||
807 | start_pfn = start >> PAGE_SHIFT; | ||
808 | end_pfn = min(big_page_start>>PAGE_SHIFT, end>>PAGE_SHIFT); | ||
809 | } else { | ||
810 | /* head is not big page alignment ? */ | ||
811 | start_pfn = start >> PAGE_SHIFT; | ||
812 | end_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT) | ||
813 | << (PMD_SHIFT - PAGE_SHIFT); | ||
814 | } | ||
815 | if (start_pfn < end_pfn) | ||
816 | kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, 0); | ||
817 | |||
818 | /* big page range */ | ||
819 | start_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT) | ||
820 | << (PMD_SHIFT - PAGE_SHIFT); | ||
821 | if (start_pfn < (big_page_start >> PAGE_SHIFT)) | ||
822 | start_pfn = big_page_start >> PAGE_SHIFT; | ||
823 | end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); | ||
824 | if (start_pfn < end_pfn) | ||
825 | kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, | ||
826 | cpu_has_pse); | ||
827 | |||
828 | /* tail is not big page alignment ? */ | ||
829 | start_pfn = end_pfn; | ||
830 | if (start_pfn > (big_page_start>>PAGE_SHIFT)) { | ||
831 | end_pfn = end >> PAGE_SHIFT; | ||
832 | if (start_pfn < end_pfn) | ||
833 | kernel_physical_mapping_init(pgd_base, start_pfn, | ||
834 | end_pfn, 0); | ||
835 | } | ||
836 | |||
837 | early_ioremap_page_table_range_init(pgd_base); | ||
527 | 838 | ||
528 | load_cr3(swapper_pg_dir); | 839 | load_cr3(swapper_pg_dir); |
529 | 840 | ||
530 | __flush_tlb_all(); | 841 | __flush_tlb_all(); |
531 | 842 | ||
843 | if (!after_init_bootmem) | ||
844 | reserve_early(table_start << PAGE_SHIFT, | ||
845 | table_end << PAGE_SHIFT, "PGTABLE"); | ||
846 | |||
847 | return end >> PAGE_SHIFT; | ||
848 | } | ||
849 | |||
850 | |||
851 | /* | ||
852 | * paging_init() sets up the page tables - note that the first 8MB are | ||
853 | * already mapped by head.S. | ||
854 | * | ||
855 | * This routines also unmaps the page at virtual kernel address 0, so | ||
856 | * that we can trap those pesky NULL-reference errors in the kernel. | ||
857 | */ | ||
858 | void __init paging_init(void) | ||
859 | { | ||
860 | pagetable_init(); | ||
861 | |||
862 | __flush_tlb_all(); | ||
863 | |||
532 | kmap_init(); | 864 | kmap_init(); |
865 | |||
866 | /* | ||
867 | * NOTE: at this point the bootmem allocator is fully available. | ||
868 | */ | ||
869 | sparse_init(); | ||
870 | zone_sizes_init(); | ||
871 | |||
872 | paravirt_post_allocator_init(); | ||
533 | } | 873 | } |
534 | 874 | ||
535 | /* | 875 | /* |
@@ -564,24 +904,11 @@ static struct kcore_list kcore_mem, kcore_vmalloc; | |||
564 | void __init mem_init(void) | 904 | void __init mem_init(void) |
565 | { | 905 | { |
566 | int codesize, reservedpages, datasize, initsize; | 906 | int codesize, reservedpages, datasize, initsize; |
567 | int tmp, bad_ppro; | 907 | int tmp; |
568 | 908 | ||
569 | #ifdef CONFIG_FLATMEM | 909 | #ifdef CONFIG_FLATMEM |
570 | BUG_ON(!mem_map); | 910 | BUG_ON(!mem_map); |
571 | #endif | 911 | #endif |
572 | bad_ppro = ppro_with_ram_bug(); | ||
573 | |||
574 | #ifdef CONFIG_HIGHMEM | ||
575 | /* check that fixmap and pkmap do not overlap */ | ||
576 | if (PKMAP_BASE + LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) { | ||
577 | printk(KERN_ERR | ||
578 | "fixmap and kmap areas overlap - this will crash\n"); | ||
579 | printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n", | ||
580 | PKMAP_BASE, PKMAP_BASE + LAST_PKMAP*PAGE_SIZE, | ||
581 | FIXADDR_START); | ||
582 | BUG(); | ||
583 | } | ||
584 | #endif | ||
585 | /* this will put all low memory onto the freelists */ | 912 | /* this will put all low memory onto the freelists */ |
586 | totalram_pages += free_all_bootmem(); | 913 | totalram_pages += free_all_bootmem(); |
587 | 914 | ||
@@ -593,7 +920,7 @@ void __init mem_init(void) | |||
593 | if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) | 920 | if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) |
594 | reservedpages++; | 921 | reservedpages++; |
595 | 922 | ||
596 | set_highmem_pages_init(bad_ppro); | 923 | set_highmem_pages_init(); |
597 | 924 | ||
598 | codesize = (unsigned long) &_etext - (unsigned long) &_text; | 925 | codesize = (unsigned long) &_etext - (unsigned long) &_text; |
599 | datasize = (unsigned long) &_edata - (unsigned long) &_etext; | 926 | datasize = (unsigned long) &_edata - (unsigned long) &_etext; |
@@ -614,7 +941,6 @@ void __init mem_init(void) | |||
614 | (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) | 941 | (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) |
615 | ); | 942 | ); |
616 | 943 | ||
617 | #if 1 /* double-sanity-check paranoia */ | ||
618 | printk(KERN_INFO "virtual kernel memory layout:\n" | 944 | printk(KERN_INFO "virtual kernel memory layout:\n" |
619 | " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" | 945 | " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" |
620 | #ifdef CONFIG_HIGHMEM | 946 | #ifdef CONFIG_HIGHMEM |
@@ -655,7 +981,6 @@ void __init mem_init(void) | |||
655 | #endif | 981 | #endif |
656 | BUG_ON(VMALLOC_START > VMALLOC_END); | 982 | BUG_ON(VMALLOC_START > VMALLOC_END); |
657 | BUG_ON((unsigned long)high_memory > VMALLOC_START); | 983 | BUG_ON((unsigned long)high_memory > VMALLOC_START); |
658 | #endif /* double-sanity-check paranoia */ | ||
659 | 984 | ||
660 | if (boot_cpu_data.wp_works_ok < 0) | 985 | if (boot_cpu_data.wp_works_ok < 0) |
661 | test_wp_bit(); | 986 | test_wp_bit(); |
@@ -710,6 +1035,8 @@ void mark_rodata_ro(void) | |||
710 | unsigned long start = PFN_ALIGN(_text); | 1035 | unsigned long start = PFN_ALIGN(_text); |
711 | unsigned long size = PFN_ALIGN(_etext) - start; | 1036 | unsigned long size = PFN_ALIGN(_etext) - start; |
712 | 1037 | ||
1038 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
1039 | /* Dynamic tracing modifies the kernel text section */ | ||
713 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); | 1040 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); |
714 | printk(KERN_INFO "Write protecting the kernel text: %luk\n", | 1041 | printk(KERN_INFO "Write protecting the kernel text: %luk\n", |
715 | size >> 10); | 1042 | size >> 10); |
@@ -722,6 +1049,8 @@ void mark_rodata_ro(void) | |||
722 | printk(KERN_INFO "Testing CPA: write protecting again\n"); | 1049 | printk(KERN_INFO "Testing CPA: write protecting again\n"); |
723 | set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT); | 1050 | set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT); |
724 | #endif | 1051 | #endif |
1052 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
1053 | |||
725 | start += size; | 1054 | start += size; |
726 | size = (unsigned long)__end_rodata - start; | 1055 | size = (unsigned long)__end_rodata - start; |
727 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); | 1056 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); |
@@ -784,3 +1113,9 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
784 | free_init_pages("initrd memory", start, end); | 1113 | free_init_pages("initrd memory", start, end); |
785 | } | 1114 | } |
786 | #endif | 1115 | #endif |
1116 | |||
1117 | int __init reserve_bootmem_generic(unsigned long phys, unsigned long len, | ||
1118 | int flags) | ||
1119 | { | ||
1120 | return reserve_bootmem(phys, len, flags); | ||
1121 | } | ||