[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |