aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen/mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/xen/mmu.c')
-rw-r--r--arch/x86/xen/mmu.c134
1 files changed, 90 insertions, 44 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index db3802fb7b84..77b242c9a11e 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -184,7 +184,7 @@ static inline unsigned p2m_index(unsigned long pfn)
184} 184}
185 185
186/* Build the parallel p2m_top_mfn structures */ 186/* Build the parallel p2m_top_mfn structures */
187void xen_setup_mfn_list_list(void) 187static void __init xen_build_mfn_list_list(void)
188{ 188{
189 unsigned pfn, idx; 189 unsigned pfn, idx;
190 190
@@ -198,7 +198,10 @@ void xen_setup_mfn_list_list(void)
198 unsigned topidx = idx * P2M_ENTRIES_PER_PAGE; 198 unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
199 p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]); 199 p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
200 } 200 }
201}
201 202
203void xen_setup_mfn_list_list(void)
204{
202 BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); 205 BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
203 206
204 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 207 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
@@ -218,6 +221,8 @@ void __init xen_build_dynamic_phys_to_machine(void)
218 221
219 p2m_top[topidx] = &mfn_list[pfn]; 222 p2m_top[topidx] = &mfn_list[pfn];
220 } 223 }
224
225 xen_build_mfn_list_list();
221} 226}
222 227
223unsigned long get_phys_to_machine(unsigned long pfn) 228unsigned long get_phys_to_machine(unsigned long pfn)
@@ -233,47 +238,74 @@ unsigned long get_phys_to_machine(unsigned long pfn)
233} 238}
234EXPORT_SYMBOL_GPL(get_phys_to_machine); 239EXPORT_SYMBOL_GPL(get_phys_to_machine);
235 240
236static void alloc_p2m(unsigned long **pp, unsigned long *mfnp) 241/* install a new p2m_top page */
242bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
237{ 243{
238 unsigned long *p; 244 unsigned topidx = p2m_top_index(pfn);
245 unsigned long **pfnp, *mfnp;
239 unsigned i; 246 unsigned i;
240 247
241 p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); 248 pfnp = &p2m_top[topidx];
242 BUG_ON(p == NULL); 249 mfnp = &p2m_top_mfn[topidx];
243 250
244 for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) 251 for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
245 p[i] = INVALID_P2M_ENTRY; 252 p[i] = INVALID_P2M_ENTRY;
246 253
247 if (cmpxchg(pp, p2m_missing, p) != p2m_missing) 254 if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
248 free_page((unsigned long)p);
249 else
250 *mfnp = virt_to_mfn(p); 255 *mfnp = virt_to_mfn(p);
256 return true;
257 }
258
259 return false;
251} 260}
252 261
253void set_phys_to_machine(unsigned long pfn, unsigned long mfn) 262static void alloc_p2m(unsigned long pfn)
254{ 263{
255 unsigned topidx, idx; 264 unsigned long *p;
256 265
257 if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { 266 p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
258 BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); 267 BUG_ON(p == NULL);
259 return; 268
260 } 269 if (!install_p2mtop_page(pfn, p))
270 free_page((unsigned long)p);
271}
272
273/* Try to install p2m mapping; fail if intermediate bits missing */
274bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
275{
276 unsigned topidx, idx;
261 277
262 if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { 278 if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
263 BUG_ON(mfn != INVALID_P2M_ENTRY); 279 BUG_ON(mfn != INVALID_P2M_ENTRY);
264 return; 280 return true;
265 } 281 }
266 282
267 topidx = p2m_top_index(pfn); 283 topidx = p2m_top_index(pfn);
268 if (p2m_top[topidx] == p2m_missing) { 284 if (p2m_top[topidx] == p2m_missing) {
269 /* no need to allocate a page to store an invalid entry */
270 if (mfn == INVALID_P2M_ENTRY) 285 if (mfn == INVALID_P2M_ENTRY)
271 return; 286 return true;
272 alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]); 287 return false;
273 } 288 }
274 289
275 idx = p2m_index(pfn); 290 idx = p2m_index(pfn);
276 p2m_top[topidx][idx] = mfn; 291 p2m_top[topidx][idx] = mfn;
292
293 return true;
294}
295
296void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
297{
298 if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
299 BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
300 return;
301 }
302
303 if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
304 alloc_p2m(pfn);
305
306 if (!__set_phys_to_machine(pfn, mfn))
307 BUG();
308 }
277} 309}
278 310
279unsigned long arbitrary_virt_to_mfn(void *vaddr) 311unsigned long arbitrary_virt_to_mfn(void *vaddr)
@@ -419,10 +451,6 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
419void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, 451void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
420 pte_t *ptep, pte_t pteval) 452 pte_t *ptep, pte_t pteval)
421{ 453{
422 /* updates to init_mm may be done without lock */
423 if (mm == &init_mm)
424 preempt_disable();
425
426 ADD_STATS(set_pte_at, 1); 454 ADD_STATS(set_pte_at, 1);
427// ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep)); 455// ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
428 ADD_STATS(set_pte_at_current, mm == current->mm); 456 ADD_STATS(set_pte_at_current, mm == current->mm);
@@ -443,9 +471,7 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
443 } 471 }
444 xen_set_pte(ptep, pteval); 472 xen_set_pte(ptep, pteval);
445 473
446out: 474out: return;
447 if (mm == &init_mm)
448 preempt_enable();
449} 475}
450 476
451pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, 477pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
@@ -987,7 +1013,7 @@ static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
987 return 0; 1013 return 0;
988} 1014}
989 1015
990void __init xen_mark_init_mm_pinned(void) 1016static void __init xen_mark_init_mm_pinned(void)
991{ 1017{
992 xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP); 1018 xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
993} 1019}
@@ -1119,10 +1145,8 @@ static void drop_other_mm_ref(void *info)
1119 1145
1120 /* If this cpu still has a stale cr3 reference, then make sure 1146 /* If this cpu still has a stale cr3 reference, then make sure
1121 it has been flushed. */ 1147 it has been flushed. */
1122 if (percpu_read(xen_current_cr3) == __pa(mm->pgd)) { 1148 if (percpu_read(xen_current_cr3) == __pa(mm->pgd))
1123 load_cr3(swapper_pg_dir); 1149 load_cr3(swapper_pg_dir);
1124 arch_flush_lazy_cpu_mode();
1125 }
1126} 1150}
1127 1151
1128static void xen_drop_mm_ref(struct mm_struct *mm) 1152static void xen_drop_mm_ref(struct mm_struct *mm)
@@ -1135,7 +1159,6 @@ static void xen_drop_mm_ref(struct mm_struct *mm)
1135 load_cr3(swapper_pg_dir); 1159 load_cr3(swapper_pg_dir);
1136 else 1160 else
1137 leave_mm(smp_processor_id()); 1161 leave_mm(smp_processor_id());
1138 arch_flush_lazy_cpu_mode();
1139 } 1162 }
1140 1163
1141 /* Get the "official" set of cpus referring to our pagetable. */ 1164 /* Get the "official" set of cpus referring to our pagetable. */
@@ -1270,8 +1293,8 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
1270 } *args; 1293 } *args;
1271 struct multicall_space mcs; 1294 struct multicall_space mcs;
1272 1295
1273 BUG_ON(cpumask_empty(cpus)); 1296 if (cpumask_empty(cpus))
1274 BUG_ON(!mm); 1297 return; /* nothing to do */
1275 1298
1276 mcs = xen_mc_entry(sizeof(*args)); 1299 mcs = xen_mc_entry(sizeof(*args));
1277 args = mcs.args; 1300 args = mcs.args;
@@ -1438,6 +1461,15 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
1438} 1461}
1439#endif 1462#endif
1440 1463
1464static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
1465{
1466 struct mmuext_op op;
1467 op.cmd = cmd;
1468 op.arg1.mfn = pfn_to_mfn(pfn);
1469 if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
1470 BUG();
1471}
1472
1441/* Early in boot, while setting up the initial pagetable, assume 1473/* Early in boot, while setting up the initial pagetable, assume
1442 everything is pinned. */ 1474 everything is pinned. */
1443static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) 1475static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
@@ -1446,22 +1478,29 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
1446 BUG_ON(mem_map); /* should only be used early */ 1478 BUG_ON(mem_map); /* should only be used early */
1447#endif 1479#endif
1448 make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); 1480 make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
1481 pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
1482}
1483
1484/* Used for pmd and pud */
1485static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
1486{
1487#ifdef CONFIG_FLATMEM
1488 BUG_ON(mem_map); /* should only be used early */
1489#endif
1490 make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
1449} 1491}
1450 1492
1451/* Early release_pte assumes that all pts are pinned, since there's 1493/* Early release_pte assumes that all pts are pinned, since there's
1452 only init_mm and anything attached to that is pinned. */ 1494 only init_mm and anything attached to that is pinned. */
1453static void xen_release_pte_init(unsigned long pfn) 1495static __init void xen_release_pte_init(unsigned long pfn)
1454{ 1496{
1497 pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
1455 make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); 1498 make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
1456} 1499}
1457 1500
1458static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) 1501static __init void xen_release_pmd_init(unsigned long pfn)
1459{ 1502{
1460 struct mmuext_op op; 1503 make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
1461 op.cmd = cmd;
1462 op.arg1.mfn = pfn_to_mfn(pfn);
1463 if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
1464 BUG();
1465} 1504}
1466 1505
1467/* This needs to make sure the new pte page is pinned iff its being 1506/* This needs to make sure the new pte page is pinned iff its being
@@ -1819,6 +1858,13 @@ __init void xen_post_allocator_init(void)
1819 xen_mark_init_mm_pinned(); 1858 xen_mark_init_mm_pinned();
1820} 1859}
1821 1860
1861static void xen_leave_lazy_mmu(void)
1862{
1863 preempt_disable();
1864 xen_mc_flush();
1865 paravirt_leave_lazy_mmu();
1866 preempt_enable();
1867}
1822 1868
1823const struct pv_mmu_ops xen_mmu_ops __initdata = { 1869const struct pv_mmu_ops xen_mmu_ops __initdata = {
1824 .pagetable_setup_start = xen_pagetable_setup_start, 1870 .pagetable_setup_start = xen_pagetable_setup_start,
@@ -1843,9 +1889,9 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
1843 1889
1844 .alloc_pte = xen_alloc_pte_init, 1890 .alloc_pte = xen_alloc_pte_init,
1845 .release_pte = xen_release_pte_init, 1891 .release_pte = xen_release_pte_init,
1846 .alloc_pmd = xen_alloc_pte_init, 1892 .alloc_pmd = xen_alloc_pmd_init,
1847 .alloc_pmd_clone = paravirt_nop, 1893 .alloc_pmd_clone = paravirt_nop,
1848 .release_pmd = xen_release_pte_init, 1894 .release_pmd = xen_release_pmd_init,
1849 1895
1850#ifdef CONFIG_HIGHPTE 1896#ifdef CONFIG_HIGHPTE
1851 .kmap_atomic_pte = xen_kmap_atomic_pte, 1897 .kmap_atomic_pte = xen_kmap_atomic_pte,
@@ -1883,8 +1929,8 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
1883 .make_pud = PV_CALLEE_SAVE(xen_make_pud), 1929 .make_pud = PV_CALLEE_SAVE(xen_make_pud),
1884 .set_pgd = xen_set_pgd_hyper, 1930 .set_pgd = xen_set_pgd_hyper,
1885 1931
1886 .alloc_pud = xen_alloc_pte_init, 1932 .alloc_pud = xen_alloc_pmd_init,
1887 .release_pud = xen_release_pte_init, 1933 .release_pud = xen_release_pmd_init,
1888#endif /* PAGETABLE_LEVELS == 4 */ 1934#endif /* PAGETABLE_LEVELS == 4 */
1889 1935
1890 .activate_mm = xen_activate_mm, 1936 .activate_mm = xen_activate_mm,
@@ -1893,7 +1939,7 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
1893 1939
1894 .lazy_mode = { 1940 .lazy_mode = {
1895 .enter = paravirt_enter_lazy_mmu, 1941 .enter = paravirt_enter_lazy_mmu,
1896 .leave = xen_leave_lazy, 1942 .leave = xen_leave_lazy_mmu,
1897 }, 1943 },
1898 1944
1899 .set_fixmap = xen_set_fixmap, 1945 .set_fixmap = xen_set_fixmap,