diff options
Diffstat (limited to 'arch/x86/mm/init_32.c')
-rw-r--r-- | arch/x86/mm/init_32.c | 90 |
1 files changed, 79 insertions, 11 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 60ec1d08ff24..8396868e82c5 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/cpumask.h> | 31 | #include <linux/cpumask.h> |
32 | 32 | ||
33 | #include <asm/asm.h> | 33 | #include <asm/asm.h> |
34 | #include <asm/bios_ebda.h> | ||
34 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
35 | #include <asm/system.h> | 36 | #include <asm/system.h> |
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
@@ -47,6 +48,7 @@ | |||
47 | #include <asm/paravirt.h> | 48 | #include <asm/paravirt.h> |
48 | #include <asm/setup.h> | 49 | #include <asm/setup.h> |
49 | #include <asm/cacheflush.h> | 50 | #include <asm/cacheflush.h> |
51 | #include <asm/smp.h> | ||
50 | 52 | ||
51 | unsigned int __VMALLOC_RESERVE = 128 << 20; | 53 | unsigned int __VMALLOC_RESERVE = 128 << 20; |
52 | 54 | ||
@@ -194,11 +196,30 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
194 | pgd_t *pgd; | 196 | pgd_t *pgd; |
195 | pmd_t *pmd; | 197 | pmd_t *pmd; |
196 | pte_t *pte; | 198 | pte_t *pte; |
197 | unsigned pages_2m = 0, pages_4k = 0; | 199 | unsigned pages_2m, pages_4k; |
200 | int mapping_iter; | ||
201 | |||
202 | /* | ||
203 | * First iteration will setup identity mapping using large/small pages | ||
204 | * based on use_pse, with other attributes same as set by | ||
205 | * the early code in head_32.S | ||
206 | * | ||
207 | * Second iteration will setup the appropriate attributes (NX, GLOBAL..) | ||
208 | * as desired for the kernel identity mapping. | ||
209 | * | ||
210 | * This two pass mechanism conforms to the TLB app note which says: | ||
211 | * | ||
212 | * "Software should not write to a paging-structure entry in a way | ||
213 | * that would change, for any linear address, both the page size | ||
214 | * and either the page frame or attributes." | ||
215 | */ | ||
216 | mapping_iter = 1; | ||
198 | 217 | ||
199 | if (!cpu_has_pse) | 218 | if (!cpu_has_pse) |
200 | use_pse = 0; | 219 | use_pse = 0; |
201 | 220 | ||
221 | repeat: | ||
222 | pages_2m = pages_4k = 0; | ||
202 | pfn = start_pfn; | 223 | pfn = start_pfn; |
203 | pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); | 224 | pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); |
204 | pgd = pgd_base + pgd_idx; | 225 | pgd = pgd_base + pgd_idx; |
@@ -224,6 +245,13 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
224 | if (use_pse) { | 245 | if (use_pse) { |
225 | unsigned int addr2; | 246 | unsigned int addr2; |
226 | pgprot_t prot = PAGE_KERNEL_LARGE; | 247 | pgprot_t prot = PAGE_KERNEL_LARGE; |
248 | /* | ||
249 | * first pass will use the same initial | ||
250 | * identity mapping attribute + _PAGE_PSE. | ||
251 | */ | ||
252 | pgprot_t init_prot = | ||
253 | __pgprot(PTE_IDENT_ATTR | | ||
254 | _PAGE_PSE); | ||
227 | 255 | ||
228 | addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE + | 256 | addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE + |
229 | PAGE_OFFSET + PAGE_SIZE-1; | 257 | PAGE_OFFSET + PAGE_SIZE-1; |
@@ -233,7 +261,10 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
233 | prot = PAGE_KERNEL_LARGE_EXEC; | 261 | prot = PAGE_KERNEL_LARGE_EXEC; |
234 | 262 | ||
235 | pages_2m++; | 263 | pages_2m++; |
236 | set_pmd(pmd, pfn_pmd(pfn, prot)); | 264 | if (mapping_iter == 1) |
265 | set_pmd(pmd, pfn_pmd(pfn, init_prot)); | ||
266 | else | ||
267 | set_pmd(pmd, pfn_pmd(pfn, prot)); | ||
237 | 268 | ||
238 | pfn += PTRS_PER_PTE; | 269 | pfn += PTRS_PER_PTE; |
239 | continue; | 270 | continue; |
@@ -245,17 +276,43 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
245 | for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn; | 276 | for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn; |
246 | pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) { | 277 | pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) { |
247 | pgprot_t prot = PAGE_KERNEL; | 278 | pgprot_t prot = PAGE_KERNEL; |
279 | /* | ||
280 | * first pass will use the same initial | ||
281 | * identity mapping attribute. | ||
282 | */ | ||
283 | pgprot_t init_prot = __pgprot(PTE_IDENT_ATTR); | ||
248 | 284 | ||
249 | if (is_kernel_text(addr)) | 285 | if (is_kernel_text(addr)) |
250 | prot = PAGE_KERNEL_EXEC; | 286 | prot = PAGE_KERNEL_EXEC; |
251 | 287 | ||
252 | pages_4k++; | 288 | pages_4k++; |
253 | set_pte(pte, pfn_pte(pfn, prot)); | 289 | if (mapping_iter == 1) |
290 | set_pte(pte, pfn_pte(pfn, init_prot)); | ||
291 | else | ||
292 | set_pte(pte, pfn_pte(pfn, prot)); | ||
254 | } | 293 | } |
255 | } | 294 | } |
256 | } | 295 | } |
257 | update_page_count(PG_LEVEL_2M, pages_2m); | 296 | if (mapping_iter == 1) { |
258 | update_page_count(PG_LEVEL_4K, pages_4k); | 297 | /* |
298 | * update direct mapping page count only in the first | ||
299 | * iteration. | ||
300 | */ | ||
301 | update_page_count(PG_LEVEL_2M, pages_2m); | ||
302 | update_page_count(PG_LEVEL_4K, pages_4k); | ||
303 | |||
304 | /* | ||
305 | * local global flush tlb, which will flush the previous | ||
306 | * mappings present in both small and large page TLB's. | ||
307 | */ | ||
308 | __flush_tlb_all(); | ||
309 | |||
310 | /* | ||
311 | * Second iteration will set the actual desired PTE attributes. | ||
312 | */ | ||
313 | mapping_iter = 2; | ||
314 | goto repeat; | ||
315 | } | ||
259 | } | 316 | } |
260 | 317 | ||
261 | /* | 318 | /* |
@@ -501,7 +558,7 @@ void zap_low_mappings(void) | |||
501 | 558 | ||
502 | int nx_enabled; | 559 | int nx_enabled; |
503 | 560 | ||
504 | pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL); | 561 | pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP); |
505 | EXPORT_SYMBOL_GPL(__supported_pte_mask); | 562 | EXPORT_SYMBOL_GPL(__supported_pte_mask); |
506 | 563 | ||
507 | #ifdef CONFIG_X86_PAE | 564 | #ifdef CONFIG_X86_PAE |
@@ -718,7 +775,7 @@ void __init setup_bootmem_allocator(void) | |||
718 | after_init_bootmem = 1; | 775 | after_init_bootmem = 1; |
719 | } | 776 | } |
720 | 777 | ||
721 | static void __init find_early_table_space(unsigned long end) | 778 | static void __init find_early_table_space(unsigned long end, int use_pse) |
722 | { | 779 | { |
723 | unsigned long puds, pmds, ptes, tables, start; | 780 | unsigned long puds, pmds, ptes, tables, start; |
724 | 781 | ||
@@ -728,7 +785,7 @@ static void __init find_early_table_space(unsigned long end) | |||
728 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; | 785 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; |
729 | tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); | 786 | tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); |
730 | 787 | ||
731 | if (cpu_has_pse) { | 788 | if (use_pse) { |
732 | unsigned long extra; | 789 | unsigned long extra; |
733 | 790 | ||
734 | extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); | 791 | extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); |
@@ -768,12 +825,22 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
768 | pgd_t *pgd_base = swapper_pg_dir; | 825 | pgd_t *pgd_base = swapper_pg_dir; |
769 | unsigned long start_pfn, end_pfn; | 826 | unsigned long start_pfn, end_pfn; |
770 | unsigned long big_page_start; | 827 | unsigned long big_page_start; |
828 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
829 | /* | ||
830 | * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages. | ||
831 | * This will simplify cpa(), which otherwise needs to support splitting | ||
832 | * large pages into small in interrupt context, etc. | ||
833 | */ | ||
834 | int use_pse = 0; | ||
835 | #else | ||
836 | int use_pse = cpu_has_pse; | ||
837 | #endif | ||
771 | 838 | ||
772 | /* | 839 | /* |
773 | * Find space for the kernel direct mapping tables. | 840 | * Find space for the kernel direct mapping tables. |
774 | */ | 841 | */ |
775 | if (!after_init_bootmem) | 842 | if (!after_init_bootmem) |
776 | find_early_table_space(end); | 843 | find_early_table_space(end, use_pse); |
777 | 844 | ||
778 | #ifdef CONFIG_X86_PAE | 845 | #ifdef CONFIG_X86_PAE |
779 | set_nx(); | 846 | set_nx(); |
@@ -819,7 +886,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
819 | end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); | 886 | end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); |
820 | if (start_pfn < end_pfn) | 887 | if (start_pfn < end_pfn) |
821 | kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, | 888 | kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, |
822 | cpu_has_pse); | 889 | use_pse); |
823 | 890 | ||
824 | /* tail is not big page alignment ? */ | 891 | /* tail is not big page alignment ? */ |
825 | start_pfn = end_pfn; | 892 | start_pfn = end_pfn; |
@@ -903,6 +970,8 @@ void __init mem_init(void) | |||
903 | int codesize, reservedpages, datasize, initsize; | 970 | int codesize, reservedpages, datasize, initsize; |
904 | int tmp; | 971 | int tmp; |
905 | 972 | ||
973 | start_periodic_check_for_corruption(); | ||
974 | |||
906 | #ifdef CONFIG_FLATMEM | 975 | #ifdef CONFIG_FLATMEM |
907 | BUG_ON(!mem_map); | 976 | BUG_ON(!mem_map); |
908 | #endif | 977 | #endif |
@@ -982,7 +1051,6 @@ void __init mem_init(void) | |||
982 | if (boot_cpu_data.wp_works_ok < 0) | 1051 | if (boot_cpu_data.wp_works_ok < 0) |
983 | test_wp_bit(); | 1052 | test_wp_bit(); |
984 | 1053 | ||
985 | cpa_init(); | ||
986 | save_pg_dir(); | 1054 | save_pg_dir(); |
987 | zap_low_mappings(); | 1055 | zap_low_mappings(); |
988 | } | 1056 | } |