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);
}
Beispiel #2
0
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 {
Beispiel #3
0
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;
}