diff options
Diffstat (limited to 'arch/x86/xen/mmu.c')
-rw-r--r-- | arch/x86/xen/mmu.c | 124 |
1 files changed, 90 insertions, 34 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index db3802fb7b84..fba55b1a4021 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/highmem.h> | 42 | #include <linux/highmem.h> |
43 | #include <linux/debugfs.h> | 43 | #include <linux/debugfs.h> |
44 | #include <linux/bug.h> | 44 | #include <linux/bug.h> |
45 | #include <linux/module.h> | ||
45 | 46 | ||
46 | #include <asm/pgtable.h> | 47 | #include <asm/pgtable.h> |
47 | #include <asm/tlbflush.h> | 48 | #include <asm/tlbflush.h> |
@@ -184,7 +185,7 @@ static inline unsigned p2m_index(unsigned long pfn) | |||
184 | } | 185 | } |
185 | 186 | ||
186 | /* Build the parallel p2m_top_mfn structures */ | 187 | /* Build the parallel p2m_top_mfn structures */ |
187 | void xen_setup_mfn_list_list(void) | 188 | static void __init xen_build_mfn_list_list(void) |
188 | { | 189 | { |
189 | unsigned pfn, idx; | 190 | unsigned pfn, idx; |
190 | 191 | ||
@@ -198,7 +199,10 @@ void xen_setup_mfn_list_list(void) | |||
198 | unsigned topidx = idx * P2M_ENTRIES_PER_PAGE; | 199 | unsigned topidx = idx * P2M_ENTRIES_PER_PAGE; |
199 | p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]); | 200 | p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]); |
200 | } | 201 | } |
202 | } | ||
201 | 203 | ||
204 | void xen_setup_mfn_list_list(void) | ||
205 | { | ||
202 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); | 206 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); |
203 | 207 | ||
204 | HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = | 208 | HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = |
@@ -218,6 +222,8 @@ void __init xen_build_dynamic_phys_to_machine(void) | |||
218 | 222 | ||
219 | p2m_top[topidx] = &mfn_list[pfn]; | 223 | p2m_top[topidx] = &mfn_list[pfn]; |
220 | } | 224 | } |
225 | |||
226 | xen_build_mfn_list_list(); | ||
221 | } | 227 | } |
222 | 228 | ||
223 | unsigned long get_phys_to_machine(unsigned long pfn) | 229 | unsigned long get_phys_to_machine(unsigned long pfn) |
@@ -233,47 +239,74 @@ unsigned long get_phys_to_machine(unsigned long pfn) | |||
233 | } | 239 | } |
234 | EXPORT_SYMBOL_GPL(get_phys_to_machine); | 240 | EXPORT_SYMBOL_GPL(get_phys_to_machine); |
235 | 241 | ||
236 | static void alloc_p2m(unsigned long **pp, unsigned long *mfnp) | 242 | /* install a new p2m_top page */ |
243 | bool install_p2mtop_page(unsigned long pfn, unsigned long *p) | ||
237 | { | 244 | { |
238 | unsigned long *p; | 245 | unsigned topidx = p2m_top_index(pfn); |
246 | unsigned long **pfnp, *mfnp; | ||
239 | unsigned i; | 247 | unsigned i; |
240 | 248 | ||
241 | p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); | 249 | pfnp = &p2m_top[topidx]; |
242 | BUG_ON(p == NULL); | 250 | mfnp = &p2m_top_mfn[topidx]; |
243 | 251 | ||
244 | for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) | 252 | for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) |
245 | p[i] = INVALID_P2M_ENTRY; | 253 | p[i] = INVALID_P2M_ENTRY; |
246 | 254 | ||
247 | if (cmpxchg(pp, p2m_missing, p) != p2m_missing) | 255 | if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) { |
248 | free_page((unsigned long)p); | ||
249 | else | ||
250 | *mfnp = virt_to_mfn(p); | 256 | *mfnp = virt_to_mfn(p); |
257 | return true; | ||
258 | } | ||
259 | |||
260 | return false; | ||
251 | } | 261 | } |
252 | 262 | ||
253 | void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | 263 | static void alloc_p2m(unsigned long pfn) |
254 | { | 264 | { |
255 | unsigned topidx, idx; | 265 | unsigned long *p; |
256 | 266 | ||
257 | if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { | 267 | p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); |
258 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | 268 | BUG_ON(p == NULL); |
259 | return; | 269 | |
260 | } | 270 | if (!install_p2mtop_page(pfn, p)) |
271 | free_page((unsigned long)p); | ||
272 | } | ||
273 | |||
274 | /* Try to install p2m mapping; fail if intermediate bits missing */ | ||
275 | bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
276 | { | ||
277 | unsigned topidx, idx; | ||
261 | 278 | ||
262 | if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { | 279 | if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { |
263 | BUG_ON(mfn != INVALID_P2M_ENTRY); | 280 | BUG_ON(mfn != INVALID_P2M_ENTRY); |
264 | return; | 281 | return true; |
265 | } | 282 | } |
266 | 283 | ||
267 | topidx = p2m_top_index(pfn); | 284 | topidx = p2m_top_index(pfn); |
268 | if (p2m_top[topidx] == p2m_missing) { | 285 | if (p2m_top[topidx] == p2m_missing) { |
269 | /* no need to allocate a page to store an invalid entry */ | ||
270 | if (mfn == INVALID_P2M_ENTRY) | 286 | if (mfn == INVALID_P2M_ENTRY) |
271 | return; | 287 | return true; |
272 | alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]); | 288 | return false; |
273 | } | 289 | } |
274 | 290 | ||
275 | idx = p2m_index(pfn); | 291 | idx = p2m_index(pfn); |
276 | p2m_top[topidx][idx] = mfn; | 292 | p2m_top[topidx][idx] = mfn; |
293 | |||
294 | return true; | ||
295 | } | ||
296 | |||
297 | void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
298 | { | ||
299 | if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { | ||
300 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | if (unlikely(!__set_phys_to_machine(pfn, mfn))) { | ||
305 | alloc_p2m(pfn); | ||
306 | |||
307 | if (!__set_phys_to_machine(pfn, mfn)) | ||
308 | BUG(); | ||
309 | } | ||
277 | } | 310 | } |
278 | 311 | ||
279 | unsigned long arbitrary_virt_to_mfn(void *vaddr) | 312 | unsigned long arbitrary_virt_to_mfn(void *vaddr) |
@@ -987,7 +1020,7 @@ static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page, | |||
987 | return 0; | 1020 | return 0; |
988 | } | 1021 | } |
989 | 1022 | ||
990 | void __init xen_mark_init_mm_pinned(void) | 1023 | static void __init xen_mark_init_mm_pinned(void) |
991 | { | 1024 | { |
992 | xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP); | 1025 | xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP); |
993 | } | 1026 | } |
@@ -1270,8 +1303,8 @@ static void xen_flush_tlb_others(const struct cpumask *cpus, | |||
1270 | } *args; | 1303 | } *args; |
1271 | struct multicall_space mcs; | 1304 | struct multicall_space mcs; |
1272 | 1305 | ||
1273 | BUG_ON(cpumask_empty(cpus)); | 1306 | if (cpumask_empty(cpus)) |
1274 | BUG_ON(!mm); | 1307 | return; /* nothing to do */ |
1275 | 1308 | ||
1276 | mcs = xen_mc_entry(sizeof(*args)); | 1309 | mcs = xen_mc_entry(sizeof(*args)); |
1277 | args = mcs.args; | 1310 | args = mcs.args; |
@@ -1438,6 +1471,15 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte) | |||
1438 | } | 1471 | } |
1439 | #endif | 1472 | #endif |
1440 | 1473 | ||
1474 | static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) | ||
1475 | { | ||
1476 | struct mmuext_op op; | ||
1477 | op.cmd = cmd; | ||
1478 | op.arg1.mfn = pfn_to_mfn(pfn); | ||
1479 | if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) | ||
1480 | BUG(); | ||
1481 | } | ||
1482 | |||
1441 | /* Early in boot, while setting up the initial pagetable, assume | 1483 | /* Early in boot, while setting up the initial pagetable, assume |
1442 | everything is pinned. */ | 1484 | everything is pinned. */ |
1443 | static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) | 1485 | static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) |
@@ -1446,22 +1488,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 */ | 1488 | BUG_ON(mem_map); /* should only be used early */ |
1447 | #endif | 1489 | #endif |
1448 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); | 1490 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); |
1491 | pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); | ||
1492 | } | ||
1493 | |||
1494 | /* Used for pmd and pud */ | ||
1495 | static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) | ||
1496 | { | ||
1497 | #ifdef CONFIG_FLATMEM | ||
1498 | BUG_ON(mem_map); /* should only be used early */ | ||
1499 | #endif | ||
1500 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); | ||
1449 | } | 1501 | } |
1450 | 1502 | ||
1451 | /* Early release_pte assumes that all pts are pinned, since there's | 1503 | /* Early release_pte assumes that all pts are pinned, since there's |
1452 | only init_mm and anything attached to that is pinned. */ | 1504 | only init_mm and anything attached to that is pinned. */ |
1453 | static void xen_release_pte_init(unsigned long pfn) | 1505 | static __init void xen_release_pte_init(unsigned long pfn) |
1454 | { | 1506 | { |
1507 | pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); | ||
1455 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); | 1508 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); |
1456 | } | 1509 | } |
1457 | 1510 | ||
1458 | static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) | 1511 | static __init void xen_release_pmd_init(unsigned long pfn) |
1459 | { | 1512 | { |
1460 | struct mmuext_op op; | 1513 | 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 | } | 1514 | } |
1466 | 1515 | ||
1467 | /* This needs to make sure the new pte page is pinned iff its being | 1516 | /* This needs to make sure the new pte page is pinned iff its being |
@@ -1746,11 +1795,16 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, | |||
1746 | 1795 | ||
1747 | pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir))); | 1796 | pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir))); |
1748 | 1797 | ||
1798 | reserve_early(__pa(xen_start_info->pt_base), | ||
1799 | __pa(xen_start_info->pt_base + | ||
1800 | xen_start_info->nr_pt_frames * PAGE_SIZE), | ||
1801 | "XEN PAGETABLES"); | ||
1802 | |||
1749 | return swapper_pg_dir; | 1803 | return swapper_pg_dir; |
1750 | } | 1804 | } |
1751 | #endif /* CONFIG_X86_64 */ | 1805 | #endif /* CONFIG_X86_64 */ |
1752 | 1806 | ||
1753 | static void xen_set_fixmap(unsigned idx, unsigned long phys, pgprot_t prot) | 1807 | static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) |
1754 | { | 1808 | { |
1755 | pte_t pte; | 1809 | pte_t pte; |
1756 | 1810 | ||
@@ -1773,6 +1827,9 @@ static void xen_set_fixmap(unsigned idx, unsigned long phys, pgprot_t prot) | |||
1773 | #ifdef CONFIG_X86_LOCAL_APIC | 1827 | #ifdef CONFIG_X86_LOCAL_APIC |
1774 | case FIX_APIC_BASE: /* maps dummy local APIC */ | 1828 | case FIX_APIC_BASE: /* maps dummy local APIC */ |
1775 | #endif | 1829 | #endif |
1830 | case FIX_TEXT_POKE0: | ||
1831 | case FIX_TEXT_POKE1: | ||
1832 | /* All local page mappings */ | ||
1776 | pte = pfn_pte(phys, prot); | 1833 | pte = pfn_pte(phys, prot); |
1777 | break; | 1834 | break; |
1778 | 1835 | ||
@@ -1819,7 +1876,6 @@ __init void xen_post_allocator_init(void) | |||
1819 | xen_mark_init_mm_pinned(); | 1876 | xen_mark_init_mm_pinned(); |
1820 | } | 1877 | } |
1821 | 1878 | ||
1822 | |||
1823 | const struct pv_mmu_ops xen_mmu_ops __initdata = { | 1879 | const struct pv_mmu_ops xen_mmu_ops __initdata = { |
1824 | .pagetable_setup_start = xen_pagetable_setup_start, | 1880 | .pagetable_setup_start = xen_pagetable_setup_start, |
1825 | .pagetable_setup_done = xen_pagetable_setup_done, | 1881 | .pagetable_setup_done = xen_pagetable_setup_done, |
@@ -1843,9 +1899,9 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = { | |||
1843 | 1899 | ||
1844 | .alloc_pte = xen_alloc_pte_init, | 1900 | .alloc_pte = xen_alloc_pte_init, |
1845 | .release_pte = xen_release_pte_init, | 1901 | .release_pte = xen_release_pte_init, |
1846 | .alloc_pmd = xen_alloc_pte_init, | 1902 | .alloc_pmd = xen_alloc_pmd_init, |
1847 | .alloc_pmd_clone = paravirt_nop, | 1903 | .alloc_pmd_clone = paravirt_nop, |
1848 | .release_pmd = xen_release_pte_init, | 1904 | .release_pmd = xen_release_pmd_init, |
1849 | 1905 | ||
1850 | #ifdef CONFIG_HIGHPTE | 1906 | #ifdef CONFIG_HIGHPTE |
1851 | .kmap_atomic_pte = xen_kmap_atomic_pte, | 1907 | .kmap_atomic_pte = xen_kmap_atomic_pte, |
@@ -1883,8 +1939,8 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = { | |||
1883 | .make_pud = PV_CALLEE_SAVE(xen_make_pud), | 1939 | .make_pud = PV_CALLEE_SAVE(xen_make_pud), |
1884 | .set_pgd = xen_set_pgd_hyper, | 1940 | .set_pgd = xen_set_pgd_hyper, |
1885 | 1941 | ||
1886 | .alloc_pud = xen_alloc_pte_init, | 1942 | .alloc_pud = xen_alloc_pmd_init, |
1887 | .release_pud = xen_release_pte_init, | 1943 | .release_pud = xen_release_pmd_init, |
1888 | #endif /* PAGETABLE_LEVELS == 4 */ | 1944 | #endif /* PAGETABLE_LEVELS == 4 */ |
1889 | 1945 | ||
1890 | .activate_mm = xen_activate_mm, | 1946 | .activate_mm = xen_activate_mm, |