aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/init_32.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-12 09:05:39 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-12 09:05:39 -0400
commita9b9e81c915e4a57ac3b21d1a7fa7ff184639780 (patch)
tree98304395fbb5b9c74fca35b196cd414c1949f280 /arch/x86/mm/init_32.c
parenta8b71a2810386a5ac8f43d2095fe3355f0d8db37 (diff)
parentfd048088306656824958e7783ffcee27e241b361 (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.c89
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
51unsigned int __VMALLOC_RESERVE = 128 << 20; 52unsigned 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
220repeat:
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
725static void __init find_early_table_space(unsigned long end) 777static 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}