--- a/sys/dev/drm/drm_vm.c +++ b/sys/dev/drm/drm_vm.c @@ -38,6 +38,10 @@ * NOTE: This handler is unreachable on every DRM driver DragonFly ships: * vm_mmap() prefers d_mmap_single (drm_mmap_single), which only * returns ENODEV for a driver with neither TTM nor DRIVER_GEM, and * i915/radeon/amdgpu all have one of the two. Deletion preferred; * the corrections below are advisory in case a legacy non-GEM driver * is ever ported. */ int drm_mmap(struct dev_mmap_args *ap) { struct file *filp = ap->a_fp; struct drm_file *priv; struct cdev *kdev = ap->a_head.a_dev; vm_offset_t offset = ap->a_offset; struct drm_device *dev = drm_get_device_from_kdev(kdev); struct drm_local_map *map = NULL; struct drm_map_list *maplist; + vm_offset_t token; struct drm_hash_item *hash; enum drm_map_type type; vm_paddr_t phys; @@ - if (dma->pagelist != NULL) { + if (dma->pagelist != NULL) { unsigned long page = offset >> PAGE_SHIFT; unsigned long phys = dma->pagelist[page]; - // XXX *paddr = phys; - ap->a_result = phys; + /* d_mmap must return a page frame number: + * old_dev_pager_fault() feeds the result through + * pmap_phys_address() == ptob(ppn). */ + ap->a_result = atop(phys); return 0; } else { return -1; @@ - if (drm_ht_find_item(&dev->map_hash, offset, &hash)) { + /* map_hash keys are page numbers (drm_bufs.c drm_map_handle), + * but a_offset is a byte offset. */ + if (drm_ht_find_item(&dev->map_hash, offset >> PAGE_SHIFT, &hash)) { DRM_ERROR("Could not find map\n"); DRM_UNLOCK(dev); return -EINVAL; } - map = drm_hash_entry(hash, struct drm_map_list, hash)->map; + maplist = drm_hash_entry(hash, struct drm_map_list, hash); + map = maplist->map; if (map == NULL) { DRM_DEBUG("Can't find map, request offset = %016jx\n", (uintmax_t)offset); @@ type = map->type; + token = maplist->user_token; /* must be read under DRM_LOCK */ DRM_UNLOCK(dev); + /* Rebase: a_offset is absolute; the map arithmetic below needs + * the offset within the map, not the user token. */ + offset -= token; + if (offset >= map->size) /* bound the mapping like Linux drm_vm */ + return -1; + switch (type) {