Skip to content

Commit a5f0edf

Browse files
mwiniarsjnikula
authored andcommitted
drm/i915: Avoid writing relocs with addresses in non-canonical form
According to PRM, some parts of HW require the addresses to be in a canonical form, where bits [63:48] == [47]. Let's convert addresses to canonical form prior to relocating and return converted offsets to userspace. We also need to make sure that userspace is using addresses in canonical form in case of softpin. v2: Whitespace fixup, gen8_canonical_addr description (Chris, Ville) v3: Rebase on top of softpin, fix a hole in relocate_entry, s/expect/require (Chris) v4: Handle softpin in validate_exec_list (Chris) v5: Convert back to canonical form at copy_to_user time (Chris) v6: Don't use struct exec_object2 in place of exec_object v7: Use sign_extend64 for converting to canonical form (Joonas), reject non-canonical and non-page-aligned offset for softpin (Chris) v8: Convert back to non-canonical form in a function, split the test for EXEC_OBJECT_PINNED (Chris) v9: s/canonial/canonical, drop accidental double newline (Chris) Cc: Chris Wilson <[email protected]> Cc: Michel Thierry <[email protected]> Cc: Ville Syrjälä <[email protected]> Signed-off-by: Michał Winiarski <[email protected]> Link: http://patchwork.freedesktop.org/patch/msgid/[email protected] Testcase: igt/gem_bad_reloc/negative-reloc-blt Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92699 Cc: [email protected] Reviewed-by: Chris Wilson <[email protected]> Signed-off-by: Daniel Vetter <[email protected]> (cherry picked from commit 934acce) Signed-off-by: Jani Nikula <[email protected]>
1 parent d5f384d commit a5f0edf

File tree

1 file changed

+48
-4
lines changed

1 file changed

+48
-4
lines changed

drivers/gpu/drm/i915/i915_gem_execbuffer.c

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,39 @@ static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
249249
obj->cache_level != I915_CACHE_NONE);
250250
}
251251

252+
/* Used to convert any address to canonical form.
253+
* Starting from gen8, some commands (e.g. STATE_BASE_ADDRESS,
254+
* MI_LOAD_REGISTER_MEM and others, see Broadwell PRM Vol2a) require the
255+
* addresses to be in a canonical form:
256+
* "GraphicsAddress[63:48] are ignored by the HW and assumed to be in correct
257+
* canonical form [63:48] == [47]."
258+
*/
259+
#define GEN8_HIGH_ADDRESS_BIT 47
260+
static inline uint64_t gen8_canonical_addr(uint64_t address)
261+
{
262+
return sign_extend64(address, GEN8_HIGH_ADDRESS_BIT);
263+
}
264+
265+
static inline uint64_t gen8_noncanonical_addr(uint64_t address)
266+
{
267+
return address & ((1ULL << (GEN8_HIGH_ADDRESS_BIT + 1)) - 1);
268+
}
269+
270+
static inline uint64_t
271+
relocation_target(struct drm_i915_gem_relocation_entry *reloc,
272+
uint64_t target_offset)
273+
{
274+
return gen8_canonical_addr((int)reloc->delta + target_offset);
275+
}
276+
252277
static int
253278
relocate_entry_cpu(struct drm_i915_gem_object *obj,
254279
struct drm_i915_gem_relocation_entry *reloc,
255280
uint64_t target_offset)
256281
{
257282
struct drm_device *dev = obj->base.dev;
258283
uint32_t page_offset = offset_in_page(reloc->offset);
259-
uint64_t delta = reloc->delta + target_offset;
284+
uint64_t delta = relocation_target(reloc, target_offset);
260285
char *vaddr;
261286
int ret;
262287

@@ -292,7 +317,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
292317
{
293318
struct drm_device *dev = obj->base.dev;
294319
struct drm_i915_private *dev_priv = dev->dev_private;
295-
uint64_t delta = reloc->delta + target_offset;
320+
uint64_t delta = relocation_target(reloc, target_offset);
296321
uint64_t offset;
297322
void __iomem *reloc_page;
298323
int ret;
@@ -347,7 +372,7 @@ relocate_entry_clflush(struct drm_i915_gem_object *obj,
347372
{
348373
struct drm_device *dev = obj->base.dev;
349374
uint32_t page_offset = offset_in_page(reloc->offset);
350-
uint64_t delta = (int)reloc->delta + target_offset;
375+
uint64_t delta = relocation_target(reloc, target_offset);
351376
char *vaddr;
352377
int ret;
353378

@@ -395,7 +420,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
395420
target_i915_obj = target_vma->obj;
396421
target_obj = &target_vma->obj->base;
397422

398-
target_offset = target_vma->node.start;
423+
target_offset = gen8_canonical_addr(target_vma->node.start);
399424

400425
/* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
401426
* pipe_control writes because the gpu doesn't properly redirect them
@@ -994,6 +1019,21 @@ validate_exec_list(struct drm_device *dev,
9941019
if (exec[i].flags & invalid_flags)
9951020
return -EINVAL;
9961021

1022+
/* Offset can be used as input (EXEC_OBJECT_PINNED), reject
1023+
* any non-page-aligned or non-canonical addresses.
1024+
*/
1025+
if (exec[i].flags & EXEC_OBJECT_PINNED) {
1026+
if (exec[i].offset !=
1027+
gen8_canonical_addr(exec[i].offset & PAGE_MASK))
1028+
return -EINVAL;
1029+
1030+
/* From drm_mm perspective address space is continuous,
1031+
* so from this point we're always using non-canonical
1032+
* form internally.
1033+
*/
1034+
exec[i].offset = gen8_noncanonical_addr(exec[i].offset);
1035+
}
1036+
9971037
if (exec[i].alignment && !is_power_of_2(exec[i].alignment))
9981038
return -EINVAL;
9991039

@@ -1687,6 +1727,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
16871727

16881728
/* Copy the new buffer offsets back to the user's exec list. */
16891729
for (i = 0; i < args->buffer_count; i++) {
1730+
exec2_list[i].offset =
1731+
gen8_canonical_addr(exec2_list[i].offset);
16901732
ret = __copy_to_user(&user_exec_list[i].offset,
16911733
&exec2_list[i].offset,
16921734
sizeof(user_exec_list[i].offset));
@@ -1752,6 +1794,8 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
17521794
int i;
17531795

17541796
for (i = 0; i < args->buffer_count; i++) {
1797+
exec2_list[i].offset =
1798+
gen8_canonical_addr(exec2_list[i].offset);
17551799
ret = __copy_to_user(&user_exec_list[i].offset,
17561800
&exec2_list[i].offset,
17571801
sizeof(user_exec_list[i].offset));

0 commit comments

Comments
 (0)