diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-12 09:05:39 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-12 09:05:39 -0400 |
commit | a9b9e81c915e4a57ac3b21d1a7fa7ff184639780 (patch) | |
tree | 98304395fbb5b9c74fca35b196cd414c1949f280 /arch/x86/mm/init_32.c | |
parent | a8b71a2810386a5ac8f43d2095fe3355f0d8db37 (diff) | |
parent | fd048088306656824958e7783ffcee27e241b361 (diff) |
Merge branch 'linus' into x86/memory-corruption-check
Diffstat (limited to 'arch/x86/mm/init_32.c')
-rw-r--r-- | arch/x86/mm/init_32.c | 89 |
1 files changed, 75 insertions, 14 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 657a16ad61ba..7e05462ffb11 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/paravirt.h> | 47 | #include <asm/paravirt.h> |
48 | #include <asm/setup.h> | 48 | #include <asm/setup.h> |
49 | #include <asm/cacheflush.h> | 49 | #include <asm/cacheflush.h> |
50 | #include <asm/smp.h> | ||
50 | 51 | ||
51 | unsigned int __VMALLOC_RESERVE = 128 << 20; | 52 | unsigned int __VMALLOC_RESERVE = 128 << 20; |
52 | 53 | ||
@@ -194,11 +195,30 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
194 | pgd_t *pgd; | 195 | pgd_t *pgd; |
195 | pmd_t *pmd; | 196 | pmd_t *pmd; |
196 | pte_t *pte; | 197 | pte_t *pte; |
197 | unsigned pages_2m = 0, pages_4k = 0; | 198 | unsigned pages_2m, pages_4k; |
199 | int mapping_iter; | ||
200 | |||
201 | /* | ||
202 | * First iteration will setup identity mapping using large/small pages | ||
203 | * based on use_pse, with other attributes same as set by | ||
204 | * the early code in head_32.S | ||
205 | * | ||
206 | * Second iteration will setup the appropriate attributes (NX, GLOBAL..) | ||
207 | * as desired for the kernel identity mapping. | ||
208 | * | ||
209 | * This two pass mechanism conforms to the TLB app note which says: | ||
210 | * | ||
211 | * "Software should not write to a paging-structure entry in a way | ||
212 | * that would change, for any linear address, both the page size | ||
213 | * and either the page frame or attributes." | ||
214 | */ | ||
215 | mapping_iter = 1; | ||
198 | 216 | ||
199 | if (!cpu_has_pse) | 217 | if (!cpu_has_pse) |
200 | use_pse = 0; | 218 | use_pse = 0; |
201 | 219 | ||
220 | repeat: | ||
221 | pages_2m = pages_4k = 0; | ||
202 | pfn = start_pfn; | 222 | pfn = start_pfn; |
203 | pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); | 223 | pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET); |
204 | pgd = pgd_base + pgd_idx; | 224 | pgd = pgd_base + pgd_idx; |
@@ -224,6 +244,13 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
224 | if (use_pse) { | 244 | if (use_pse) { |
225 | unsigned int addr2; | 245 | unsigned int addr2; |
226 | pgprot_t prot = PAGE_KERNEL_LARGE; | 246 | pgprot_t prot = PAGE_KERNEL_LARGE; |
247 | /* | ||
248 | * first pass will use the same initial | ||
249 | * identity mapping attribute + _PAGE_PSE. | ||
250 | */ | ||
251 | pgprot_t init_prot = | ||
252 | __pgprot(PTE_IDENT_ATTR | | ||
253 | _PAGE_PSE); | ||
227 | 254 | ||
228 | addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE + | 255 | addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE + |
229 | PAGE_OFFSET + PAGE_SIZE-1; | 256 | PAGE_OFFSET + PAGE_SIZE-1; |
@@ -233,7 +260,10 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
233 | prot = PAGE_KERNEL_LARGE_EXEC; | 260 | prot = PAGE_KERNEL_LARGE_EXEC; |
234 | 261 | ||
235 | pages_2m++; | 262 | pages_2m++; |
236 | set_pmd(pmd, pfn_pmd(pfn, prot)); | 263 | if (mapping_iter == 1) |
264 | set_pmd(pmd, pfn_pmd(pfn, init_prot)); | ||
265 | else | ||
266 | set_pmd(pmd, pfn_pmd(pfn, prot)); | ||
237 | 267 | ||
238 | pfn += PTRS_PER_PTE; | 268 | pfn += PTRS_PER_PTE; |
239 | continue; | 269 | continue; |
@@ -245,17 +275,43 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base, | |||
245 | for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn; | 275 | for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn; |
246 | pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) { | 276 | pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) { |
247 | pgprot_t prot = PAGE_KERNEL; | 277 | pgprot_t prot = PAGE_KERNEL; |
278 | /* | ||
279 | * first pass will use the same initial | ||
280 | * identity mapping attribute. | ||
281 | */ | ||
282 | pgprot_t init_prot = __pgprot(PTE_IDENT_ATTR); | ||
248 | 283 | ||
249 | if (is_kernel_text(addr)) | 284 | if (is_kernel_text(addr)) |
250 | prot = PAGE_KERNEL_EXEC; | 285 | prot = PAGE_KERNEL_EXEC; |
251 | 286 | ||
252 | pages_4k++; | 287 | pages_4k++; |
253 | set_pte(pte, pfn_pte(pfn, prot)); | 288 | if (mapping_iter == 1) |
289 | set_pte(pte, pfn_pte(pfn, init_prot)); | ||
290 | else | ||
291 | set_pte(pte, pfn_pte(pfn, prot)); | ||
254 | } | 292 | } |
255 | } | 293 | } |
256 | } | 294 | } |
257 | update_page_count(PG_LEVEL_2M, pages_2m); | 295 | if (mapping_iter == 1) { |
258 | update_page_count(PG_LEVEL_4K, pages_4k); | 296 | /* |
297 | * update direct mapping page count only in the first | ||
298 | * iteration. | ||
299 | */ | ||
300 | update_page_count(PG_LEVEL_2M, pages_2m); | ||
301 | update_page_count(PG_LEVEL_4K, pages_4k); | ||
302 | |||
303 | /* | ||
304 | * local global flush tlb, which will flush the previous | ||
305 | * mappings present in both small and large page TLB's. | ||
306 | */ | ||
307 | __flush_tlb_all(); | ||
308 | |||
309 | /* | ||
310 | * Second iteration will set the actual desired PTE attributes. | ||
311 | */ | ||
312 | mapping_iter = 2; | ||
313 | goto repeat; | ||
314 | } | ||
259 | } | 315 | } |
260 | 316 | ||
261 | /* | 317 | /* |
@@ -458,11 +514,7 @@ static void __init pagetable_init(void) | |||
458 | { | 514 | { |
459 | pgd_t *pgd_base = swapper_pg_dir; | 515 | pgd_t *pgd_base = swapper_pg_dir; |
460 | 516 | ||
461 | paravirt_pagetable_setup_start(pgd_base); | ||
462 | |||
463 | permanent_kmaps_init(pgd_base); | 517 | permanent_kmaps_init(pgd_base); |
464 | |||
465 | paravirt_pagetable_setup_done(pgd_base); | ||
466 | } | 518 | } |
467 | 519 | ||
468 | #ifdef CONFIG_ACPI_SLEEP | 520 | #ifdef CONFIG_ACPI_SLEEP |
@@ -722,7 +774,7 @@ void __init setup_bootmem_allocator(void) | |||
722 | after_init_bootmem = 1; | 774 | after_init_bootmem = 1; |
723 | } | 775 | } |
724 | 776 | ||
725 | static void __init find_early_table_space(unsigned long end) | 777 | static void __init find_early_table_space(unsigned long end, int use_pse) |
726 | { | 778 | { |
727 | unsigned long puds, pmds, ptes, tables, start; | 779 | unsigned long puds, pmds, ptes, tables, start; |
728 | 780 | ||
@@ -732,7 +784,7 @@ static void __init find_early_table_space(unsigned long end) | |||
732 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; | 784 | pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; |
733 | tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); | 785 | tables += PAGE_ALIGN(pmds * sizeof(pmd_t)); |
734 | 786 | ||
735 | if (cpu_has_pse) { | 787 | if (use_pse) { |
736 | unsigned long extra; | 788 | unsigned long extra; |
737 | 789 | ||
738 | extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); | 790 | extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); |
@@ -772,12 +824,22 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
772 | pgd_t *pgd_base = swapper_pg_dir; | 824 | pgd_t *pgd_base = swapper_pg_dir; |
773 | unsigned long start_pfn, end_pfn; | 825 | unsigned long start_pfn, end_pfn; |
774 | unsigned long big_page_start; | 826 | unsigned long big_page_start; |
827 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
828 | /* | ||
829 | * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages. | ||
830 | * This will simplify cpa(), which otherwise needs to support splitting | ||
831 | * large pages into small in interrupt context, etc. | ||
832 | */ | ||
833 | int use_pse = 0; | ||
834 | #else | ||
835 | int use_pse = cpu_has_pse; | ||
836 | #endif | ||
775 | 837 | ||
776 | /* | 838 | /* |
777 | * Find space for the kernel direct mapping tables. | 839 | * Find space for the kernel direct mapping tables. |
778 | */ | 840 | */ |
779 | if (!after_init_bootmem) | 841 | if (!after_init_bootmem) |
780 | find_early_table_space(end); | 842 | find_early_table_space(end, use_pse); |
781 | 843 | ||
782 | #ifdef CONFIG_X86_PAE | 844 | #ifdef CONFIG_X86_PAE |
783 | set_nx(); | 845 | set_nx(); |
@@ -823,7 +885,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, | |||
823 | end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); | 885 | end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT); |
824 | if (start_pfn < end_pfn) | 886 | if (start_pfn < end_pfn) |
825 | kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, | 887 | kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, |
826 | cpu_has_pse); | 888 | use_pse); |
827 | 889 | ||
828 | /* tail is not big page alignment ? */ | 890 | /* tail is not big page alignment ? */ |
829 | start_pfn = end_pfn; | 891 | start_pfn = end_pfn; |
@@ -988,7 +1050,6 @@ void __init mem_init(void) | |||
988 | if (boot_cpu_data.wp_works_ok < 0) | 1050 | if (boot_cpu_data.wp_works_ok < 0) |
989 | test_wp_bit(); | 1051 | test_wp_bit(); |
990 | 1052 | ||
991 | cpa_init(); | ||
992 | save_pg_dir(); | 1053 | save_pg_dir(); |
993 | zap_low_mappings(); | 1054 | zap_low_mappings(); |
994 | } | 1055 | } |