⬢ DragonFlyBSD Kernel Audit
DF-4444 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/i915/i915_vma.c b/sys/dev/drm/i915/i915_vma.c
index 1111111..2222222 100644
--- a/sys/dev/drm/i915/i915_vma.c
+++ b/sys/dev/drm/i915/i915_vma.c
@@ -25,6 +25,9 @@
 #include "i915_drv.h"
 #include "intel_ringbuffer.h"
 #include "intel_frontbuffer.h"
+#ifdef __DragonFly__
+#include <vm/pmap.h>		/* pmap_page_protect, vm_phys_fictitious_to_vm_page */
+#endif
 
 #include <drm/drm_gem.h>
 
@@ -854,46 +857,42 @@ static void __i915_vma_iounmap(struct i915_vma *vma)
 	vma->iomap = NULL;
 }
 
 #ifdef __DragonFly__
 /*
- * XXX: this is a bit of a hammer approach
- * On DragonFly, we invalidate the entire set of gem object pages
- * and not just the ones belonging to a particular VMA
+ * Revoke user CPU mappings of this VMA's GGTT aperture window.
+ *
+ * OBJT_MGTDEVICE pages are never inserted into the device vm_object
+ * (i915_gem_fault() hands fictitious aperture pages straight to the
+ * pmap), so vm_object_page_remove()/vm_page_lookup() on the object
+ * cannot see them and the previous implementation removed nothing:
+ * user PTEs into the aperture survived VMA unbind and kept pointing
+ * into whatever object later reused the aperture range.
+ *
+ * The correct zap is at the pmap level: the fictitious pages covering
+ * [gmadr + node.start, gmadr + node.start + node.size) are exactly the
+ * physical pages those PTEs map, and pmap_page_protect(VM_PROT_NONE)
+ * removes every PV entry for them (the same idiom cdev_pager_free_page()
+ * uses in sys/vm/device_pager.c).
  */
-static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node,
-				      struct address_space *file_mapping)
+static void drm_vma_node_unmap(struct i915_vma *vma)
 {
-	struct drm_i915_gem_object *obj = container_of(
-		node,struct drm_i915_gem_object, base.vma_node);
-	vm_object_t devobj;
+	struct i915_ggtt *ggtt = i915_vm_to_ggtt(vma->vm);
 	vm_page_t m;
-	int i, page_count;
+	u64 start, len, off;
 
-	devobj = cdev_pager_lookup(obj);
-	if (devobj != NULL) {
-		page_count = OFF_TO_IDX(obj->base.size);
+	if (!drm_mm_node_allocated(&vma->node))
+		return;
 
-		VM_OBJECT_LOCK(devobj);
-		vm_object_page_remove(devobj, 0, 0, false);
-#if 1
-		for (i = 0; i < page_count; i++) {
-			m = vm_page_lookup_busy_wait(devobj, i, TRUE, "915unm");
-			if (m == NULL)
-				continue;
-			cdev_pager_free_page(devobj, m);
-		}
-#endif
-		VM_OBJECT_UNLOCK(devobj);
-		vm_object_deallocate(devobj);
+	start = vma->node.start;
+	if (start >= ggtt->mappable_end)
+		return;
+	len = min(vma->node.size, ggtt->mappable_end - start);
+
+	for (off = 0; off < len; off += PAGE_SIZE) {
+		m = vm_phys_fictitious_to_vm_page(ggtt->gmadr.start +
+						  start + off);
+		if (m == NULL)
+			continue;
+		pmap_page_protect(m, VM_PROT_NONE);
 	}
 }
 #endif
 
 void i915_vma_revoke_mmap(struct i915_vma *vma)
 {
-	struct drm_vma_offset_node *node = &vma->obj->base.vma_node;
-	u64 vma_offset;
-
 	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
 
 	if (!i915_vma_has_userfault(vma))
@@ -902,16 +901,7 @@ void i915_vma_revoke_mmap(struct i915_vma *vma)
 	GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
 	GEM_BUG_ON(!vma->obj->userfault_count);
 
-	vma_offset = vma->ggtt_view.partial.offset << PAGE_SHIFT;
 #ifdef __DragonFly__
-	drm_vma_node_unmap(node, NULL);
-#else
-	unmap_mapping_range(vma->vm->i915->drm.anon_inode->i_mapping,
-			    drm_vma_node_offset_addr(node) + vma_offset,
-			    vma->size,
-			    1);
+	drm_vma_node_unmap(vma);
 #endif
 
 	i915_vma_unset_userfault(vma);