diff options
Diffstat (limited to 'arch/x86/xen/mmu.c')
-rw-r--r-- | arch/x86/xen/mmu.c | 121 |
1 files changed, 96 insertions, 25 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 5e92b61ad574..aef7af92b28b 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
47 | #include <linux/gfp.h> | 47 | #include <linux/gfp.h> |
48 | #include <linux/memblock.h> | 48 | #include <linux/memblock.h> |
49 | #include <linux/seq_file.h> | ||
49 | 50 | ||
50 | #include <asm/pgtable.h> | 51 | #include <asm/pgtable.h> |
51 | #include <asm/tlbflush.h> | 52 | #include <asm/tlbflush.h> |
@@ -78,8 +79,7 @@ | |||
78 | 79 | ||
79 | /* | 80 | /* |
80 | * Protects atomic reservation decrease/increase against concurrent increases. | 81 | * Protects atomic reservation decrease/increase against concurrent increases. |
81 | * Also protects non-atomic updates of current_pages and driver_pages, and | 82 | * Also protects non-atomic updates of current_pages and balloon lists. |
82 | * balloon lists. | ||
83 | */ | 83 | */ |
84 | DEFINE_SPINLOCK(xen_reservation_lock); | 84 | DEFINE_SPINLOCK(xen_reservation_lock); |
85 | 85 | ||
@@ -416,8 +416,12 @@ static pteval_t pte_pfn_to_mfn(pteval_t val) | |||
416 | if (val & _PAGE_PRESENT) { | 416 | if (val & _PAGE_PRESENT) { |
417 | unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; | 417 | unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT; |
418 | pteval_t flags = val & PTE_FLAGS_MASK; | 418 | pteval_t flags = val & PTE_FLAGS_MASK; |
419 | unsigned long mfn = pfn_to_mfn(pfn); | 419 | unsigned long mfn; |
420 | 420 | ||
421 | if (!xen_feature(XENFEAT_auto_translated_physmap)) | ||
422 | mfn = get_phys_to_machine(pfn); | ||
423 | else | ||
424 | mfn = pfn; | ||
421 | /* | 425 | /* |
422 | * If there's no mfn for the pfn, then just create an | 426 | * If there's no mfn for the pfn, then just create an |
423 | * empty non-present pte. Unfortunately this loses | 427 | * empty non-present pte. Unfortunately this loses |
@@ -427,8 +431,18 @@ static pteval_t pte_pfn_to_mfn(pteval_t val) | |||
427 | if (unlikely(mfn == INVALID_P2M_ENTRY)) { | 431 | if (unlikely(mfn == INVALID_P2M_ENTRY)) { |
428 | mfn = 0; | 432 | mfn = 0; |
429 | flags = 0; | 433 | flags = 0; |
434 | } else { | ||
435 | /* | ||
436 | * Paramount to do this test _after_ the | ||
437 | * INVALID_P2M_ENTRY as INVALID_P2M_ENTRY & | ||
438 | * IDENTITY_FRAME_BIT resolves to true. | ||
439 | */ | ||
440 | mfn &= ~FOREIGN_FRAME_BIT; | ||
441 | if (mfn & IDENTITY_FRAME_BIT) { | ||
442 | mfn &= ~IDENTITY_FRAME_BIT; | ||
443 | flags |= _PAGE_IOMAP; | ||
444 | } | ||
430 | } | 445 | } |
431 | |||
432 | val = ((pteval_t)mfn << PAGE_SHIFT) | flags; | 446 | val = ((pteval_t)mfn << PAGE_SHIFT) | flags; |
433 | } | 447 | } |
434 | 448 | ||
@@ -532,6 +546,41 @@ pte_t xen_make_pte(pteval_t pte) | |||
532 | } | 546 | } |
533 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); | 547 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); |
534 | 548 | ||
549 | #ifdef CONFIG_XEN_DEBUG | ||
550 | pte_t xen_make_pte_debug(pteval_t pte) | ||
551 | { | ||
552 | phys_addr_t addr = (pte & PTE_PFN_MASK); | ||
553 | phys_addr_t other_addr; | ||
554 | bool io_page = false; | ||
555 | pte_t _pte; | ||
556 | |||
557 | if (pte & _PAGE_IOMAP) | ||
558 | io_page = true; | ||
559 | |||
560 | _pte = xen_make_pte(pte); | ||
561 | |||
562 | if (!addr) | ||
563 | return _pte; | ||
564 | |||
565 | if (io_page && | ||
566 | (xen_initial_domain() || addr >= ISA_END_ADDRESS)) { | ||
567 | other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT; | ||
568 | WARN_ONCE(addr != other_addr, | ||
569 | "0x%lx is using VM_IO, but it is 0x%lx!\n", | ||
570 | (unsigned long)addr, (unsigned long)other_addr); | ||
571 | } else { | ||
572 | pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP; | ||
573 | other_addr = (_pte.pte & PTE_PFN_MASK); | ||
574 | WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set), | ||
575 | "0x%lx is missing VM_IO (and wasn't fixed)!\n", | ||
576 | (unsigned long)addr); | ||
577 | } | ||
578 | |||
579 | return _pte; | ||
580 | } | ||
581 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug); | ||
582 | #endif | ||
583 | |||
535 | pgd_t xen_make_pgd(pgdval_t pgd) | 584 | pgd_t xen_make_pgd(pgdval_t pgd) |
536 | { | 585 | { |
537 | pgd = pte_pfn_to_mfn(pgd); | 586 | pgd = pte_pfn_to_mfn(pgd); |
@@ -986,10 +1035,9 @@ static void xen_pgd_pin(struct mm_struct *mm) | |||
986 | */ | 1035 | */ |
987 | void xen_mm_pin_all(void) | 1036 | void xen_mm_pin_all(void) |
988 | { | 1037 | { |
989 | unsigned long flags; | ||
990 | struct page *page; | 1038 | struct page *page; |
991 | 1039 | ||
992 | spin_lock_irqsave(&pgd_lock, flags); | 1040 | spin_lock(&pgd_lock); |
993 | 1041 | ||
994 | list_for_each_entry(page, &pgd_list, lru) { | 1042 | list_for_each_entry(page, &pgd_list, lru) { |
995 | if (!PagePinned(page)) { | 1043 | if (!PagePinned(page)) { |
@@ -998,7 +1046,7 @@ void xen_mm_pin_all(void) | |||
998 | } | 1046 | } |
999 | } | 1047 | } |
1000 | 1048 | ||
1001 | spin_unlock_irqrestore(&pgd_lock, flags); | 1049 | spin_unlock(&pgd_lock); |
1002 | } | 1050 | } |
1003 | 1051 | ||
1004 | /* | 1052 | /* |
@@ -1099,10 +1147,9 @@ static void xen_pgd_unpin(struct mm_struct *mm) | |||
1099 | */ | 1147 | */ |
1100 | void xen_mm_unpin_all(void) | 1148 | void xen_mm_unpin_all(void) |
1101 | { | 1149 | { |
1102 | unsigned long flags; | ||
1103 | struct page *page; | 1150 | struct page *page; |
1104 | 1151 | ||
1105 | spin_lock_irqsave(&pgd_lock, flags); | 1152 | spin_lock(&pgd_lock); |
1106 | 1153 | ||
1107 | list_for_each_entry(page, &pgd_list, lru) { | 1154 | list_for_each_entry(page, &pgd_list, lru) { |
1108 | if (PageSavePinned(page)) { | 1155 | if (PageSavePinned(page)) { |
@@ -1112,7 +1159,7 @@ void xen_mm_unpin_all(void) | |||
1112 | } | 1159 | } |
1113 | } | 1160 | } |
1114 | 1161 | ||
1115 | spin_unlock_irqrestore(&pgd_lock, flags); | 1162 | spin_unlock(&pgd_lock); |
1116 | } | 1163 | } |
1117 | 1164 | ||
1118 | void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next) | 1165 | void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next) |
@@ -1426,28 +1473,35 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) | |||
1426 | #endif | 1473 | #endif |
1427 | } | 1474 | } |
1428 | 1475 | ||
1476 | #ifdef CONFIG_X86_32 | ||
1429 | static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) | 1477 | static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) |
1430 | { | 1478 | { |
1431 | unsigned long pfn = pte_pfn(pte); | ||
1432 | |||
1433 | #ifdef CONFIG_X86_32 | ||
1434 | /* If there's an existing pte, then don't allow _PAGE_RW to be set */ | 1479 | /* If there's an existing pte, then don't allow _PAGE_RW to be set */ |
1435 | if (pte_val_ma(*ptep) & _PAGE_PRESENT) | 1480 | if (pte_val_ma(*ptep) & _PAGE_PRESENT) |
1436 | pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) & | 1481 | pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) & |
1437 | pte_val_ma(pte)); | 1482 | pte_val_ma(pte)); |
1438 | #endif | 1483 | |
1484 | return pte; | ||
1485 | } | ||
1486 | #else /* CONFIG_X86_64 */ | ||
1487 | static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) | ||
1488 | { | ||
1489 | unsigned long pfn = pte_pfn(pte); | ||
1439 | 1490 | ||
1440 | /* | 1491 | /* |
1441 | * If the new pfn is within the range of the newly allocated | 1492 | * If the new pfn is within the range of the newly allocated |
1442 | * kernel pagetable, and it isn't being mapped into an | 1493 | * kernel pagetable, and it isn't being mapped into an |
1443 | * early_ioremap fixmap slot, make sure it is RO. | 1494 | * early_ioremap fixmap slot as a freshly allocated page, make sure |
1495 | * it is RO. | ||
1444 | */ | 1496 | */ |
1445 | if (!is_early_ioremap_ptep(ptep) && | 1497 | if (((!is_early_ioremap_ptep(ptep) && |
1446 | pfn >= e820_table_start && pfn < e820_table_end) | 1498 | pfn >= pgt_buf_start && pfn < pgt_buf_end)) || |
1499 | (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1))) | ||
1447 | pte = pte_wrprotect(pte); | 1500 | pte = pte_wrprotect(pte); |
1448 | 1501 | ||
1449 | return pte; | 1502 | return pte; |
1450 | } | 1503 | } |
1504 | #endif /* CONFIG_X86_64 */ | ||
1451 | 1505 | ||
1452 | /* Init-time set_pte while constructing initial pagetables, which | 1506 | /* Init-time set_pte while constructing initial pagetables, which |
1453 | doesn't allow RO pagetable pages to be remapped RW */ | 1507 | doesn't allow RO pagetable pages to be remapped RW */ |
@@ -1653,9 +1707,6 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) | |||
1653 | for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) { | 1707 | for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) { |
1654 | pte_t pte; | 1708 | pte_t pte; |
1655 | 1709 | ||
1656 | if (pfn > max_pfn_mapped) | ||
1657 | max_pfn_mapped = pfn; | ||
1658 | |||
1659 | if (!pte_none(pte_page[pteidx])) | 1710 | if (!pte_none(pte_page[pteidx])) |
1660 | continue; | 1711 | continue; |
1661 | 1712 | ||
@@ -1697,7 +1748,7 @@ static void convert_pfn_mfn(void *v) | |||
1697 | } | 1748 | } |
1698 | 1749 | ||
1699 | /* | 1750 | /* |
1700 | * Set up the inital kernel pagetable. | 1751 | * Set up the initial kernel pagetable. |
1701 | * | 1752 | * |
1702 | * We can construct this by grafting the Xen provided pagetable into | 1753 | * We can construct this by grafting the Xen provided pagetable into |
1703 | * head_64.S's preconstructed pagetables. We copy the Xen L2's into | 1754 | * head_64.S's preconstructed pagetables. We copy the Xen L2's into |
@@ -1713,6 +1764,12 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, | |||
1713 | pud_t *l3; | 1764 | pud_t *l3; |
1714 | pmd_t *l2; | 1765 | pmd_t *l2; |
1715 | 1766 | ||
1767 | /* max_pfn_mapped is the last pfn mapped in the initial memory | ||
1768 | * mappings. Considering that on Xen after the kernel mappings we | ||
1769 | * have the mappings of some pages that don't exist in pfn space, we | ||
1770 | * set max_pfn_mapped to the last real pfn mapped. */ | ||
1771 | max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list)); | ||
1772 | |||
1716 | /* Zap identity mapping */ | 1773 | /* Zap identity mapping */ |
1717 | init_level4_pgt[0] = __pgd(0); | 1774 | init_level4_pgt[0] = __pgd(0); |
1718 | 1775 | ||
@@ -1817,9 +1874,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, | |||
1817 | initial_kernel_pmd = | 1874 | initial_kernel_pmd = |
1818 | extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE); | 1875 | extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE); |
1819 | 1876 | ||
1820 | max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) + | 1877 | max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list)); |
1821 | xen_start_info->nr_pt_frames * PAGE_SIZE + | ||
1822 | 512*1024); | ||
1823 | 1878 | ||
1824 | kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd); | 1879 | kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd); |
1825 | memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); | 1880 | memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD); |
@@ -1942,6 +1997,9 @@ __init void xen_ident_map_ISA(void) | |||
1942 | 1997 | ||
1943 | static __init void xen_post_allocator_init(void) | 1998 | static __init void xen_post_allocator_init(void) |
1944 | { | 1999 | { |
2000 | #ifdef CONFIG_XEN_DEBUG | ||
2001 | pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug); | ||
2002 | #endif | ||
1945 | pv_mmu_ops.set_pte = xen_set_pte; | 2003 | pv_mmu_ops.set_pte = xen_set_pte; |
1946 | pv_mmu_ops.set_pmd = xen_set_pmd; | 2004 | pv_mmu_ops.set_pmd = xen_set_pmd; |
1947 | pv_mmu_ops.set_pud = xen_set_pud; | 2005 | pv_mmu_ops.set_pud = xen_set_pud; |
@@ -2074,7 +2132,7 @@ static void xen_zap_pfn_range(unsigned long vaddr, unsigned int order, | |||
2074 | in_frames[i] = virt_to_mfn(vaddr); | 2132 | in_frames[i] = virt_to_mfn(vaddr); |
2075 | 2133 | ||
2076 | MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0); | 2134 | MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0); |
2077 | set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY); | 2135 | __set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY); |
2078 | 2136 | ||
2079 | if (out_frames) | 2137 | if (out_frames) |
2080 | out_frames[i] = virt_to_pfn(vaddr); | 2138 | out_frames[i] = virt_to_pfn(vaddr); |
@@ -2353,6 +2411,18 @@ EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); | |||
2353 | 2411 | ||
2354 | #ifdef CONFIG_XEN_DEBUG_FS | 2412 | #ifdef CONFIG_XEN_DEBUG_FS |
2355 | 2413 | ||
2414 | static int p2m_dump_open(struct inode *inode, struct file *filp) | ||
2415 | { | ||
2416 | return single_open(filp, p2m_dump_show, NULL); | ||
2417 | } | ||
2418 | |||
2419 | static const struct file_operations p2m_dump_fops = { | ||
2420 | .open = p2m_dump_open, | ||
2421 | .read = seq_read, | ||
2422 | .llseek = seq_lseek, | ||
2423 | .release = single_release, | ||
2424 | }; | ||
2425 | |||
2356 | static struct dentry *d_mmu_debug; | 2426 | static struct dentry *d_mmu_debug; |
2357 | 2427 | ||
2358 | static int __init xen_mmu_debugfs(void) | 2428 | static int __init xen_mmu_debugfs(void) |
@@ -2408,6 +2478,7 @@ static int __init xen_mmu_debugfs(void) | |||
2408 | debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug, | 2478 | debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug, |
2409 | &mmu_stats.prot_commit_batched); | 2479 | &mmu_stats.prot_commit_batched); |
2410 | 2480 | ||
2481 | debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops); | ||
2411 | return 0; | 2482 | return 0; |
2412 | } | 2483 | } |
2413 | fs_initcall(xen_mmu_debugfs); | 2484 | fs_initcall(xen_mmu_debugfs); |