aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/Kconfig8
-rw-r--r--arch/x86/xen/enlighten.c1
-rw-r--r--arch/x86/xen/mmu.c52
-rw-r--r--arch/x86/xen/p2m.c128
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
53config 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}
496PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte); 496PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
497 497
498#ifdef CONFIG_XEN_DEBUG
499pte_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}
530PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
531#endif
532
533static pgd_t xen_make_pgd(pgdval_t pgd) 498static 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
1993static void __init xen_post_allocator_init(void) 1958static 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}
2406EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); 2368EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
2407
2408#ifdef CONFIG_XEN_DEBUG_FS
2409static int p2m_dump_open(struct inode *inode, struct file *filp)
2410{
2411 return single_open(filp, p2m_dump_show, NULL);
2412}
2413
2414static 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
167static void __init m2p_override_init(void); 169static 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 */
679int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) 681int 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)
782EXPORT_SYMBOL_GPL(m2p_find_override_pfn); 840EXPORT_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>
786int p2m_dump_show(struct seq_file *m, void *v) 844#include "debugfs.h"
845static 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
922static int p2m_dump_open(struct inode *inode, struct file *filp)
923{
924 return single_open(filp, p2m_dump_show, NULL);
925}
926
927static 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
934static struct dentry *d_mmu_debug;
935
936static 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}
948fs_initcall(xen_p2m_debugfs);
949#endif /* CONFIG_XEN_DEBUG_FS */