diff options
Diffstat (limited to 'arch/x86/mm/init_64.c')
-rw-r--r-- | arch/x86/mm/init_64.c | 222 |
1 files changed, 184 insertions, 38 deletions
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index a02a14f0f324..1076097dcab2 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -54,6 +54,26 @@ static unsigned long dma_reserve __initdata; | |||
54 | 54 | ||
55 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 55 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
56 | 56 | ||
57 | int direct_gbpages __meminitdata | ||
58 | #ifdef CONFIG_DIRECT_GBPAGES | ||
59 | = 1 | ||
60 | #endif | ||
61 | ; | ||
62 | |||
63 | static int __init parse_direct_gbpages_off(char *arg) | ||
64 | { | ||
65 | direct_gbpages = 0; | ||
66 | return 0; | ||
67 | } | ||
68 | early_param("nogbpages", parse_direct_gbpages_off); | ||
69 | |||
70 | static int __init parse_direct_gbpages_on(char *arg) | ||
71 | { | ||
72 | direct_gbpages = 1; | ||
73 | return 0; | ||
74 | } | ||
75 | early_param("gbpages", parse_direct_gbpages_on); | ||
76 | |||
57 | /* | 77 | /* |
58 | * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the | 78 | * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the |
59 | * physical space so we can cache the place of the first one and move | 79 | * physical space so we can cache the place of the first one and move |
@@ -69,9 +89,6 @@ void show_mem(void) | |||
69 | 89 | ||
70 | printk(KERN_INFO "Mem-info:\n"); | 90 | printk(KERN_INFO "Mem-info:\n"); |
71 | show_free_areas(); | 91 | show_free_areas(); |
72 | printk(KERN_INFO "Free swap: %6ldkB\n", | ||
73 | nr_swap_pages << (PAGE_SHIFT-10)); | ||
74 | |||
75 | for_each_online_pgdat(pgdat) { | 92 | for_each_online_pgdat(pgdat) { |
76 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { | 93 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { |
77 | /* | 94 | /* |
@@ -296,7 +313,7 @@ __meminit void early_iounmap(void *addr, unsigned long size) | |||
296 | __flush_tlb_all(); | 313 | __flush_tlb_all(); |
297 | } | 314 | } |
298 | 315 | ||
299 | static void __meminit | 316 | static unsigned long __meminit |
300 | phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end) | 317 | phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end) |
301 | { | 318 | { |
302 | int i = pmd_index(address); | 319 | int i = pmd_index(address); |
@@ -318,21 +335,26 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end) | |||
318 | set_pte((pte_t *)pmd, | 335 | set_pte((pte_t *)pmd, |
319 | pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); | 336 | pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); |
320 | } | 337 | } |
338 | return address; | ||
321 | } | 339 | } |
322 | 340 | ||
323 | static void __meminit | 341 | static unsigned long __meminit |
324 | phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end) | 342 | phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end) |
325 | { | 343 | { |
326 | pmd_t *pmd = pmd_offset(pud, 0); | 344 | pmd_t *pmd = pmd_offset(pud, 0); |
345 | unsigned long last_map_addr; | ||
346 | |||
327 | spin_lock(&init_mm.page_table_lock); | 347 | spin_lock(&init_mm.page_table_lock); |
328 | phys_pmd_init(pmd, address, end); | 348 | last_map_addr = phys_pmd_init(pmd, address, end); |
329 | spin_unlock(&init_mm.page_table_lock); | 349 | spin_unlock(&init_mm.page_table_lock); |
330 | __flush_tlb_all(); | 350 | __flush_tlb_all(); |
351 | return last_map_addr; | ||
331 | } | 352 | } |
332 | 353 | ||
333 | static void __meminit | 354 | static unsigned long __meminit |
334 | phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end) | 355 | phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end) |
335 | { | 356 | { |
357 | unsigned long last_map_addr = end; | ||
336 | int i = pud_index(addr); | 358 | int i = pud_index(addr); |
337 | 359 | ||
338 | for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) { | 360 | for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) { |
@@ -350,7 +372,15 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end) | |||
350 | } | 372 | } |
351 | 373 | ||
352 | if (pud_val(*pud)) { | 374 | if (pud_val(*pud)) { |
353 | phys_pmd_update(pud, addr, end); | 375 | if (!pud_large(*pud)) |
376 | last_map_addr = phys_pmd_update(pud, addr, end); | ||
377 | continue; | ||
378 | } | ||
379 | |||
380 | if (direct_gbpages) { | ||
381 | set_pte((pte_t *)pud, | ||
382 | pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); | ||
383 | last_map_addr = (addr & PUD_MASK) + PUD_SIZE; | ||
354 | continue; | 384 | continue; |
355 | } | 385 | } |
356 | 386 | ||
@@ -358,12 +388,14 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end) | |||
358 | 388 | ||
359 | spin_lock(&init_mm.page_table_lock); | 389 | spin_lock(&init_mm.page_table_lock); |
360 | set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE)); | 390 | set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE)); |
361 | phys_pmd_init(pmd, addr, end); | 391 | last_map_addr = phys_pmd_init(pmd, addr, end); |
362 | spin_unlock(&init_mm.page_table_lock); | 392 | spin_unlock(&init_mm.page_table_lock); |
363 | 393 | ||
364 | unmap_low_page(pmd); | 394 | unmap_low_page(pmd); |
365 | } | 395 | } |
366 | __flush_tlb_all(); | 396 | __flush_tlb_all(); |
397 | |||
398 | return last_map_addr >> PAGE_SHIFT; | ||
367 | } | 399 | } |
368 | 400 | ||
369 | static void __init find_early_table_space(unsigned long end) | 401 | static void __init find_early_table_space(unsigned long end) |
@@ -371,9 +403,11 @@ static void __init find_early_table_space(unsigned long end) | |||
371 | unsigned long puds, pmds, tables, start; | 403 | unsigned long puds, pmds, tables, start; |
372 | 404 | ||
373 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; | 405 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; |
374 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; | 406 | tables = round_up(puds * sizeof(pud_t), PAGE_SIZE); |
375 | tables = round_up(puds * sizeof(pud_t), PAGE_SIZE) + | 407 | if (!direct_gbpages) { |
376 | round_up(pmds * sizeof(pmd_t), PAGE_SIZE); | 408 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; |
409 | tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE); | ||
410 | } | ||
377 | 411 | ||
378 | /* | 412 | /* |
379 | * RED-PEN putting page tables only on node 0 could | 413 | * RED-PEN putting page tables only on node 0 could |
@@ -393,16 +427,135 @@ static void __init find_early_table_space(unsigned long end) | |||
393 | (table_start << PAGE_SHIFT) + tables); | 427 | (table_start << PAGE_SHIFT) + tables); |
394 | } | 428 | } |
395 | 429 | ||
430 | static void __init init_gbpages(void) | ||
431 | { | ||
432 | if (direct_gbpages && cpu_has_gbpages) | ||
433 | printk(KERN_INFO "Using GB pages for direct mapping\n"); | ||
434 | else | ||
435 | direct_gbpages = 0; | ||
436 | } | ||
437 | |||
438 | #ifdef CONFIG_MEMTEST_BOOTPARAM | ||
439 | |||
440 | static void __init memtest(unsigned long start_phys, unsigned long size, | ||
441 | unsigned pattern) | ||
442 | { | ||
443 | unsigned long i; | ||
444 | unsigned long *start; | ||
445 | unsigned long start_bad; | ||
446 | unsigned long last_bad; | ||
447 | unsigned long val; | ||
448 | unsigned long start_phys_aligned; | ||
449 | unsigned long count; | ||
450 | unsigned long incr; | ||
451 | |||
452 | switch (pattern) { | ||
453 | case 0: | ||
454 | val = 0UL; | ||
455 | break; | ||
456 | case 1: | ||
457 | val = -1UL; | ||
458 | break; | ||
459 | case 2: | ||
460 | val = 0x5555555555555555UL; | ||
461 | break; | ||
462 | case 3: | ||
463 | val = 0xaaaaaaaaaaaaaaaaUL; | ||
464 | break; | ||
465 | default: | ||
466 | return; | ||
467 | } | ||
468 | |||
469 | incr = sizeof(unsigned long); | ||
470 | start_phys_aligned = ALIGN(start_phys, incr); | ||
471 | count = (size - (start_phys_aligned - start_phys))/incr; | ||
472 | start = __va(start_phys_aligned); | ||
473 | start_bad = 0; | ||
474 | last_bad = 0; | ||
475 | |||
476 | for (i = 0; i < count; i++) | ||
477 | start[i] = val; | ||
478 | for (i = 0; i < count; i++, start++, start_phys_aligned += incr) { | ||
479 | if (*start != val) { | ||
480 | if (start_phys_aligned == last_bad + incr) { | ||
481 | last_bad += incr; | ||
482 | } else { | ||
483 | if (start_bad) { | ||
484 | printk(KERN_CONT "\n %016lx bad mem addr %016lx - %016lx reserved", | ||
485 | val, start_bad, last_bad + incr); | ||
486 | reserve_early(start_bad, last_bad - start_bad, "BAD RAM"); | ||
487 | } | ||
488 | start_bad = last_bad = start_phys_aligned; | ||
489 | } | ||
490 | } | ||
491 | } | ||
492 | if (start_bad) { | ||
493 | printk(KERN_CONT "\n %016lx bad mem addr %016lx - %016lx reserved", | ||
494 | val, start_bad, last_bad + incr); | ||
495 | reserve_early(start_bad, last_bad - start_bad, "BAD RAM"); | ||
496 | } | ||
497 | |||
498 | } | ||
499 | |||
500 | static int memtest_pattern __initdata = CONFIG_MEMTEST_BOOTPARAM_VALUE; | ||
501 | |||
502 | static int __init parse_memtest(char *arg) | ||
503 | { | ||
504 | if (arg) | ||
505 | memtest_pattern = simple_strtoul(arg, NULL, 0); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | early_param("memtest", parse_memtest); | ||
510 | |||
511 | static void __init early_memtest(unsigned long start, unsigned long end) | ||
512 | { | ||
513 | unsigned long t_start, t_size; | ||
514 | unsigned pattern; | ||
515 | |||
516 | if (!memtest_pattern) | ||
517 | return; | ||
518 | |||
519 | printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern); | ||
520 | for (pattern = 0; pattern < memtest_pattern; pattern++) { | ||
521 | t_start = start; | ||
522 | t_size = 0; | ||
523 | while (t_start < end) { | ||
524 | t_start = find_e820_area_size(t_start, &t_size, 1); | ||
525 | |||
526 | /* done ? */ | ||
527 | if (t_start >= end) | ||
528 | break; | ||
529 | if (t_start + t_size > end) | ||
530 | t_size = end - t_start; | ||
531 | |||
532 | printk(KERN_CONT "\n %016lx - %016lx pattern %d", | ||
533 | t_start, t_start + t_size, pattern); | ||
534 | |||
535 | memtest(t_start, t_size, pattern); | ||
536 | |||
537 | t_start += t_size; | ||
538 | } | ||
539 | } | ||
540 | printk(KERN_CONT "\n"); | ||
541 | } | ||
542 | #else | ||
543 | static void __init early_memtest(unsigned long start, unsigned long end) | ||
544 | { | ||
545 | } | ||
546 | #endif | ||
547 | |||
396 | /* | 548 | /* |
397 | * Setup the direct mapping of the physical memory at PAGE_OFFSET. | 549 | * Setup the direct mapping of the physical memory at PAGE_OFFSET. |
398 | * This runs before bootmem is initialized and gets pages directly from | 550 | * This runs before bootmem is initialized and gets pages directly from |
399 | * the physical memory. To access them they are temporarily mapped. | 551 | * the physical memory. To access them they are temporarily mapped. |
400 | */ | 552 | */ |
401 | void __init_refok init_memory_mapping(unsigned long start, unsigned long end) | 553 | unsigned long __init_refok init_memory_mapping(unsigned long start, unsigned long end) |
402 | { | 554 | { |
403 | unsigned long next; | 555 | unsigned long next, last_map_addr = end; |
556 | unsigned long start_phys = start, end_phys = end; | ||
404 | 557 | ||
405 | pr_debug("init_memory_mapping\n"); | 558 | printk(KERN_INFO "init_memory_mapping\n"); |
406 | 559 | ||
407 | /* | 560 | /* |
408 | * Find space for the kernel direct mapping tables. | 561 | * Find space for the kernel direct mapping tables. |
@@ -411,8 +564,10 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end) | |||
411 | * memory mapped. Unfortunately this is done currently before the | 564 | * memory mapped. Unfortunately this is done currently before the |
412 | * nodes are discovered. | 565 | * nodes are discovered. |
413 | */ | 566 | */ |
414 | if (!after_bootmem) | 567 | if (!after_bootmem) { |
568 | init_gbpages(); | ||
415 | find_early_table_space(end); | 569 | find_early_table_space(end); |
570 | } | ||
416 | 571 | ||
417 | start = (unsigned long)__va(start); | 572 | start = (unsigned long)__va(start); |
418 | end = (unsigned long)__va(end); | 573 | end = (unsigned long)__va(end); |
@@ -430,7 +585,7 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end) | |||
430 | next = start + PGDIR_SIZE; | 585 | next = start + PGDIR_SIZE; |
431 | if (next > end) | 586 | if (next > end) |
432 | next = end; | 587 | next = end; |
433 | phys_pud_init(pud, __pa(start), __pa(next)); | 588 | last_map_addr = phys_pud_init(pud, __pa(start), __pa(next)); |
434 | if (!after_bootmem) | 589 | if (!after_bootmem) |
435 | set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys)); | 590 | set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys)); |
436 | unmap_low_page(pud); | 591 | unmap_low_page(pud); |
@@ -443,6 +598,11 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end) | |||
443 | if (!after_bootmem) | 598 | if (!after_bootmem) |
444 | reserve_early(table_start << PAGE_SHIFT, | 599 | reserve_early(table_start << PAGE_SHIFT, |
445 | table_end << PAGE_SHIFT, "PGTABLE"); | 600 | table_end << PAGE_SHIFT, "PGTABLE"); |
601 | |||
602 | if (!after_bootmem) | ||
603 | early_memtest(start_phys, end_phys); | ||
604 | |||
605 | return last_map_addr; | ||
446 | } | 606 | } |
447 | 607 | ||
448 | #ifndef CONFIG_NUMA | 608 | #ifndef CONFIG_NUMA |
@@ -482,11 +642,13 @@ int arch_add_memory(int nid, u64 start, u64 size) | |||
482 | { | 642 | { |
483 | struct pglist_data *pgdat = NODE_DATA(nid); | 643 | struct pglist_data *pgdat = NODE_DATA(nid); |
484 | struct zone *zone = pgdat->node_zones + ZONE_NORMAL; | 644 | struct zone *zone = pgdat->node_zones + ZONE_NORMAL; |
485 | unsigned long start_pfn = start >> PAGE_SHIFT; | 645 | unsigned long last_mapped_pfn, start_pfn = start >> PAGE_SHIFT; |
486 | unsigned long nr_pages = size >> PAGE_SHIFT; | 646 | unsigned long nr_pages = size >> PAGE_SHIFT; |
487 | int ret; | 647 | int ret; |
488 | 648 | ||
489 | init_memory_mapping(start, start + size-1); | 649 | last_mapped_pfn = init_memory_mapping(start, start + size-1); |
650 | if (last_mapped_pfn > max_pfn_mapped) | ||
651 | max_pfn_mapped = last_mapped_pfn; | ||
490 | 652 | ||
491 | ret = __add_pages(zone, start_pfn, nr_pages); | 653 | ret = __add_pages(zone, start_pfn, nr_pages); |
492 | WARN_ON(1); | 654 | WARN_ON(1); |
@@ -596,24 +758,7 @@ EXPORT_SYMBOL_GPL(rodata_test_data); | |||
596 | 758 | ||
597 | void mark_rodata_ro(void) | 759 | void mark_rodata_ro(void) |
598 | { | 760 | { |
599 | unsigned long start = (unsigned long)_stext, end; | 761 | unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata); |
600 | |||
601 | #ifdef CONFIG_HOTPLUG_CPU | ||
602 | /* It must still be possible to apply SMP alternatives. */ | ||
603 | if (num_possible_cpus() > 1) | ||
604 | start = (unsigned long)_etext; | ||
605 | #endif | ||
606 | |||
607 | #ifdef CONFIG_KPROBES | ||
608 | start = (unsigned long)__start_rodata; | ||
609 | #endif | ||
610 | |||
611 | end = (unsigned long)__end_rodata; | ||
612 | start = (start + PAGE_SIZE - 1) & PAGE_MASK; | ||
613 | end &= PAGE_MASK; | ||
614 | if (end <= start) | ||
615 | return; | ||
616 | |||
617 | 762 | ||
618 | printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", | 763 | printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", |
619 | (end - start) >> 10); | 764 | (end - start) >> 10); |
@@ -636,6 +781,7 @@ void mark_rodata_ro(void) | |||
636 | set_memory_ro(start, (end-start) >> PAGE_SHIFT); | 781 | set_memory_ro(start, (end-start) >> PAGE_SHIFT); |
637 | #endif | 782 | #endif |
638 | } | 783 | } |
784 | |||
639 | #endif | 785 | #endif |
640 | 786 | ||
641 | #ifdef CONFIG_BLK_DEV_INITRD | 787 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -657,7 +803,7 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len) | |||
657 | * This can happen with kdump kernels when accessing | 803 | * This can happen with kdump kernels when accessing |
658 | * firmware tables: | 804 | * firmware tables: |
659 | */ | 805 | */ |
660 | if (pfn < end_pfn_map) | 806 | if (pfn < max_pfn_mapped) |
661 | return; | 807 | return; |
662 | 808 | ||
663 | printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", | 809 | printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", |