On Wed, 14 Sep 2011, Jiageng Yu wrote:
> Hi Stefano,
>
> I just have a prototype of vram mapping and test it now. The
> implementation of linux-stubdom kernel part is as follows.
> xen_remap_domain_mfn_range2 function maps foreign dom's physical
> address into linux kernel space. It is similar to
> xen_remap_domain_mfn_range. But xen_remap_domain_mfn_range is used to
> map foreign pages into linux user space.
>
> But the page info seems wrong after executing xen_remap_domain_mfn_range2.
>
> struct page *page=pfn_to_page(vmalloc_to_pfn(info->fb));
>
> The page->_count = 0xc2c2c2c2. It is very strange.
>
> Did I do the right thing?
>
use page_address instead of pfn_to_page to find the struct page
> Greeting.
>
> Jiageng Yu.
>
>
> diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
> index 204e3ba..72a7808 100644
> --- a/arch/x86/xen/mmu.c
> +++ b/arch/x86/xen/mmu.c
> @@ -2693,6 +2693,73 @@ out:
> }
> EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
>
> +int xen_remap_domain_mfn_range2(unsigned long addr,unsigned long gpfn,
> + int nr, unsigned domid)
> +{
> + struct remap_data rmd;
> + struct mmu_update mmu_update[REMAP_BATCH_SIZE];
> + int level,i,batch,nr_page = nr;
> + unsigned long range;
> + int err = 0;
> + unsigned long vaddr,base_addr = addr;
> + pte_t pte,*ptep;
> +
> + rmd.mfn = gpfn;
> + rmd.prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED |
> _PAGE_IOMAP);
> +
> + while(nr_page) {
> + batch = min(REMAP_BATCH_SIZE, nr);
> + range = (unsigned long)batch << PAGE_SHIFT;
> +
> + rmd.mmu_update = mmu_update;
> +
> + for(i=0; i < batch; i++){
> + pte = pte_mkspecial(pfn_pte(rmd.mfn++, rmd.prot));
> + vaddr = base_addr + i*PAGE_SIZE;
> + ptep = lookup_address(vaddr, &level);
you need to check if ptep is valid here and the level is PG_LEVEL_4K
> + rmd.mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr |
> + MMU_NORMAL_PT_UPDATE;
you can use pte_mfn(*ptep) instead of arbitrary_virt_to_machine
> + rmd.mmu_update->val = pte_val_ma(pte);
> + rmd.mmu_update++;
> + }
> +
> + err = -EFAULT;
> + if(HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
> + goto out;
> +
> + nr_page -= batch;
> + base_addr += range;
> + }
> +
> + err = 0;
> +
> + base_addr = addr;
> + for(i=0; i < nr; i++){
> + vaddr = base_addr + i*PAGE_SIZE;
> + set_phys_to_machine(vmalloc_to_pfn(vaddr),
> + arbitrary_virt_to_machine(vaddr).maddr >> PAGE_SHIFT);
> + }
The second argument (mfn) to set_phys_to_machine is wrong:
arbitrary_virt_to_machine ends up calling virt_to_machine if
virt_addr_valid. You need to manually call pte_mfn:
/* the ptep content has been updated by Xen so we can lookup the foreign
* mfn from the pte now */
pte = lookup_address(vaddr, &level);
BUG_ON(pte == NULL);
offset = vaddr & ~PAGE_MASK;
mfn = XMADDR(((phys_addr_t)pte_mfn(*pte) << PAGE_SHIFT) + offset);
> +
> +out:
> + flush_tlb_all();
> + return err;
> +}
> +EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range2);
the name should be changed to xen_remap_foreign_gpfn_range
> #ifdef CONFIG_XEN_PVHVM
> static void xen_hvm_exit_mmap(struct mm_struct *mm)
> {
> diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
> index dc72563..82da2ee 100644
> --- a/drivers/video/xen-fbfront.c
> +++ b/drivers/video/xen-fbfront.c
> @@ -25,8 +25,12 @@
> #include <linux/module.h>
> #include <linux/vmalloc.h>
> #include <linux/mm.h>
> +#include <linux/sched.h>
> +#include <asm/pgtable.h>
> +#include <asm/page.h>
>
> #include <asm/xen/hypervisor.h>
> +#include <asm/xen/page.h>
>
> #include <xen/xen.h>
> #include <xen/events.h>
> @@ -34,6 +38,7 @@
> #include <xen/interface/io/fbif.h>
> #include <xen/interface/io/protocols.h>
> #include <xen/xenbus.h>
> +#include <xen/xen-ops.h>
>
> struct xenfb_info {
> unsigned char *fb;
> @@ -62,6 +67,12 @@ module_param_array(video, int, NULL, 0);
> MODULE_PARM_DESC(video,
> "Video memory size in MB, width, height in pixels (default 2,800,600)");
>
> +static unsigned long foreign_vaddr = 0;
> +module_param(foreign_vaddr, ulong, S_IRUGO);
> +
> +static unsigned long foreign_domid = 0;
> +module_param(foreign_domid, ulong, S_IRUGO);
> +
> static void xenfb_make_preferred_console(void);
> static int xenfb_remove(struct xenbus_device *);
> static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);
> @@ -398,7 +408,17 @@ static int __devinit xenfb_probe(struct xenbus_device
> *dev,
> if (info->fb == NULL)
> goto error_nomem;
> memset(info->fb, 0, fb_size);
> -
> + if((foreign_vaddr != 0) && (foreign_domid != 0)){
> + ret = xen_remap_domain_mfn_range2((unsigned long)(info->fb),
> + foreign_vaddr >> PAGE_SHIFT,
> + fb_size >> PAGE_SHIFT, foreign_domid);
you should rename foreign_vaddr to foreign_gpfn and pass the gpfn value
that is the ram_addr (page shifted) passed to xen_ram_alloc in qemu.
> + if(ret < 0){
> + printk("Can not remap vram of hvm guest.\n");
> + goto error;
> + }
> + }
> info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
>
> info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
> diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
> index 4349e89..1554531 100644
> --- a/include/xen/xen-ops.h
> +++ b/include/xen/xen-ops.h
> @@ -20,6 +20,10 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
> unsigned long mfn, int nr,
> pgprot_t prot, unsigned domid);
>
> +int xen_remap_domain_mfn_range2(unsigned long addr,unsigned long mfn,
> + int nr, unsigned domid);
> extern unsigned long *xen_contiguous_bitmap;
> int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
> unsigned int address_bits);
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|