Skip to content

Commit 8bdd9ef

Browse files
Andi Shytijlahtine-intel
authored andcommitted
drm/i915/gem: Fix Virtual Memory mapping boundaries calculation
Calculating the size of the mapped area as the lesser value between the requested size and the actual size does not consider the partial mapping offset. This can cause page fault access. Fix the calculation of the starting and ending addresses, the total size is now deduced from the difference between the end and start addresses. Additionally, the calculations have been rewritten in a clearer and more understandable form. Fixes: c58305a ("drm/i915: Use remap_io_mapping() to prefault all PTE in a single pass") Reported-by: Jann Horn <jannh@google.com> Co-developed-by: Chris Wilson <chris.p.wilson@linux.intel.com> Signed-off-by: Chris Wilson <chris.p.wilson@linux.intel.com> Signed-off-by: Andi Shyti <andi.shyti@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.auld@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: <stable@vger.kernel.org> # v4.9+ Reviewed-by: Jann Horn <jannh@google.com> Reviewed-by: Jonathan Cavitt <Jonathan.cavitt@intel.com> [Joonas: Add Requires: tag] Requires: 60a2066 ("drm/i915/gem: Adjust vma offset for framebuffer mmap offset") Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240802083850.103694-3-andi.shyti@linux.intel.com (cherry picked from commit 97b6784) Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
1 parent 1ac5167 commit 8bdd9ef

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

drivers/gpu/drm/i915/gem/i915_gem_mman.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,41 @@ static vm_fault_t vm_fault_cpu(struct vm_fault *vmf)
290290
return i915_error_to_vmf_fault(err);
291291
}
292292

293+
static void set_address_limits(struct vm_area_struct *area,
294+
struct i915_vma *vma,
295+
unsigned long obj_offset,
296+
unsigned long *start_vaddr,
297+
unsigned long *end_vaddr)
298+
{
299+
unsigned long vm_start, vm_end, vma_size; /* user's memory parameters */
300+
long start, end; /* memory boundaries */
301+
302+
/*
303+
* Let's move into the ">> PAGE_SHIFT"
304+
* domain to be sure not to lose bits
305+
*/
306+
vm_start = area->vm_start >> PAGE_SHIFT;
307+
vm_end = area->vm_end >> PAGE_SHIFT;
308+
vma_size = vma->size >> PAGE_SHIFT;
309+
310+
/*
311+
* Calculate the memory boundaries by considering the offset
312+
* provided by the user during memory mapping and the offset
313+
* provided for the partial mapping.
314+
*/
315+
start = vm_start;
316+
start -= obj_offset;
317+
start += vma->gtt_view.partial.offset;
318+
end = start + vma_size;
319+
320+
start = max_t(long, start, vm_start);
321+
end = min_t(long, end, vm_end);
322+
323+
/* Let's move back into the "<< PAGE_SHIFT" domain */
324+
*start_vaddr = (unsigned long)start << PAGE_SHIFT;
325+
*end_vaddr = (unsigned long)end << PAGE_SHIFT;
326+
}
327+
293328
static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
294329
{
295330
#define MIN_CHUNK_PAGES (SZ_1M >> PAGE_SHIFT)
@@ -302,14 +337,18 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
302337
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
303338
bool write = area->vm_flags & VM_WRITE;
304339
struct i915_gem_ww_ctx ww;
340+
unsigned long obj_offset;
341+
unsigned long start, end; /* memory boundaries */
305342
intel_wakeref_t wakeref;
306343
struct i915_vma *vma;
307344
pgoff_t page_offset;
345+
unsigned long pfn;
308346
int srcu;
309347
int ret;
310348

311-
/* We don't use vmf->pgoff since that has the fake offset */
349+
obj_offset = area->vm_pgoff - drm_vma_node_start(&mmo->vma_node);
312350
page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT;
351+
page_offset += obj_offset;
313352

314353
trace_i915_gem_object_fault(obj, page_offset, true, write);
315354

@@ -402,12 +441,14 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
402441
if (ret)
403442
goto err_unpin;
404443

444+
set_address_limits(area, vma, obj_offset, &start, &end);
445+
446+
pfn = (ggtt->gmadr.start + i915_ggtt_offset(vma)) >> PAGE_SHIFT;
447+
pfn += (start - area->vm_start) >> PAGE_SHIFT;
448+
pfn += obj_offset - vma->gtt_view.partial.offset;
449+
405450
/* Finally, remap it using the new GTT offset */
406-
ret = remap_io_mapping(area,
407-
area->vm_start + (vma->gtt_view.partial.offset << PAGE_SHIFT),
408-
(ggtt->gmadr.start + i915_ggtt_offset(vma)) >> PAGE_SHIFT,
409-
min_t(u64, vma->size, area->vm_end - area->vm_start),
410-
&ggtt->iomap);
451+
ret = remap_io_mapping(area, start, pfn, end - start, &ggtt->iomap);
411452
if (ret)
412453
goto err_fence;
413454

0 commit comments

Comments
 (0)