|
@@ -2119,44 +2119,83 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
|
|
return pgd;
|
|
return pgd;
|
|
}
|
|
}
|
|
#else /* !CONFIG_X86_64 */
|
|
#else /* !CONFIG_X86_64 */
|
|
-static RESERVE_BRK_ARRAY(pmd_t, level2_kernel_pgt, PTRS_PER_PMD);
|
|
|
|
|
|
+static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
|
|
|
|
+static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD);
|
|
|
|
+
|
|
|
|
+static __init void xen_write_cr3_init(unsigned long cr3)
|
|
|
|
+{
|
|
|
|
+ unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir));
|
|
|
|
+
|
|
|
|
+ BUG_ON(read_cr3() != __pa(initial_page_table));
|
|
|
|
+ BUG_ON(cr3 != __pa(swapper_pg_dir));
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We are switching to swapper_pg_dir for the first time (from
|
|
|
|
+ * initial_page_table) and therefore need to mark that page
|
|
|
|
+ * read-only and then pin it.
|
|
|
|
+ *
|
|
|
|
+ * Xen disallows sharing of kernel PMDs for PAE
|
|
|
|
+ * guests. Therefore we must copy the kernel PMD from
|
|
|
|
+ * initial_page_table into a new kernel PMD to be used in
|
|
|
|
+ * swapper_pg_dir.
|
|
|
|
+ */
|
|
|
|
+ swapper_kernel_pmd =
|
|
|
|
+ extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
|
|
|
|
+ memcpy(swapper_kernel_pmd, initial_kernel_pmd,
|
|
|
|
+ sizeof(pmd_t) * PTRS_PER_PMD);
|
|
|
|
+ swapper_pg_dir[KERNEL_PGD_BOUNDARY] =
|
|
|
|
+ __pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT);
|
|
|
|
+ set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO);
|
|
|
|
+
|
|
|
|
+ set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
|
|
|
|
+ xen_write_cr3(cr3);
|
|
|
|
+ pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, pfn);
|
|
|
|
+
|
|
|
|
+ pin_pagetable_pfn(MMUEXT_UNPIN_TABLE,
|
|
|
|
+ PFN_DOWN(__pa(initial_page_table)));
|
|
|
|
+ set_page_prot(initial_page_table, PAGE_KERNEL);
|
|
|
|
+ set_page_prot(initial_kernel_pmd, PAGE_KERNEL);
|
|
|
|
+
|
|
|
|
+ pv_mmu_ops.write_cr3 = &xen_write_cr3;
|
|
|
|
+}
|
|
|
|
|
|
__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
|
|
__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
|
|
unsigned long max_pfn)
|
|
unsigned long max_pfn)
|
|
{
|
|
{
|
|
pmd_t *kernel_pmd;
|
|
pmd_t *kernel_pmd;
|
|
|
|
|
|
- level2_kernel_pgt = extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
|
|
|
|
|
|
+ initial_kernel_pmd =
|
|
|
|
+ extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
|
|
|
|
|
|
max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
|
|
max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
|
|
xen_start_info->nr_pt_frames * PAGE_SIZE +
|
|
xen_start_info->nr_pt_frames * PAGE_SIZE +
|
|
512*1024);
|
|
512*1024);
|
|
|
|
|
|
kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
|
|
kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
|
|
- memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
|
|
|
|
|
|
+ memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
|
|
|
|
|
|
- xen_map_identity_early(level2_kernel_pgt, max_pfn);
|
|
|
|
|
|
+ xen_map_identity_early(initial_kernel_pmd, max_pfn);
|
|
|
|
|
|
- memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
|
|
|
|
- set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY],
|
|
|
|
- __pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT));
|
|
|
|
|
|
+ memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
|
|
|
|
+ initial_page_table[KERNEL_PGD_BOUNDARY] =
|
|
|
|
+ __pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT);
|
|
|
|
|
|
- set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO);
|
|
|
|
- set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
|
|
|
|
|
|
+ set_page_prot(initial_kernel_pmd, PAGE_KERNEL_RO);
|
|
|
|
+ set_page_prot(initial_page_table, PAGE_KERNEL_RO);
|
|
set_page_prot(empty_zero_page, PAGE_KERNEL_RO);
|
|
set_page_prot(empty_zero_page, PAGE_KERNEL_RO);
|
|
|
|
|
|
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
|
|
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
|
|
|
|
|
|
- xen_write_cr3(__pa(swapper_pg_dir));
|
|
|
|
-
|
|
|
|
- pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir)));
|
|
|
|
|
|
+ pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE,
|
|
|
|
+ PFN_DOWN(__pa(initial_page_table)));
|
|
|
|
+ xen_write_cr3(__pa(initial_page_table));
|
|
|
|
|
|
memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
|
|
memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
|
|
__pa(xen_start_info->pt_base +
|
|
__pa(xen_start_info->pt_base +
|
|
xen_start_info->nr_pt_frames * PAGE_SIZE),
|
|
xen_start_info->nr_pt_frames * PAGE_SIZE),
|
|
"XEN PAGETABLES");
|
|
"XEN PAGETABLES");
|
|
|
|
|
|
- return swapper_pg_dir;
|
|
|
|
|
|
+ return initial_page_table;
|
|
}
|
|
}
|
|
#endif /* CONFIG_X86_64 */
|
|
#endif /* CONFIG_X86_64 */
|
|
|
|
|
|
@@ -2290,7 +2329,11 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
|
.write_cr2 = xen_write_cr2,
|
|
.write_cr2 = xen_write_cr2,
|
|
|
|
|
|
.read_cr3 = xen_read_cr3,
|
|
.read_cr3 = xen_read_cr3,
|
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
|
+ .write_cr3 = xen_write_cr3_init,
|
|
|
|
+#else
|
|
.write_cr3 = xen_write_cr3,
|
|
.write_cr3 = xen_write_cr3,
|
|
|
|
+#endif
|
|
|
|
|
|
.flush_tlb_user = xen_flush_tlb,
|
|
.flush_tlb_user = xen_flush_tlb,
|
|
.flush_tlb_kernel = xen_flush_tlb,
|
|
.flush_tlb_kernel = xen_flush_tlb,
|