aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2010-11-03 11:32:21 -0400
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-11-29 20:07:53 -0500
commit805e3f495057aa5307ad4e3d6dc7073d4733c691 (patch)
tree7d5bfeb30f5e178f05b932c20d64f2d9fd98583f /arch/x86
parent31e323cca9d5c8afd372976c35a5d46192f540d1 (diff)
xen: x86/32: perform initial startup on initial_page_table
Only make swapper_pg_dir readonly and pinned when generic x86 architecture code (which also starts on initial_page_table) switches to it. This helps ensure that the generic setup paths work on Xen unmodified. In particular clone_pgd_range writes directly to the destination pgd entries and is used to initialise swapper_pg_dir so we need to ensure that it remains writeable until the last possible moment during bring up. This is complicated slightly by the need to avoid sharing kernel PMD entries when running under Xen, therefore the Xen implementation must make a copy of the kernel PMD (which is otherwise referred to by both intial_page_table and swapper_pg_dir) before switching to swapper_pg_dir. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Cc: Borislav Petkov <bp@alien8.de> Cc: H. Peter Anvin <hpa@linux.intel.com> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/xen/enlighten.c2
-rw-r--r--arch/x86/xen/mmu.c69
2 files changed, 56 insertions, 15 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 4a5973abefc8..0db7303bccb6 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1187,8 +1187,6 @@ asmlinkage void __init xen_start_kernel(void)
1187 /* Allocate and initialize top and mid mfn levels for p2m structure */ 1187 /* Allocate and initialize top and mid mfn levels for p2m structure */
1188 xen_build_mfn_list_list(); 1188 xen_build_mfn_list_list();
1189 1189
1190 init_mm.pgd = pgd;
1191
1192 /* keep using Xen gdt for now; no urgent need to change it */ 1190 /* keep using Xen gdt for now; no urgent need to change it */
1193 1191
1194#ifdef CONFIG_X86_32 1192#ifdef CONFIG_X86_32
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 21ed8d7f75a5..c9cf23e17440 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2119,44 +2119,83 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
2119 return pgd; 2119 return pgd;
2120} 2120}
2121#else /* !CONFIG_X86_64 */ 2121#else /* !CONFIG_X86_64 */
2122static RESERVE_BRK_ARRAY(pmd_t, level2_kernel_pgt, PTRS_PER_PMD); 2122static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
2123static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD);
2124
2125static __init void xen_write_cr3_init(unsigned long cr3)
2126{
2127 unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir));
2128
2129 BUG_ON(read_cr3() != __pa(initial_page_table));
2130 BUG_ON(cr3 != __pa(swapper_pg_dir));
2131
2132 /*
2133 * We are switching to swapper_pg_dir for the first time (from
2134 * initial_page_table) and therefore need to mark that page
2135 * read-only and then pin it.
2136 *
2137 * Xen disallows sharing of kernel PMDs for PAE
2138 * guests. Therefore we must copy the kernel PMD from
2139 * initial_page_table into a new kernel PMD to be used in
2140 * swapper_pg_dir.
2141 */
2142 swapper_kernel_pmd =
2143 extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
2144 memcpy(swapper_kernel_pmd, initial_kernel_pmd,
2145 sizeof(pmd_t) * PTRS_PER_PMD);
2146 swapper_pg_dir[KERNEL_PGD_BOUNDARY] =
2147 __pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT);
2148 set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO);
2149
2150 set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
2151 xen_write_cr3(cr3);
2152 pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, pfn);
2153
2154 pin_pagetable_pfn(MMUEXT_UNPIN_TABLE,
2155 PFN_DOWN(__pa(initial_page_table)));
2156 set_page_prot(initial_page_table, PAGE_KERNEL);
2157 set_page_prot(initial_kernel_pmd, PAGE_KERNEL);
2158
2159 pv_mmu_ops.write_cr3 = &xen_write_cr3;
2160}
2123 2161
2124__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, 2162__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
2125 unsigned long max_pfn) 2163 unsigned long max_pfn)
2126{ 2164{
2127 pmd_t *kernel_pmd; 2165 pmd_t *kernel_pmd;
2128 2166
2129 level2_kernel_pgt = extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE); 2167 initial_kernel_pmd =
2168 extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
2130 2169
2131 max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) + 2170 max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
2132 xen_start_info->nr_pt_frames * PAGE_SIZE + 2171 xen_start_info->nr_pt_frames * PAGE_SIZE +
2133 512*1024); 2172 512*1024);
2134 2173
2135 kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd); 2174 kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
2136 memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); 2175 memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
2137 2176
2138 xen_map_identity_early(level2_kernel_pgt, max_pfn); 2177 xen_map_identity_early(initial_kernel_pmd, max_pfn);
2139 2178
2140 memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD); 2179 memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
2141 set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY], 2180 initial_page_table[KERNEL_PGD_BOUNDARY] =
2142 __pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT)); 2181 __pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT);
2143 2182
2144 set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); 2183 set_page_prot(initial_kernel_pmd, PAGE_KERNEL_RO);
2145 set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO); 2184 set_page_prot(initial_page_table, PAGE_KERNEL_RO);
2146 set_page_prot(empty_zero_page, PAGE_KERNEL_RO); 2185 set_page_prot(empty_zero_page, PAGE_KERNEL_RO);
2147 2186
2148 pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd))); 2187 pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
2149 2188
2150 xen_write_cr3(__pa(swapper_pg_dir)); 2189 pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE,
2151 2190 PFN_DOWN(__pa(initial_page_table)));
2152 pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir))); 2191 xen_write_cr3(__pa(initial_page_table));
2153 2192
2154 memblock_x86_reserve_range(__pa(xen_start_info->pt_base), 2193 memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
2155 __pa(xen_start_info->pt_base + 2194 __pa(xen_start_info->pt_base +
2156 xen_start_info->nr_pt_frames * PAGE_SIZE), 2195 xen_start_info->nr_pt_frames * PAGE_SIZE),
2157 "XEN PAGETABLES"); 2196 "XEN PAGETABLES");
2158 2197
2159 return swapper_pg_dir; 2198 return initial_page_table;
2160} 2199}
2161#endif /* CONFIG_X86_64 */ 2200#endif /* CONFIG_X86_64 */
2162 2201
@@ -2290,7 +2329,11 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
2290 .write_cr2 = xen_write_cr2, 2329 .write_cr2 = xen_write_cr2,
2291 2330
2292 .read_cr3 = xen_read_cr3, 2331 .read_cr3 = xen_read_cr3,
2332#ifdef CONFIG_X86_32
2333 .write_cr3 = xen_write_cr3_init,
2334#else
2293 .write_cr3 = xen_write_cr3, 2335 .write_cr3 = xen_write_cr3,
2336#endif
2294 2337
2295 .flush_tlb_user = xen_flush_tlb, 2338 .flush_tlb_user = xen_flush_tlb,
2296 .flush_tlb_kernel = xen_flush_tlb, 2339 .flush_tlb_kernel = xen_flush_tlb,