diff options
-rw-r--r-- | arch/i386/kernel/paravirt.c | 3 | ||||
-rw-r--r-- | arch/i386/mm/init.c | 138 | ||||
-rw-r--r-- | include/asm-i386/paravirt.h | 17 | ||||
-rw-r--r-- | include/asm-i386/pgtable.h | 16 |
4 files changed, 126 insertions, 48 deletions
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index cba7a15ce1b0..47d075bdfb95 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c | |||
@@ -193,6 +193,9 @@ struct paravirt_ops paravirt_ops = { | |||
193 | #endif | 193 | #endif |
194 | .set_lazy_mode = paravirt_nop, | 194 | .set_lazy_mode = paravirt_nop, |
195 | 195 | ||
196 | .pagetable_setup_start = native_pagetable_setup_start, | ||
197 | .pagetable_setup_done = native_pagetable_setup_done, | ||
198 | |||
196 | .flush_tlb_user = native_flush_tlb, | 199 | .flush_tlb_user = native_flush_tlb, |
197 | .flush_tlb_kernel = native_flush_tlb_global, | 200 | .flush_tlb_kernel = native_flush_tlb_global, |
198 | .flush_tlb_single = native_flush_tlb_single, | 201 | .flush_tlb_single = native_flush_tlb_single, |
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index bd5ef3718504..e8545dcf06c5 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/tlb.h> | 43 | #include <asm/tlb.h> |
44 | #include <asm/tlbflush.h> | 44 | #include <asm/tlbflush.h> |
45 | #include <asm/sections.h> | 45 | #include <asm/sections.h> |
46 | #include <asm/paravirt.h> | ||
46 | 47 | ||
47 | unsigned int __VMALLOC_RESERVE = 128 << 20; | 48 | unsigned int __VMALLOC_RESERVE = 128 << 20; |
48 | 49 | ||
@@ -62,17 +63,18 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) | |||
62 | pmd_t *pmd_table; | 63 | pmd_t *pmd_table; |
63 | 64 | ||
64 | #ifdef CONFIG_X86_PAE | 65 | #ifdef CONFIG_X86_PAE |
65 | pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); | 66 | if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { |
66 | paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); | 67 | pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); |
67 | set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); | 68 | |
68 | pud = pud_offset(pgd, 0); | 69 | paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); |
69 | if (pmd_table != pmd_offset(pud, 0)) | 70 | set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); |
70 | BUG(); | 71 | pud = pud_offset(pgd, 0); |
71 | #else | 72 | if (pmd_table != pmd_offset(pud, 0)) |
73 | BUG(); | ||
74 | } | ||
75 | #endif | ||
72 | pud = pud_offset(pgd, 0); | 76 | pud = pud_offset(pgd, 0); |
73 | pmd_table = pmd_offset(pud, 0); | 77 | pmd_table = pmd_offset(pud, 0); |
74 | #endif | ||
75 | |||
76 | return pmd_table; | 78 | return pmd_table; |
77 | } | 79 | } |
78 | 80 | ||
@@ -82,14 +84,12 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) | |||
82 | */ | 84 | */ |
83 | static pte_t * __init one_page_table_init(pmd_t *pmd) | 85 | static pte_t * __init one_page_table_init(pmd_t *pmd) |
84 | { | 86 | { |
85 | if (pmd_none(*pmd)) { | 87 | if (!(pmd_val(*pmd) & _PAGE_PRESENT)) { |
86 | pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); | 88 | pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); |
89 | |||
87 | paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); | 90 | paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); |
88 | set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); | 91 | set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); |
89 | if (page_table != pte_offset_kernel(pmd, 0)) | 92 | BUG_ON(page_table != pte_offset_kernel(pmd, 0)); |
90 | BUG(); | ||
91 | |||
92 | return page_table; | ||
93 | } | 93 | } |
94 | 94 | ||
95 | return pte_offset_kernel(pmd, 0); | 95 | return pte_offset_kernel(pmd, 0); |
@@ -109,7 +109,6 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) | |||
109 | static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) | 109 | static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) |
110 | { | 110 | { |
111 | pgd_t *pgd; | 111 | pgd_t *pgd; |
112 | pud_t *pud; | ||
113 | pmd_t *pmd; | 112 | pmd_t *pmd; |
114 | int pgd_idx, pmd_idx; | 113 | int pgd_idx, pmd_idx; |
115 | unsigned long vaddr; | 114 | unsigned long vaddr; |
@@ -120,13 +119,10 @@ static void __init page_table_range_init (unsigned long start, unsigned long end | |||
120 | pgd = pgd_base + pgd_idx; | 119 | pgd = pgd_base + pgd_idx; |
121 | 120 | ||
122 | for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { | 121 | for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { |
123 | if (pgd_none(*pgd)) | 122 | pmd = one_md_table_init(pgd); |
124 | one_md_table_init(pgd); | 123 | pmd = pmd + pmd_index(vaddr); |
125 | pud = pud_offset(pgd, vaddr); | ||
126 | pmd = pmd_offset(pud, vaddr); | ||
127 | for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { | 124 | for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { |
128 | if (pmd_none(*pmd)) | 125 | one_page_table_init(pmd); |
129 | one_page_table_init(pmd); | ||
130 | 126 | ||
131 | vaddr += PMD_SIZE; | 127 | vaddr += PMD_SIZE; |
132 | } | 128 | } |
@@ -168,20 +164,22 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
168 | /* Map with big pages if possible, otherwise create normal page tables. */ | 164 | /* Map with big pages if possible, otherwise create normal page tables. */ |
169 | if (cpu_has_pse) { | 165 | if (cpu_has_pse) { |
170 | unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; | 166 | unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; |
171 | |||
172 | if (is_kernel_text(address) || is_kernel_text(address2)) | 167 | if (is_kernel_text(address) || is_kernel_text(address2)) |
173 | set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); | 168 | set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); |
174 | else | 169 | else |
175 | set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); | 170 | set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); |
171 | |||
176 | pfn += PTRS_PER_PTE; | 172 | pfn += PTRS_PER_PTE; |
177 | } else { | 173 | } else { |
178 | pte = one_page_table_init(pmd); | 174 | pte = one_page_table_init(pmd); |
179 | 175 | ||
180 | for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { | 176 | for (pte_ofs = 0; |
181 | if (is_kernel_text(address)) | 177 | pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; |
182 | set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); | 178 | pte++, pfn++, pte_ofs++, address += PAGE_SIZE) { |
183 | else | 179 | if (is_kernel_text(address)) |
184 | set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); | 180 | set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); |
181 | else | ||
182 | set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); | ||
185 | } | 183 | } |
186 | } | 184 | } |
187 | } | 185 | } |
@@ -338,24 +336,78 @@ extern void __init remap_numa_kva(void); | |||
338 | #define remap_numa_kva() do {} while (0) | 336 | #define remap_numa_kva() do {} while (0) |
339 | #endif | 337 | #endif |
340 | 338 | ||
341 | static void __init pagetable_init (void) | 339 | void __init native_pagetable_setup_start(pgd_t *base) |
342 | { | 340 | { |
343 | unsigned long vaddr; | ||
344 | pgd_t *pgd_base = swapper_pg_dir; | ||
345 | |||
346 | #ifdef CONFIG_X86_PAE | 341 | #ifdef CONFIG_X86_PAE |
347 | int i; | 342 | int i; |
348 | /* Init entries of the first-level page table to the zero page */ | 343 | |
349 | for (i = 0; i < PTRS_PER_PGD; i++) | 344 | /* |
350 | set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); | 345 | * Init entries of the first-level page table to the |
346 | * zero page, if they haven't already been set up. | ||
347 | * | ||
348 | * In a normal native boot, we'll be running on a | ||
349 | * pagetable rooted in swapper_pg_dir, but not in PAE | ||
350 | * mode, so this will end up clobbering the mappings | ||
351 | * for the lower 24Mbytes of the address space, | ||
352 | * without affecting the kernel address space. | ||
353 | */ | ||
354 | for (i = 0; i < USER_PTRS_PER_PGD; i++) | ||
355 | set_pgd(&base[i], | ||
356 | __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); | ||
357 | |||
358 | /* Make sure kernel address space is empty so that a pagetable | ||
359 | will be allocated for it. */ | ||
360 | memset(&base[USER_PTRS_PER_PGD], 0, | ||
361 | KERNEL_PGD_PTRS * sizeof(pgd_t)); | ||
351 | #else | 362 | #else |
352 | paravirt_alloc_pd(__pa(swapper_pg_dir) >> PAGE_SHIFT); | 363 | paravirt_alloc_pd(__pa(swapper_pg_dir) >> PAGE_SHIFT); |
353 | #endif | 364 | #endif |
365 | } | ||
366 | |||
367 | void __init native_pagetable_setup_done(pgd_t *base) | ||
368 | { | ||
369 | #ifdef CONFIG_X86_PAE | ||
370 | /* | ||
371 | * Add low memory identity-mappings - SMP needs it when | ||
372 | * starting up on an AP from real-mode. In the non-PAE | ||
373 | * case we already have these mappings through head.S. | ||
374 | * All user-space mappings are explicitly cleared after | ||
375 | * SMP startup. | ||
376 | */ | ||
377 | set_pgd(&base[0], base[USER_PTRS_PER_PGD]); | ||
378 | #endif | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Build a proper pagetable for the kernel mappings. Up until this | ||
383 | * point, we've been running on some set of pagetables constructed by | ||
384 | * the boot process. | ||
385 | * | ||
386 | * If we're booting on native hardware, this will be a pagetable | ||
387 | * constructed in arch/i386/kernel/head.S, and not running in PAE mode | ||
388 | * (even if we'll end up running in PAE). The root of the pagetable | ||
389 | * will be swapper_pg_dir. | ||
390 | * | ||
391 | * If we're booting paravirtualized under a hypervisor, then there are | ||
392 | * more options: we may already be running PAE, and the pagetable may | ||
393 | * or may not be based in swapper_pg_dir. In any case, | ||
394 | * paravirt_pagetable_setup_start() will set up swapper_pg_dir | ||
395 | * appropriately for the rest of the initialization to work. | ||
396 | * | ||
397 | * In general, pagetable_init() assumes that the pagetable may already | ||
398 | * be partially populated, and so it avoids stomping on any existing | ||
399 | * mappings. | ||
400 | */ | ||
401 | static void __init pagetable_init (void) | ||
402 | { | ||
403 | unsigned long vaddr, end; | ||
404 | pgd_t *pgd_base = swapper_pg_dir; | ||
405 | |||
406 | paravirt_pagetable_setup_start(pgd_base); | ||
354 | 407 | ||
355 | /* Enable PSE if available */ | 408 | /* Enable PSE if available */ |
356 | if (cpu_has_pse) { | 409 | if (cpu_has_pse) |
357 | set_in_cr4(X86_CR4_PSE); | 410 | set_in_cr4(X86_CR4_PSE); |
358 | } | ||
359 | 411 | ||
360 | /* Enable PGE if available */ | 412 | /* Enable PGE if available */ |
361 | if (cpu_has_pge) { | 413 | if (cpu_has_pge) { |
@@ -372,20 +424,12 @@ static void __init pagetable_init (void) | |||
372 | * created - mappings will be set by set_fixmap(): | 424 | * created - mappings will be set by set_fixmap(): |
373 | */ | 425 | */ |
374 | vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; | 426 | vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; |
375 | page_table_range_init(vaddr, 0, pgd_base); | 427 | end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; |
428 | page_table_range_init(vaddr, end, pgd_base); | ||
376 | 429 | ||
377 | permanent_kmaps_init(pgd_base); | 430 | permanent_kmaps_init(pgd_base); |
378 | 431 | ||
379 | #ifdef CONFIG_X86_PAE | 432 | paravirt_pagetable_setup_done(pgd_base); |
380 | /* | ||
381 | * Add low memory identity-mappings - SMP needs it when | ||
382 | * starting up on an AP from real-mode. In the non-PAE | ||
383 | * case we already have these mappings through head.S. | ||
384 | * All user-space mappings are explicitly cleared after | ||
385 | * SMP startup. | ||
386 | */ | ||
387 | set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]); | ||
388 | #endif | ||
389 | } | 433 | } |
390 | 434 | ||
391 | #if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP) | 435 | #if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP) |
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h index 0aacb13bb929..c49b44cdd8ee 100644 --- a/include/asm-i386/paravirt.h +++ b/include/asm-i386/paravirt.h | |||
@@ -2,10 +2,11 @@ | |||
2 | #define __ASM_PARAVIRT_H | 2 | #define __ASM_PARAVIRT_H |
3 | /* Various instructions on x86 need to be replaced for | 3 | /* Various instructions on x86 need to be replaced for |
4 | * para-virtualization: those hooks are defined here. */ | 4 | * para-virtualization: those hooks are defined here. */ |
5 | |||
6 | #ifdef CONFIG_PARAVIRT | ||
5 | #include <linux/stringify.h> | 7 | #include <linux/stringify.h> |
6 | #include <asm/page.h> | 8 | #include <asm/page.h> |
7 | 9 | ||
8 | #ifdef CONFIG_PARAVIRT | ||
9 | /* These are the most performance critical ops, so we want to be able to patch | 10 | /* These are the most performance critical ops, so we want to be able to patch |
10 | * callers */ | 11 | * callers */ |
11 | #define PARAVIRT_IRQ_DISABLE 0 | 12 | #define PARAVIRT_IRQ_DISABLE 0 |
@@ -50,6 +51,9 @@ struct paravirt_ops | |||
50 | char *(*memory_setup)(void); | 51 | char *(*memory_setup)(void); |
51 | void (*init_IRQ)(void); | 52 | void (*init_IRQ)(void); |
52 | 53 | ||
54 | void (*pagetable_setup_start)(pgd_t *pgd_base); | ||
55 | void (*pagetable_setup_done)(pgd_t *pgd_base); | ||
56 | |||
53 | void (*banner)(void); | 57 | void (*banner)(void); |
54 | 58 | ||
55 | unsigned long (*get_wallclock)(void); | 59 | unsigned long (*get_wallclock)(void); |
@@ -370,6 +374,17 @@ static inline void setup_secondary_clock(void) | |||
370 | } | 374 | } |
371 | #endif | 375 | #endif |
372 | 376 | ||
377 | static inline void paravirt_pagetable_setup_start(pgd_t *base) | ||
378 | { | ||
379 | if (paravirt_ops.pagetable_setup_start) | ||
380 | (*paravirt_ops.pagetable_setup_start)(base); | ||
381 | } | ||
382 | |||
383 | static inline void paravirt_pagetable_setup_done(pgd_t *base) | ||
384 | { | ||
385 | if (paravirt_ops.pagetable_setup_done) | ||
386 | (*paravirt_ops.pagetable_setup_done)(base); | ||
387 | } | ||
373 | 388 | ||
374 | #ifdef CONFIG_SMP | 389 | #ifdef CONFIG_SMP |
375 | static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip, | 390 | static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip, |
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 147f2553784d..0790ad6ed440 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h | |||
@@ -514,6 +514,22 @@ do { \ | |||
514 | * tables contain all the necessary information. | 514 | * tables contain all the necessary information. |
515 | */ | 515 | */ |
516 | #define update_mmu_cache(vma,address,pte) do { } while (0) | 516 | #define update_mmu_cache(vma,address,pte) do { } while (0) |
517 | |||
518 | void native_pagetable_setup_start(pgd_t *base); | ||
519 | void native_pagetable_setup_done(pgd_t *base); | ||
520 | |||
521 | #ifndef CONFIG_PARAVIRT | ||
522 | static inline void paravirt_pagetable_setup_start(pgd_t *base) | ||
523 | { | ||
524 | native_pagetable_setup_start(base); | ||
525 | } | ||
526 | |||
527 | static inline void paravirt_pagetable_setup_done(pgd_t *base) | ||
528 | { | ||
529 | native_pagetable_setup_done(base); | ||
530 | } | ||
531 | #endif /* !CONFIG_PARAVIRT */ | ||
532 | |||
517 | #endif /* !__ASSEMBLY__ */ | 533 | #endif /* !__ASSEMBLY__ */ |
518 | 534 | ||
519 | #ifdef CONFIG_FLATMEM | 535 | #ifdef CONFIG_FLATMEM |