diff options
Diffstat (limited to 'arch/x86/mm/init_32.c')
-rw-r--r-- | arch/x86/mm/init_32.c | 213 |
1 files changed, 99 insertions, 114 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 2cef05074413..47df0e1bbeb9 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -49,9 +49,6 @@ | |||
49 | #include <asm/paravirt.h> | 49 | #include <asm/paravirt.h> |
50 | #include <asm/setup.h> | 50 | #include <asm/setup.h> |
51 | #include <asm/cacheflush.h> | 51 | #include <asm/cacheflush.h> |
52 | #include <asm/smp.h> | ||
53 | |||
54 | unsigned int __VMALLOC_RESERVE = 128 << 20; | ||
55 | 52 | ||
56 | unsigned long max_low_pfn_mapped; | 53 | unsigned long max_low_pfn_mapped; |
57 | unsigned long max_pfn_mapped; | 54 | unsigned long max_pfn_mapped; |
@@ -138,6 +135,23 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) | |||
138 | return pte_offset_kernel(pmd, 0); | 135 | return pte_offset_kernel(pmd, 0); |
139 | } | 136 | } |
140 | 137 | ||
138 | pmd_t * __init populate_extra_pmd(unsigned long vaddr) | ||
139 | { | ||
140 | int pgd_idx = pgd_index(vaddr); | ||
141 | int pmd_idx = pmd_index(vaddr); | ||
142 | |||
143 | return one_md_table_init(swapper_pg_dir + pgd_idx) + pmd_idx; | ||
144 | } | ||
145 | |||
146 | pte_t * __init populate_extra_pte(unsigned long vaddr) | ||
147 | { | ||
148 | int pte_idx = pte_index(vaddr); | ||
149 | pmd_t *pmd; | ||
150 | |||
151 | pmd = populate_extra_pmd(vaddr); | ||
152 | return one_page_table_init(pmd) + pte_idx; | ||
153 | } | ||
154 | |||
141 | static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd, | 155 | static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd, |
142 | unsigned long vaddr, pte_t *lastpte) | 156 | unsigned long vaddr, pte_t *lastpte) |
143 | { | 157 | { |
@@ -470,22 +484,10 @@ void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn, | |||
470 | work_with_active_regions(nid, add_highpages_work_fn, &data); | 484 | work_with_active_regions(nid, add_highpages_work_fn, &data); |
471 | } | 485 | } |
472 | 486 | ||
473 | #ifndef CONFIG_NUMA | ||
474 | static void __init set_highmem_pages_init(void) | ||
475 | { | ||
476 | add_highpages_with_active_regions(0, highstart_pfn, highend_pfn); | ||
477 | |||
478 | totalram_pages += totalhigh_pages; | ||
479 | } | ||
480 | #endif /* !CONFIG_NUMA */ | ||
481 | |||
482 | #else | 487 | #else |
483 | static inline void permanent_kmaps_init(pgd_t *pgd_base) | 488 | static inline void permanent_kmaps_init(pgd_t *pgd_base) |
484 | { | 489 | { |
485 | } | 490 | } |
486 | static inline void set_highmem_pages_init(void) | ||
487 | { | ||
488 | } | ||
489 | #endif /* CONFIG_HIGHMEM */ | 491 | #endif /* CONFIG_HIGHMEM */ |
490 | 492 | ||
491 | void __init native_pagetable_setup_start(pgd_t *base) | 493 | void __init native_pagetable_setup_start(pgd_t *base) |
@@ -675,75 +677,97 @@ static int __init parse_highmem(char *arg) | |||
675 | } | 677 | } |
676 | early_param("highmem", parse_highmem); | 678 | early_param("highmem", parse_highmem); |
677 | 679 | ||
680 | #define MSG_HIGHMEM_TOO_BIG \ | ||
681 | "highmem size (%luMB) is bigger than pages available (%luMB)!\n" | ||
682 | |||
683 | #define MSG_LOWMEM_TOO_SMALL \ | ||
684 | "highmem size (%luMB) results in <64MB lowmem, ignoring it!\n" | ||
678 | /* | 685 | /* |
679 | * Determine low and high memory ranges: | 686 | * All of RAM fits into lowmem - but if user wants highmem |
687 | * artificially via the highmem=x boot parameter then create | ||
688 | * it: | ||
680 | */ | 689 | */ |
681 | void __init find_low_pfn_range(void) | 690 | void __init lowmem_pfn_init(void) |
682 | { | 691 | { |
683 | /* it could update max_pfn */ | ||
684 | |||
685 | /* max_low_pfn is 0, we already have early_res support */ | 692 | /* max_low_pfn is 0, we already have early_res support */ |
686 | |||
687 | max_low_pfn = max_pfn; | 693 | max_low_pfn = max_pfn; |
688 | if (max_low_pfn > MAXMEM_PFN) { | 694 | |
689 | if (highmem_pages == -1) | 695 | if (highmem_pages == -1) |
690 | highmem_pages = max_pfn - MAXMEM_PFN; | 696 | highmem_pages = 0; |
691 | if (highmem_pages + MAXMEM_PFN < max_pfn) | 697 | #ifdef CONFIG_HIGHMEM |
692 | max_pfn = MAXMEM_PFN + highmem_pages; | 698 | if (highmem_pages >= max_pfn) { |
693 | if (highmem_pages + MAXMEM_PFN > max_pfn) { | 699 | printk(KERN_ERR MSG_HIGHMEM_TOO_BIG, |
694 | printk(KERN_WARNING "only %luMB highmem pages " | 700 | pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); |
695 | "available, ignoring highmem size of %uMB.\n", | 701 | highmem_pages = 0; |
696 | pages_to_mb(max_pfn - MAXMEM_PFN), | 702 | } |
703 | if (highmem_pages) { | ||
704 | if (max_low_pfn - highmem_pages < 64*1024*1024/PAGE_SIZE) { | ||
705 | printk(KERN_ERR MSG_LOWMEM_TOO_SMALL, | ||
697 | pages_to_mb(highmem_pages)); | 706 | pages_to_mb(highmem_pages)); |
698 | highmem_pages = 0; | 707 | highmem_pages = 0; |
699 | } | 708 | } |
700 | max_low_pfn = MAXMEM_PFN; | 709 | max_low_pfn -= highmem_pages; |
710 | } | ||
711 | #else | ||
712 | if (highmem_pages) | ||
713 | printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n"); | ||
714 | #endif | ||
715 | } | ||
716 | |||
717 | #define MSG_HIGHMEM_TOO_SMALL \ | ||
718 | "only %luMB highmem pages available, ignoring highmem size of %luMB!\n" | ||
719 | |||
720 | #define MSG_HIGHMEM_TRIMMED \ | ||
721 | "Warning: only 4GB will be used. Use a HIGHMEM64G enabled kernel!\n" | ||
722 | /* | ||
723 | * We have more RAM than fits into lowmem - we try to put it into | ||
724 | * highmem, also taking the highmem=x boot parameter into account: | ||
725 | */ | ||
726 | void __init highmem_pfn_init(void) | ||
727 | { | ||
728 | max_low_pfn = MAXMEM_PFN; | ||
729 | |||
730 | if (highmem_pages == -1) | ||
731 | highmem_pages = max_pfn - MAXMEM_PFN; | ||
732 | |||
733 | if (highmem_pages + MAXMEM_PFN < max_pfn) | ||
734 | max_pfn = MAXMEM_PFN + highmem_pages; | ||
735 | |||
736 | if (highmem_pages + MAXMEM_PFN > max_pfn) { | ||
737 | printk(KERN_WARNING MSG_HIGHMEM_TOO_SMALL, | ||
738 | pages_to_mb(max_pfn - MAXMEM_PFN), | ||
739 | pages_to_mb(highmem_pages)); | ||
740 | highmem_pages = 0; | ||
741 | } | ||
701 | #ifndef CONFIG_HIGHMEM | 742 | #ifndef CONFIG_HIGHMEM |
702 | /* Maximum memory usable is what is directly addressable */ | 743 | /* Maximum memory usable is what is directly addressable */ |
703 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", | 744 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20); |
704 | MAXMEM>>20); | 745 | if (max_pfn > MAX_NONPAE_PFN) |
705 | if (max_pfn > MAX_NONPAE_PFN) | 746 | printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n"); |
706 | printk(KERN_WARNING | 747 | else |
707 | "Use a HIGHMEM64G enabled kernel.\n"); | 748 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); |
708 | else | 749 | max_pfn = MAXMEM_PFN; |
709 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); | ||
710 | max_pfn = MAXMEM_PFN; | ||
711 | #else /* !CONFIG_HIGHMEM */ | 750 | #else /* !CONFIG_HIGHMEM */ |
712 | #ifndef CONFIG_HIGHMEM64G | 751 | #ifndef CONFIG_HIGHMEM64G |
713 | if (max_pfn > MAX_NONPAE_PFN) { | 752 | if (max_pfn > MAX_NONPAE_PFN) { |
714 | max_pfn = MAX_NONPAE_PFN; | 753 | max_pfn = MAX_NONPAE_PFN; |
715 | printk(KERN_WARNING "Warning only 4GB will be used." | 754 | printk(KERN_WARNING MSG_HIGHMEM_TRIMMED); |
716 | "Use a HIGHMEM64G enabled kernel.\n"); | 755 | } |
717 | } | ||
718 | #endif /* !CONFIG_HIGHMEM64G */ | 756 | #endif /* !CONFIG_HIGHMEM64G */ |
719 | #endif /* !CONFIG_HIGHMEM */ | 757 | #endif /* !CONFIG_HIGHMEM */ |
720 | } else { | 758 | } |
721 | if (highmem_pages == -1) | 759 | |
722 | highmem_pages = 0; | 760 | /* |
723 | #ifdef CONFIG_HIGHMEM | 761 | * Determine low and high memory ranges: |
724 | if (highmem_pages >= max_pfn) { | 762 | */ |
725 | printk(KERN_ERR "highmem size specified (%uMB) is " | 763 | void __init find_low_pfn_range(void) |
726 | "bigger than pages available (%luMB)!.\n", | 764 | { |
727 | pages_to_mb(highmem_pages), | 765 | /* it could update max_pfn */ |
728 | pages_to_mb(max_pfn)); | 766 | |
729 | highmem_pages = 0; | 767 | if (max_pfn <= MAXMEM_PFN) |
730 | } | 768 | lowmem_pfn_init(); |
731 | if (highmem_pages) { | 769 | else |
732 | if (max_low_pfn - highmem_pages < | 770 | highmem_pfn_init(); |
733 | 64*1024*1024/PAGE_SIZE){ | ||
734 | printk(KERN_ERR "highmem size %uMB results in " | ||
735 | "smaller than 64MB lowmem, ignoring it.\n" | ||
736 | , pages_to_mb(highmem_pages)); | ||
737 | highmem_pages = 0; | ||
738 | } | ||
739 | max_low_pfn -= highmem_pages; | ||
740 | } | ||
741 | #else | ||
742 | if (highmem_pages) | ||
743 | printk(KERN_ERR "ignoring highmem size on non-highmem" | ||
744 | " kernel!\n"); | ||
745 | #endif | ||
746 | } | ||
747 | } | 771 | } |
748 | 772 | ||
749 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 773 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
@@ -826,10 +850,10 @@ static void __init find_early_table_space(unsigned long end, int use_pse) | |||
826 | unsigned long puds, pmds, ptes, tables, start; | 850 | unsigned long puds, pmds, ptes, tables, start; |
827 | 851 | ||
828 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; | 852 | puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; |
829 | tables = PAGE_ALIGN(puds * sizeof(pud_t)); | 853 | tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); |
830 | 854 | ||
831 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; | 855 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; |
832 | tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); | 856 | tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE); |
833 | 857 | ||
834 | if (use_pse) { | 858 | if (use_pse) { |
835 | unsigned long extra; | 859 | unsigned long extra; |
@@ -840,10 +864,10 @@ static void __init find_early_table_space(unsigned long end, int use_pse) | |||
840 | } else | 864 | } else |
841 | ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; | 865 | ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; |
842 | 866 | ||
843 | tables += PAGE_ALIGN(ptes * sizeof(pte_t)); | 867 | tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE); |
844 | 868 | ||
845 | /* for fixmap */ | 869 | /* for fixmap */ |
846 | tables += PAGE_ALIGN(__end_of_fixed_addresses * sizeof(pte_t)); | 870 | tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE); |
847 | 871 | ||
848 | /* | 872 | /* |
849 | * RED-PEN putting page tables only on node 0 could | 873 | * RED-PEN putting page tables only on node 0 could |
@@ -1193,45 +1217,6 @@ void mark_rodata_ro(void) | |||
1193 | } | 1217 | } |
1194 | #endif | 1218 | #endif |
1195 | 1219 | ||
1196 | void free_init_pages(char *what, unsigned long begin, unsigned long end) | ||
1197 | { | ||
1198 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
1199 | /* | ||
1200 | * If debugging page accesses then do not free this memory but | ||
1201 | * mark them not present - any buggy init-section access will | ||
1202 | * create a kernel page fault: | ||
1203 | */ | ||
1204 | printk(KERN_INFO "debug: unmapping init memory %08lx..%08lx\n", | ||
1205 | begin, PAGE_ALIGN(end)); | ||
1206 | set_memory_np(begin, (end - begin) >> PAGE_SHIFT); | ||
1207 | #else | ||
1208 | unsigned long addr; | ||
1209 | |||
1210 | /* | ||
1211 | * We just marked the kernel text read only above, now that | ||
1212 | * we are going to free part of that, we need to make that | ||
1213 | * writeable first. | ||
1214 | */ | ||
1215 | set_memory_rw(begin, (end - begin) >> PAGE_SHIFT); | ||
1216 | |||
1217 | for (addr = begin; addr < end; addr += PAGE_SIZE) { | ||
1218 | ClearPageReserved(virt_to_page(addr)); | ||
1219 | init_page_count(virt_to_page(addr)); | ||
1220 | memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); | ||
1221 | free_page(addr); | ||
1222 | totalram_pages++; | ||
1223 | } | ||
1224 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); | ||
1225 | #endif | ||
1226 | } | ||
1227 | |||
1228 | void free_initmem(void) | ||
1229 | { | ||
1230 | free_init_pages("unused kernel memory", | ||
1231 | (unsigned long)(&__init_begin), | ||
1232 | (unsigned long)(&__init_end)); | ||
1233 | } | ||
1234 | |||
1235 | #ifdef CONFIG_BLK_DEV_INITRD | 1220 | #ifdef CONFIG_BLK_DEV_INITRD |
1236 | void free_initrd_mem(unsigned long start, unsigned long end) | 1221 | void free_initrd_mem(unsigned long start, unsigned long end) |
1237 | { | 1222 | { |