diff options
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/Kconfig | 8 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 1 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 52 | ||||
-rw-r--r-- | arch/x86/xen/p2m.c | 128 |
4 files changed, 110 insertions, 79 deletions
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index 5cc821cb2e09..ae559fe91c25 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig | |||
@@ -49,11 +49,3 @@ config XEN_DEBUG_FS | |||
49 | help | 49 | help |
50 | Enable statistics output and various tuning options in debugfs. | 50 | Enable statistics output and various tuning options in debugfs. |
51 | Enabling this option may incur a significant performance overhead. | 51 | Enabling this option may incur a significant performance overhead. |
52 | |||
53 | config XEN_DEBUG | ||
54 | bool "Enable Xen debug checks" | ||
55 | depends on XEN | ||
56 | default n | ||
57 | help | ||
58 | Enable various WARN_ON checks in the Xen MMU code. | ||
59 | Enabling this option WILL incur a significant performance overhead. | ||
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 2d69617950f7..da8afd576a6b 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -251,6 +251,7 @@ static void __init xen_init_cpuid_mask(void) | |||
251 | ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ | 251 | ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ |
252 | (1 << X86_FEATURE_ACPI)); /* disable ACPI */ | 252 | (1 << X86_FEATURE_ACPI)); /* disable ACPI */ |
253 | ax = 1; | 253 | ax = 1; |
254 | cx = 0; | ||
254 | xen_cpuid(&ax, &bx, &cx, &dx); | 255 | xen_cpuid(&ax, &bx, &cx, &dx); |
255 | 256 | ||
256 | xsave_mask = | 257 | xsave_mask = |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 3dd53f997b11..87f6673b1207 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -495,41 +495,6 @@ static pte_t xen_make_pte(pteval_t pte) | |||
495 | } | 495 | } |
496 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); | 496 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); |
497 | 497 | ||
498 | #ifdef CONFIG_XEN_DEBUG | ||
499 | pte_t xen_make_pte_debug(pteval_t pte) | ||
500 | { | ||
501 | phys_addr_t addr = (pte & PTE_PFN_MASK); | ||
502 | phys_addr_t other_addr; | ||
503 | bool io_page = false; | ||
504 | pte_t _pte; | ||
505 | |||
506 | if (pte & _PAGE_IOMAP) | ||
507 | io_page = true; | ||
508 | |||
509 | _pte = xen_make_pte(pte); | ||
510 | |||
511 | if (!addr) | ||
512 | return _pte; | ||
513 | |||
514 | if (io_page && | ||
515 | (xen_initial_domain() || addr >= ISA_END_ADDRESS)) { | ||
516 | other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT; | ||
517 | WARN_ONCE(addr != other_addr, | ||
518 | "0x%lx is using VM_IO, but it is 0x%lx!\n", | ||
519 | (unsigned long)addr, (unsigned long)other_addr); | ||
520 | } else { | ||
521 | pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP; | ||
522 | other_addr = (_pte.pte & PTE_PFN_MASK); | ||
523 | WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set), | ||
524 | "0x%lx is missing VM_IO (and wasn't fixed)!\n", | ||
525 | (unsigned long)addr); | ||
526 | } | ||
527 | |||
528 | return _pte; | ||
529 | } | ||
530 | PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug); | ||
531 | #endif | ||
532 | |||
533 | static pgd_t xen_make_pgd(pgdval_t pgd) | 498 | static pgd_t xen_make_pgd(pgdval_t pgd) |
534 | { | 499 | { |
535 | pgd = pte_pfn_to_mfn(pgd); | 500 | pgd = pte_pfn_to_mfn(pgd); |
@@ -1992,9 +1957,6 @@ void __init xen_ident_map_ISA(void) | |||
1992 | 1957 | ||
1993 | static void __init xen_post_allocator_init(void) | 1958 | static void __init xen_post_allocator_init(void) |
1994 | { | 1959 | { |
1995 | #ifdef CONFIG_XEN_DEBUG | ||
1996 | pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug); | ||
1997 | #endif | ||
1998 | pv_mmu_ops.set_pte = xen_set_pte; | 1960 | pv_mmu_ops.set_pte = xen_set_pte; |
1999 | pv_mmu_ops.set_pmd = xen_set_pmd; | 1961 | pv_mmu_ops.set_pmd = xen_set_pmd; |
2000 | pv_mmu_ops.set_pud = xen_set_pud; | 1962 | pv_mmu_ops.set_pud = xen_set_pud; |
@@ -2404,17 +2366,3 @@ out: | |||
2404 | return err; | 2366 | return err; |
2405 | } | 2367 | } |
2406 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); | 2368 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); |
2407 | |||
2408 | #ifdef CONFIG_XEN_DEBUG_FS | ||
2409 | static int p2m_dump_open(struct inode *inode, struct file *filp) | ||
2410 | { | ||
2411 | return single_open(filp, p2m_dump_show, NULL); | ||
2412 | } | ||
2413 | |||
2414 | static const struct file_operations p2m_dump_fops = { | ||
2415 | .open = p2m_dump_open, | ||
2416 | .read = seq_read, | ||
2417 | .llseek = seq_lseek, | ||
2418 | .release = single_release, | ||
2419 | }; | ||
2420 | #endif /* CONFIG_XEN_DEBUG_FS */ | ||
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 58efeb9d5440..1b267e75158d 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c | |||
@@ -161,7 +161,9 @@ | |||
161 | #include <asm/xen/page.h> | 161 | #include <asm/xen/page.h> |
162 | #include <asm/xen/hypercall.h> | 162 | #include <asm/xen/hypercall.h> |
163 | #include <asm/xen/hypervisor.h> | 163 | #include <asm/xen/hypervisor.h> |
164 | #include <xen/grant_table.h> | ||
164 | 165 | ||
166 | #include "multicalls.h" | ||
165 | #include "xen-ops.h" | 167 | #include "xen-ops.h" |
166 | 168 | ||
167 | static void __init m2p_override_init(void); | 169 | static void __init m2p_override_init(void); |
@@ -676,7 +678,8 @@ static unsigned long mfn_hash(unsigned long mfn) | |||
676 | } | 678 | } |
677 | 679 | ||
678 | /* Add an MFN override for a particular page */ | 680 | /* Add an MFN override for a particular page */ |
679 | int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) | 681 | int m2p_add_override(unsigned long mfn, struct page *page, |
682 | struct gnttab_map_grant_ref *kmap_op) | ||
680 | { | 683 | { |
681 | unsigned long flags; | 684 | unsigned long flags; |
682 | unsigned long pfn; | 685 | unsigned long pfn; |
@@ -692,16 +695,28 @@ int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) | |||
692 | "m2p_add_override: pfn %lx not mapped", pfn)) | 695 | "m2p_add_override: pfn %lx not mapped", pfn)) |
693 | return -EINVAL; | 696 | return -EINVAL; |
694 | } | 697 | } |
695 | 698 | WARN_ON(PagePrivate(page)); | |
696 | page->private = mfn; | 699 | SetPagePrivate(page); |
700 | set_page_private(page, mfn); | ||
697 | page->index = pfn_to_mfn(pfn); | 701 | page->index = pfn_to_mfn(pfn); |
698 | 702 | ||
699 | if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) | 703 | if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) |
700 | return -ENOMEM; | 704 | return -ENOMEM; |
701 | 705 | ||
702 | if (clear_pte && !PageHighMem(page)) | 706 | if (kmap_op != NULL) { |
703 | /* Just zap old mapping for now */ | 707 | if (!PageHighMem(page)) { |
704 | pte_clear(&init_mm, address, ptep); | 708 | struct multicall_space mcs = |
709 | xen_mc_entry(sizeof(*kmap_op)); | ||
710 | |||
711 | MULTI_grant_table_op(mcs.mc, | ||
712 | GNTTABOP_map_grant_ref, kmap_op, 1); | ||
713 | |||
714 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
715 | } | ||
716 | /* let's use dev_bus_addr to record the old mfn instead */ | ||
717 | kmap_op->dev_bus_addr = page->index; | ||
718 | page->index = (unsigned long) kmap_op; | ||
719 | } | ||
705 | spin_lock_irqsave(&m2p_override_lock, flags); | 720 | spin_lock_irqsave(&m2p_override_lock, flags); |
706 | list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); | 721 | list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); |
707 | spin_unlock_irqrestore(&m2p_override_lock, flags); | 722 | spin_unlock_irqrestore(&m2p_override_lock, flags); |
@@ -735,13 +750,56 @@ int m2p_remove_override(struct page *page, bool clear_pte) | |||
735 | spin_lock_irqsave(&m2p_override_lock, flags); | 750 | spin_lock_irqsave(&m2p_override_lock, flags); |
736 | list_del(&page->lru); | 751 | list_del(&page->lru); |
737 | spin_unlock_irqrestore(&m2p_override_lock, flags); | 752 | spin_unlock_irqrestore(&m2p_override_lock, flags); |
738 | set_phys_to_machine(pfn, page->index); | 753 | WARN_ON(!PagePrivate(page)); |
754 | ClearPagePrivate(page); | ||
739 | 755 | ||
740 | if (clear_pte && !PageHighMem(page)) | 756 | if (clear_pte) { |
741 | set_pte_at(&init_mm, address, ptep, | 757 | struct gnttab_map_grant_ref *map_op = |
742 | pfn_pte(pfn, PAGE_KERNEL)); | 758 | (struct gnttab_map_grant_ref *) page->index; |
743 | /* No tlb flush necessary because the caller already | 759 | set_phys_to_machine(pfn, map_op->dev_bus_addr); |
744 | * left the pte unmapped. */ | 760 | if (!PageHighMem(page)) { |
761 | struct multicall_space mcs; | ||
762 | struct gnttab_unmap_grant_ref *unmap_op; | ||
763 | |||
764 | /* | ||
765 | * It might be that we queued all the m2p grant table | ||
766 | * hypercalls in a multicall, then m2p_remove_override | ||
767 | * get called before the multicall has actually been | ||
768 | * issued. In this case handle is going to -1 because | ||
769 | * it hasn't been modified yet. | ||
770 | */ | ||
771 | if (map_op->handle == -1) | ||
772 | xen_mc_flush(); | ||
773 | /* | ||
774 | * Now if map_op->handle is negative it means that the | ||
775 | * hypercall actually returned an error. | ||
776 | */ | ||
777 | if (map_op->handle == GNTST_general_error) { | ||
778 | printk(KERN_WARNING "m2p_remove_override: " | ||
779 | "pfn %lx mfn %lx, failed to modify kernel mappings", | ||
780 | pfn, mfn); | ||
781 | return -1; | ||
782 | } | ||
783 | |||
784 | mcs = xen_mc_entry( | ||
785 | sizeof(struct gnttab_unmap_grant_ref)); | ||
786 | unmap_op = mcs.args; | ||
787 | unmap_op->host_addr = map_op->host_addr; | ||
788 | unmap_op->handle = map_op->handle; | ||
789 | unmap_op->dev_bus_addr = 0; | ||
790 | |||
791 | MULTI_grant_table_op(mcs.mc, | ||
792 | GNTTABOP_unmap_grant_ref, unmap_op, 1); | ||
793 | |||
794 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
795 | |||
796 | set_pte_at(&init_mm, address, ptep, | ||
797 | pfn_pte(pfn, PAGE_KERNEL)); | ||
798 | __flush_tlb_single(address); | ||
799 | map_op->host_addr = 0; | ||
800 | } | ||
801 | } else | ||
802 | set_phys_to_machine(pfn, page->index); | ||
745 | 803 | ||
746 | return 0; | 804 | return 0; |
747 | } | 805 | } |
@@ -758,7 +816,7 @@ struct page *m2p_find_override(unsigned long mfn) | |||
758 | spin_lock_irqsave(&m2p_override_lock, flags); | 816 | spin_lock_irqsave(&m2p_override_lock, flags); |
759 | 817 | ||
760 | list_for_each_entry(p, bucket, lru) { | 818 | list_for_each_entry(p, bucket, lru) { |
761 | if (p->private == mfn) { | 819 | if (page_private(p) == mfn) { |
762 | ret = p; | 820 | ret = p; |
763 | break; | 821 | break; |
764 | } | 822 | } |
@@ -782,17 +840,21 @@ unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn) | |||
782 | EXPORT_SYMBOL_GPL(m2p_find_override_pfn); | 840 | EXPORT_SYMBOL_GPL(m2p_find_override_pfn); |
783 | 841 | ||
784 | #ifdef CONFIG_XEN_DEBUG_FS | 842 | #ifdef CONFIG_XEN_DEBUG_FS |
785 | 843 | #include <linux/debugfs.h> | |
786 | int p2m_dump_show(struct seq_file *m, void *v) | 844 | #include "debugfs.h" |
845 | static int p2m_dump_show(struct seq_file *m, void *v) | ||
787 | { | 846 | { |
788 | static const char * const level_name[] = { "top", "middle", | 847 | static const char * const level_name[] = { "top", "middle", |
789 | "entry", "abnormal" }; | 848 | "entry", "abnormal", "error"}; |
790 | static const char * const type_name[] = { "identity", "missing", | ||
791 | "pfn", "abnormal"}; | ||
792 | #define TYPE_IDENTITY 0 | 849 | #define TYPE_IDENTITY 0 |
793 | #define TYPE_MISSING 1 | 850 | #define TYPE_MISSING 1 |
794 | #define TYPE_PFN 2 | 851 | #define TYPE_PFN 2 |
795 | #define TYPE_UNKNOWN 3 | 852 | #define TYPE_UNKNOWN 3 |
853 | static const char * const type_name[] = { | ||
854 | [TYPE_IDENTITY] = "identity", | ||
855 | [TYPE_MISSING] = "missing", | ||
856 | [TYPE_PFN] = "pfn", | ||
857 | [TYPE_UNKNOWN] = "abnormal"}; | ||
796 | unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0; | 858 | unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0; |
797 | unsigned int uninitialized_var(prev_level); | 859 | unsigned int uninitialized_var(prev_level); |
798 | unsigned int uninitialized_var(prev_type); | 860 | unsigned int uninitialized_var(prev_type); |
@@ -856,4 +918,32 @@ int p2m_dump_show(struct seq_file *m, void *v) | |||
856 | #undef TYPE_PFN | 918 | #undef TYPE_PFN |
857 | #undef TYPE_UNKNOWN | 919 | #undef TYPE_UNKNOWN |
858 | } | 920 | } |
859 | #endif | 921 | |
922 | static int p2m_dump_open(struct inode *inode, struct file *filp) | ||
923 | { | ||
924 | return single_open(filp, p2m_dump_show, NULL); | ||
925 | } | ||
926 | |||
927 | static const struct file_operations p2m_dump_fops = { | ||
928 | .open = p2m_dump_open, | ||
929 | .read = seq_read, | ||
930 | .llseek = seq_lseek, | ||
931 | .release = single_release, | ||
932 | }; | ||
933 | |||
934 | static struct dentry *d_mmu_debug; | ||
935 | |||
936 | static int __init xen_p2m_debugfs(void) | ||
937 | { | ||
938 | struct dentry *d_xen = xen_init_debugfs(); | ||
939 | |||
940 | if (d_xen == NULL) | ||
941 | return -ENOMEM; | ||
942 | |||
943 | d_mmu_debug = debugfs_create_dir("mmu", d_xen); | ||
944 | |||
945 | debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops); | ||
946 | return 0; | ||
947 | } | ||
948 | fs_initcall(xen_p2m_debugfs); | ||
949 | #endif /* CONFIG_XEN_DEBUG_FS */ | ||