aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen/p2m.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/xen/p2m.c')
-rw-r--r--arch/x86/xen/p2m.c128
1 files changed, 109 insertions, 19 deletions
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 */