[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] Xen with dom0 pvops on ultra-recent "git tip"kernel on x86_64



Hi again,

ok, to my astonishment this seem to be actually working.

My X server is coming up and seems usable (until my hard disk stops
working after some minutes again :-)).

Here's the patch that's doing the trick for me (the Xen implementation
is mostly copied over from the 2.6.27 SuSE Xen kernel):


Subject: [PATCH] Make io_remap_pfn_range a paravirt operation and have a special
 implementation for it in Xen.

---
 arch/x86/include/asm/paravirt.h   |   12 ++++
 arch/x86/include/asm/pgtable_32.h |    4 ++
 arch/x86/include/asm/pgtable_64.h |    4 ++
 arch/x86/kernel/paravirt.c        |    1 +
 arch/x86/xen/enlighten.c          |    1 +
 arch/x86/xen/mmu.c                |  103 +++++++++++++++++++++++++++++++++++++
 arch/x86/xen/mmu.h                |    4 ++
 7 files changed, 129 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 40795f4..d2a7298 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -39,6 +39,7 @@ struct desc_ptr;
 struct tss_struct;
 struct mm_struct;
 struct desc_struct;
+struct vm_area_struct;
 
 /* general info */
 struct pv_info {
@@ -326,6 +327,10 @@ struct pv_mmu_ops {
                           unsigned long phys, pgprot_t flags);
 
        int (*page_is_ram)(unsigned long pfn);
+
+       int (*io_remap_pfn_range)(struct vm_area_struct *vma,
+                                 unsigned long address, unsigned long mfn,
+                                 unsigned long size, pgprot_t prot);
 };
 
 struct raw_spinlock;
@@ -1402,6 +1407,13 @@ static inline int page_is_ram(unsigned long pfn)
        return PVOP_CALL1(int, pv_mmu_ops.page_is_ram, pfn);
 }
 
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+                                     unsigned long vaddr, unsigned long pfn,
+                                     unsigned long size, pgprot_t prot)
+{
+       return pv_mmu_ops.io_remap_pfn_range(vma, vaddr, pfn, size, prot);
+}
+
 void _paravirt_nop(void);
 #define paravirt_nop   ((void *)_paravirt_nop)
 
diff --git a/arch/x86/include/asm/pgtable_32.h 
b/arch/x86/include/asm/pgtable_32.h
index 56e1560..ab2419b 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -182,7 +182,11 @@ do {                                               \
 #define kern_addr_valid(kaddr) (0)
 #endif
 
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)        \
        remap_pfn_range(vma, vaddr, pfn, size, prot)
+#endif
 
 #endif /* _ASM_X86_PGTABLE_32_H */
diff --git a/arch/x86/include/asm/pgtable_64.h 
b/arch/x86/include/asm/pgtable_64.h
index 537081e..293570f 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -272,8 +272,12 @@ extern int direct_gbpages;
 extern int kern_addr_valid(unsigned long addr);
 extern void cleanup_highmap(void);
 
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)        \
        remap_pfn_range(vma, vaddr, pfn, size, prot)
+#endif
 
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 602edc0..81c2e15 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -453,6 +453,7 @@ struct pv_mmu_ops pv_mmu_ops = {
 
        .set_fixmap = native_set_fixmap,
        .page_is_ram = native_page_is_ram,
+       .io_remap_pfn_range = remap_pfn_range
 };
 
 EXPORT_SYMBOL_GPL(pv_time_ops);
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 360f04b..643d00f 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1401,6 +1401,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
        .set_fixmap = xen_set_fixmap,
        .page_is_ram = xen_page_is_ram,
+       .io_remap_pfn_range = xen_io_remap_pfn_range
 };
 
 static void xen_reboot(int reason)
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 72069b1..d0a9348 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1441,6 +1441,109 @@ void xen_destroy_contiguous_region(unsigned long 
vstart, unsigned int order)
 }
 EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
 
+static inline pte_t pfn_pte_ma(unsigned long page_nr, pgprot_t pgprot)
+{
+       pgprotval_t prot = pgprot_val(pgprot);
+
+       if (prot & _PAGE_PRESENT)
+               prot &= __supported_pte_mask;
+       return __pte_ma(((phys_addr_t)page_nr << PAGE_SHIFT) | prot);
+}
+                                        
+static int direct_remap_area_pte_fn(pte_t *pte,
+                                   struct page *pmd_page,
+                                   unsigned long address,
+                                   void *data)
+{
+       struct mmu_update **v = (struct mmu_update **)data;
+
+       BUG_ON(!pte_none(*pte));
+
+       (*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pmd_page)) <<
+                    PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
+       (*v)++;
+
+       return 0;
+}
+
+static int __direct_remap_pfn_range(struct mm_struct *mm,
+                                   unsigned long address,
+                                   unsigned long mfn,
+                                   unsigned long size,
+                                   pgprot_t prot,
+                                   domid_t  domid)
+{
+       int rc;
+       unsigned long i, start_address;
+       struct mmu_update *u, *v, *w;
+
+       u = v = w = (struct mmu_update 
*)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
+       if (u == NULL)
+               return -ENOMEM;
+
+       start_address = address;
+
+       flush_cache_all();
+
+       for (i = 0; i < size; i += PAGE_SIZE) {
+               if ((v - u) == (PAGE_SIZE / sizeof(struct mmu_update))) {
+                       /* Flush a full batch after filling in the PTE ptrs. */
+                       rc = apply_to_page_range(mm, start_address,
+                                                address - start_address,
+                                                direct_remap_area_pte_fn, &w);
+                       if (rc)
+                               goto out;
+                       rc = -EFAULT;
+                       if (HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0)
+                               goto out;
+                       v = w = u;
+                       start_address = address;
+               }
+
+               /*
+                * Fill in the machine address: PTE ptr is done later by
+                * apply_to_page_range().
+                */
+                v->val = pfn_pte_ma(mfn, prot).pte
+                         | _PAGE_SPECIAL | _PAGE_IOMAP;
+
+               mfn++;
+               address += PAGE_SIZE;
+               v++;
+       }
+
+       if (v != u) {
+               /* Final batch. */
+               rc = apply_to_page_range(mm, start_address,
+                                        address - start_address,
+                                        direct_remap_area_pte_fn, &w);
+               if (rc)
+                       goto out;
+               rc = -EFAULT;
+               if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0))
+                       goto out;
+       }
+
+       rc = 0;
+
+ out:
+       flush_tlb_all();
+
+       free_page((unsigned long)u);
+
+       return rc;
+}
+
+int xen_io_remap_pfn_range(struct vm_area_struct *vma,
+                           unsigned long address, unsigned long mfn,
+                           unsigned long size, pgprot_t prot)
+{
+       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+
+       return __direct_remap_pfn_range(
+               vma->vm_mm, address, mfn, size, prot, DOMID_IO);
+}
+
 #ifdef CONFIG_XEN_DEBUG_FS
 
 static struct dentry *d_mmu_debug;
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 98d7165..e1c8321 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -54,4 +54,8 @@ pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, 
unsigned long addr, pte_t
 void  xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
                                  pte_t *ptep, pte_t pte);
 
+int xen_io_remap_pfn_range(struct vm_area_struct *vma,
+                           unsigned long address, unsigned long mfn,
+                           unsigned long size, pgprot_t prot);
+
 #endif /* _XEN_MMU_H */
-- 
1.6.1




_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.