diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-07-08 04:43:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-09 04:43:26 -0400 |
commit | c2e6d65bcea2672788f9bb58ce7606c41388387b (patch) | |
tree | 3ba6eab6156b0d2335c7a6bcd936838bb58ce87a /arch/x86/mm/init_64.c | |
parent | 2dc807b37b7b8c7df445513ad2b415df4ebcaf6d (diff) |
x86: not overmap more than the end of RAM in init_memory_mapping - 64bit
handle head and tail that are not aligned to big pages (2MB/1GB boundary).
with this patch, on system that support gbpages, change:
last_map_addr: 1080000000 end: 1078000000
to:
last_map_addr: 1078000000 end: 1078000000
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/mm/init_64.c')
-rw-r--r-- | arch/x86/mm/init_64.c | 77 |
1 files changed, 65 insertions, 12 deletions
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index f7d80313ede5..51f69b39b752 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -462,18 +462,25 @@ phys_pud_update(pgd_t *pgd, unsigned long addr, unsigned long end, | |||
462 | 462 | ||
463 | static void __init find_early_table_space(unsigned long end) | 463 | static void __init find_early_table_space(unsigned long end) |
464 | { | 464 | { |
465 | unsigned long puds, tables, start; | 465 | unsigned long puds, pmds, ptes, tables, start; |
466 | 466 | ||
467 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; | 467 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; |
468 | tables = round_up(puds * sizeof(pud_t), PAGE_SIZE); | 468 | tables = round_up(puds * sizeof(pud_t), PAGE_SIZE); |
469 | if (!direct_gbpages) { | 469 | if (direct_gbpages) { |
470 | unsigned long pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; | 470 | unsigned long extra; |
471 | tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE); | 471 | extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT); |
472 | } | 472 | pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT; |
473 | if (!cpu_has_pse) { | 473 | } else |
474 | unsigned long ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; | 474 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; |
475 | tables += round_up(ptes * sizeof(pte_t), PAGE_SIZE); | 475 | tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE); |
476 | } | 476 | |
477 | if (cpu_has_pse) { | ||
478 | unsigned long extra; | ||
479 | extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); | ||
480 | ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
481 | } else | ||
482 | ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
483 | tables += round_up(ptes * sizeof(pte_t), PAGE_SIZE); | ||
477 | 484 | ||
478 | /* | 485 | /* |
479 | * RED-PEN putting page tables only on node 0 could | 486 | * RED-PEN putting page tables only on node 0 could |
@@ -660,8 +667,9 @@ static unsigned long __init kernel_physical_mapping_init(unsigned long start, | |||
660 | unsigned long __init_refok init_memory_mapping(unsigned long start, | 667 | unsigned long __init_refok init_memory_mapping(unsigned long start, |
661 | unsigned long end) | 668 | unsigned long end) |
662 | { | 669 | { |
663 | unsigned long last_map_addr; | 670 | unsigned long last_map_addr = end; |
664 | unsigned long page_size_mask = 0; | 671 | unsigned long page_size_mask = 0; |
672 | unsigned long start_pfn, end_pfn; | ||
665 | 673 | ||
666 | printk(KERN_INFO "init_memory_mapping\n"); | 674 | printk(KERN_INFO "init_memory_mapping\n"); |
667 | 675 | ||
@@ -682,8 +690,53 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
682 | if (cpu_has_pse) | 690 | if (cpu_has_pse) |
683 | page_size_mask |= 1 << PG_LEVEL_2M; | 691 | page_size_mask |= 1 << PG_LEVEL_2M; |
684 | 692 | ||
685 | last_map_addr = kernel_physical_mapping_init(start, end, | 693 | /* head if not big page aligment ?*/ |
686 | page_size_mask); | 694 | start_pfn = start >> PAGE_SHIFT; |
695 | end_pfn = ((start + (PMD_SIZE - 1)) >> PMD_SHIFT) | ||
696 | << (PMD_SHIFT - PAGE_SHIFT); | ||
697 | if (start_pfn < end_pfn) | ||
698 | last_map_addr = kernel_physical_mapping_init( | ||
699 | start_pfn<<PAGE_SHIFT, | ||
700 | end_pfn<<PAGE_SHIFT, 0); | ||
701 | |||
702 | /* big page (2M) range*/ | ||
703 | start_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT) | ||
704 | << (PMD_SHIFT - PAGE_SHIFT); | ||
705 | end_pfn = ((start + (PUD_SIZE - 1))>>PUD_SHIFT) | ||
706 | << (PUD_SHIFT - PAGE_SHIFT); | ||
707 | if (end_pfn > ((end>>PUD_SHIFT)<<(PUD_SHIFT - PAGE_SHIFT))) | ||
708 | end_pfn = ((end>>PUD_SHIFT)<<(PUD_SHIFT - PAGE_SHIFT)); | ||
709 | if (start_pfn < end_pfn) | ||
710 | last_map_addr = kernel_physical_mapping_init( | ||
711 | start_pfn<<PAGE_SHIFT, | ||
712 | end_pfn<<PAGE_SHIFT, | ||
713 | page_size_mask & (1<<PG_LEVEL_2M)); | ||
714 | |||
715 | /* big page (1G) range */ | ||
716 | start_pfn = end_pfn; | ||
717 | end_pfn = (end>>PUD_SHIFT) << (PUD_SHIFT - PAGE_SHIFT); | ||
718 | if (start_pfn < end_pfn) | ||
719 | last_map_addr = kernel_physical_mapping_init( | ||
720 | start_pfn<<PAGE_SHIFT, | ||
721 | end_pfn<<PAGE_SHIFT, | ||
722 | page_size_mask & ((1<<PG_LEVEL_2M) | ||
723 | | (1<<PG_LEVEL_1G))); | ||
724 | |||
725 | /* tail is not big page (1G) alignment */ | ||
726 | start_pfn = end_pfn; | ||
727 | end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); | ||
728 | if (start_pfn < end_pfn) | ||
729 | last_map_addr = kernel_physical_mapping_init( | ||
730 | start_pfn<<PAGE_SHIFT, | ||
731 | end_pfn<<PAGE_SHIFT, | ||
732 | page_size_mask & (1<<PG_LEVEL_2M)); | ||
733 | /* tail is not big page (2M) alignment */ | ||
734 | start_pfn = end_pfn; | ||
735 | end_pfn = end>>PAGE_SHIFT; | ||
736 | if (start_pfn < end_pfn) | ||
737 | last_map_addr = kernel_physical_mapping_init( | ||
738 | start_pfn<<PAGE_SHIFT, | ||
739 | end_pfn<<PAGE_SHIFT, 0); | ||
687 | 740 | ||
688 | if (!after_bootmem) | 741 | if (!after_bootmem) |
689 | mmu_cr4_features = read_cr4(); | 742 | mmu_cr4_features = read_cr4(); |