aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2010-11-24 07:09:41 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2010-11-24 12:07:44 -0500
commit5b5c1af104ab5adec1be9dcb4c787492d83d8d83 (patch)
tree38292f2f54e581c341e63fe0eeb837907931b753 /arch
parente53beacd23d9cb47590da6a7a7f6d417b941a994 (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> Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Borislav Petkov <bp@alien8.de> Cc: H. Peter Anvin <hpa@linux.intel.com> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch')
-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 235c0f4d3861..ff82909801b6 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1191,8 +1191,6 @@ asmlinkage void __init xen_start_kernel(void)
1191 /* Allocate and initialize top and mid mfn levels for p2m structure */ 1191 /* Allocate and initialize top and mid mfn levels for p2m structure */
1192 xen_build_mfn_list_list(); 1192 xen_build_mfn_list_list();
1193 1193
1194 init_mm.pgd = pgd;
1195
1196 /* keep using Xen gdt for now; no urgent need to change it */ 1194 /* keep using Xen gdt for now; no urgent need to change it */
1197 1195
1198#ifdef CONFIG_X86_32 1196#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,