static int netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset, int prot, vm_page_t *mres) { struct netmap_vm_handle_t *vmh = object->handle; struct netmap_priv_d *priv = vmh->priv; vm_paddr_t paddr; vm_page_t page; vm_memattr_t memattr; vm_pindex_t pidx; ND("object %p offset %jd prot %d mres %p", object, (intmax_t)offset, prot, mres); memattr = object->memattr; pidx = OFF_TO_IDX(offset); paddr = netmap_mem_ofstophys(priv->np_mref, offset); if (paddr == 0) return VM_PAGER_FAIL; if (((*mres)->flags & PG_FICTITIOUS) != 0) { /* * If the passed in result page is a fake page, update it with * the new physical address. */ page = *mres; vm_page_updatefake(page, paddr, memattr); } else { /* * Replace the passed in reqpage page with our own fake page and * free up the all of the original pages. */ #ifndef VM_OBJECT_WUNLOCK /* FreeBSD < 10.x */ #define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK #define VM_OBJECT_WLOCK VM_OBJECT_LOCK #endif /* VM_OBJECT_WUNLOCK */ VM_OBJECT_WUNLOCK(object); page = vm_page_getfake(paddr, memattr); VM_OBJECT_WLOCK(object); vm_page_free(*mres); *mres = page; vm_page_insert(page, object, pidx); } page->valid = VM_PAGE_BITS_ALL; return (VM_PAGER_OK); }
static int linux_netmap_mmap(struct file *f, struct vm_area_struct *vma) { int error = 0; unsigned long off; u_int memsize, memflags; struct netmap_priv_d *priv = f->private_data; struct netmap_adapter *na = priv->np_na; /* * vma->vm_start: start of mapping user address space * vma->vm_end: end of the mapping user address space * vma->vm_pfoff: offset of first page in the device */ if (priv->np_nifp == NULL) { return -EINVAL; } mb(); /* check that [off, off + vsize) is within our memory */ error = netmap_mem_get_info(na->nm_mem, &memsize, &memflags, NULL); ND("get_info returned %d", error); if (error) return -error; off = vma->vm_pgoff << PAGE_SHIFT; ND("off %lx size %lx memsize %x", off, (vma->vm_end - vma->vm_start), memsize); if (off + (vma->vm_end - vma->vm_start) > memsize) return -EINVAL; if (memflags & NETMAP_MEM_IO) { vm_ooffset_t pa; /* the underlying memory is contiguous */ pa = netmap_mem_ofstophys(na->nm_mem, 0); if (pa == 0) return -EINVAL; return remap_pfn_range(vma, vma->vm_start, pa >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } else {
int linux_netmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct netmap_priv_d *priv = vma->vm_private_data; struct netmap_adapter *na = priv->np_na; struct page *page; unsigned long off = (vma->vm_pgoff + vmf->pgoff) << PAGE_SHIFT; unsigned long pa, pfn; pa = netmap_mem_ofstophys(na->nm_mem, off); ND("fault off %lx -> phys addr %lx", off, pa); if (pa == 0) return VM_FAULT_SIGBUS; pfn = pa >> PAGE_SHIFT; if (!pfn_valid(pfn)) return VM_FAULT_SIGBUS; page = pfn_to_page(pfn); get_page(page); vmf->page = page; return 0; }