diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index a33e443..d783da8 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ struct grant_map { struct ioctl_gntdev_grant_ref *grants; struct gnttab_map_grant_ref *map_ops; struct gnttab_unmap_grant_ref *unmap_ops; + void* start; }; /* ------------------------------------------------------------------ */ @@ -95,6 +97,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); + add->start = NULL; if (NULL == add->grants || NULL == add->map_ops || NULL == add->unmap_ops) @@ -187,6 +190,7 @@ static void gntdev_free_map(struct grant_map *map) { if (!map) return; + vfree(map->start); kfree(map->grants); kfree(map->map_ops); kfree(map->unmap_ops); @@ -212,6 +216,24 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token, unsigned long addr, void return 0; } +static int hvm_setup_grant_ops(struct grant_map *map) +{ + int i; + map->start = vmalloc(map->count << PAGE_SHIFT); + if (!map->start) + return -ENOMEM; + + for(i = 0; i < map->count; i++) { + void* address = map->start + (i << PAGE_SHIFT); + u64 mfn = (u64)pfn_to_kaddr(vmalloc_to_pfn(address)); + gnttab_set_map_op(&map->map_ops[i], mfn, map->flags, + map->grants[i].ref, map->grants[i].domid); + gnttab_set_unmap_op(&map->unmap_ops[i], mfn, map->flags, 0); + } + + return 0; +} + static int map_grant_pages(struct grant_map *map) { int i, err = 0; @@ -266,10 +288,27 @@ static void gntdev_vma_close(struct vm_area_struct *vma) static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - if (debug) - printk("%s: vaddr %p, pgoff %ld (shouldn't happen)\n", - __FUNCTION__, vmf->virtual_address, vmf->pgoff); - vmf->flags = VM_FAULT_ERROR; + struct page *page; + struct grant_map *map = vma->vm_private_data; + pgoff_t pgoff = vmf->pgoff - vma->vm_pgoff; + + if (!map || !map->start) { + if (debug) + printk("%s: vaddr %p, pgoff %ld (shouldn't happen)\n", + __FUNCTION__, vmf->virtual_address, pgoff); + return VM_FAULT_SIGBUS; + } + + if (pgoff < 0 || pgoff > map->count) + return VM_FAULT_SIGBUS; + + page = vmalloc_to_page(map->start + (pgoff << PAGE_SHIFT)); + if (!page) + return VM_FAULT_SIGBUS; + + get_page(page); + vmf->page = page; + return 0; } @@ -573,29 +612,33 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_DONTCOPY; vma->vm_flags |= VM_DONTEXPAND; + vma->vm_flags |= VM_FOREIGN; vma->vm_private_data = map; map->vma = vma; - map->flags = GNTMAP_host_map | GNTMAP_application_map | GNTMAP_contains_pte; + map->flags = GNTMAP_host_map; if (!(vma->vm_flags & VM_WRITE)) map->flags |= GNTMAP_readonly; - err = apply_to_page_range(vma->vm_mm, vma->vm_start, - vma->vm_end - vma->vm_start, - find_grant_ptes, map); - if (err) { - goto unlock_out; - if (debug) - printk("%s: find_grant_ptes() failure.\n", __FUNCTION__); + if (xen_pv_domain()) { + // Add foreign mapping by page table modification + map->flags |= GNTMAP_application_map | GNTMAP_contains_pte; + + err = apply_to_page_range(vma->vm_mm, vma->vm_start, + vma->vm_end - vma->vm_start, + find_grant_ptes, map); + } else { + // Add mapping by sharing in-domain memory + err = hvm_setup_grant_ops(map); } + if (err) + goto unlock_out; err = map_grant_pages(map); - if (err) { + if (err) goto unlock_out; - if (debug) - printk("%s: map_grant_pages() failure.\n", __FUNCTION__); - } + map->is_mapped = 1; unlock_out: