Skip to content

Commit 100d46b

Browse files
committed
Merge Intel Gen8/Gen9 graphics fixes from Jon Bloomfield.
This fixes two different classes of bugs in the Intel graphics hardware: MMIO register read hang: "On Intels Gen8 and Gen9 Graphics hardware, a read of specific graphics MMIO registers when the product is in certain low power states causes a system hang. There are two potential triggers for DoS: a) H/W corruption of the RC6 save/restore vector b) Hard hang within the MIPI hardware This prevents the DoS in two areas of the hardware: 1) Detect corruption of RC6 address on exit from low-power state, and if we find it corrupted, disable RC6 and RPM 2) Permanently lower the MIPI MMIO timeout" Blitter command streamer unrestricted memory accesses: "On Intels Gen9 Graphics hardware the Blitter Command Streamer (BCS) allows writing to Memory Mapped Input Output (MMIO) that should be blocked. With modifications of page tables, this can lead to privilege escalation. This exposure is limited to the Guest Physical Address space and does not allow for access outside of the graphics virtual machine. This series establishes a software parser into the Blitter command stream to scan for, and prevent, reads or writes to MMIO's that should not be accessible to non-privileged contexts. Much of the command parser infrastructure has existed for some time, and is used on Ivybridge/Haswell/Valleyview derived products to allow the use of features normally blocked by hardware. In this legacy context, the command parser is employed to allow normally unprivileged submissions to be run with elevated privileges in order to grant access to a limited set of extra capabilities. In this mode the parser is optional; In the event that the parser finds any construct that it cannot properly validate (e.g. nested command buffers), it simply aborts the scan and submits the buffer in non-privileged mode. For Gen9 Graphics, this series makes the parser mandatory for all Blitter submissions. The incoming user buffer is first copied to a kernel owned buffer, and parsed. If all checks are successful the kernel owned buffer is mapped READ-ONLY and submitted on behalf of the user. If any checks fail, or the parser is unable to complete the scan (nested buffers), it is forcibly rejected. The successfully scanned buffer is executed with NORMAL user privileges (key difference from legacy usage). Modern usermode does not use the Blitter on later hardware, having switched over to using the 3D engine instead for performance reasons. There are however some legacy usermode apps that rely on Blitter, notably the SNA X-Server. There are no known usermode applications that require nested command buffers on the Blitter, so the forcible rejection of such buffers in this patch series is considered an acceptable limitation" * Intel graphics fixes in emailed bundle from Jon Bloomfield <[email protected]>: drm/i915/cmdparser: Fix jump whitelist clearing drm/i915/gen8+: Add RC6 CTX corruption WA drm/i915: Lower RM timeout to avoid DSI hard hangs drm/i915/cmdparser: Ignore Length operands during command matching drm/i915/cmdparser: Add support for backward jumps drm/i915/cmdparser: Use explicit goto for error paths drm/i915: Add gen9 BCS cmdparsing drm/i915: Allow parsing of unsized batches drm/i915: Support ro ppgtt mapped cmdparser shadow buffers drm/i915: Add support for mandatory cmdparsing drm/i915: Remove Master tables from cmdparser drm/i915: Disable Secure Batches for gen6+ drm/i915: Rename gen7 cmdparser tables
2 parents de620fb + ea0b163 commit 100d46b

13 files changed

+595
-172
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
319319
free_engines(rcu_access_pointer(ctx->engines));
320320
mutex_destroy(&ctx->engines_mutex);
321321

322+
kfree(ctx->jump_whitelist);
323+
322324
if (ctx->timeline)
323325
intel_timeline_put(ctx->timeline);
324326

@@ -441,6 +443,9 @@ __create_context(struct drm_i915_private *i915)
441443
for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
442444
ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
443445

446+
ctx->jump_whitelist = NULL;
447+
ctx->jump_whitelist_cmds = 0;
448+
444449
return ctx;
445450

446451
err_free:

drivers/gpu/drm/i915/gem/i915_gem_context_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ struct i915_gem_context {
192192
* per vm, which may be one per context or shared with the global GTT)
193193
*/
194194
struct radix_tree_root handles_vma;
195+
196+
/** jump_whitelist: Bit array for tracking cmds during cmdparsing
197+
* Guarded by struct_mutex
198+
*/
199+
unsigned long *jump_whitelist;
200+
/** jump_whitelist_cmds: No of cmd slots available */
201+
u32 jump_whitelist_cmds;
195202
};
196203

197204
#endif /* __I915_GEM_CONTEXT_TYPES_H__ */

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

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ static inline u64 gen8_noncanonical_addr(u64 address)
296296

297297
static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
298298
{
299-
return intel_engine_needs_cmd_parser(eb->engine) && eb->batch_len;
299+
return intel_engine_requires_cmd_parser(eb->engine) ||
300+
(intel_engine_using_cmd_parser(eb->engine) &&
301+
eb->args->batch_len);
300302
}
301303

302304
static int eb_create(struct i915_execbuffer *eb)
@@ -1955,40 +1957,94 @@ static int i915_reset_gen7_sol_offsets(struct i915_request *rq)
19551957
return 0;
19561958
}
19571959

1958-
static struct i915_vma *eb_parse(struct i915_execbuffer *eb, bool is_master)
1960+
static struct i915_vma *
1961+
shadow_batch_pin(struct i915_execbuffer *eb, struct drm_i915_gem_object *obj)
1962+
{
1963+
struct drm_i915_private *dev_priv = eb->i915;
1964+
struct i915_vma * const vma = *eb->vma;
1965+
struct i915_address_space *vm;
1966+
u64 flags;
1967+
1968+
/*
1969+
* PPGTT backed shadow buffers must be mapped RO, to prevent
1970+
* post-scan tampering
1971+
*/
1972+
if (CMDPARSER_USES_GGTT(dev_priv)) {
1973+
flags = PIN_GLOBAL;
1974+
vm = &dev_priv->ggtt.vm;
1975+
} else if (vma->vm->has_read_only) {
1976+
flags = PIN_USER;
1977+
vm = vma->vm;
1978+
i915_gem_object_set_readonly(obj);
1979+
} else {
1980+
DRM_DEBUG("Cannot prevent post-scan tampering without RO capable vm\n");
1981+
return ERR_PTR(-EINVAL);
1982+
}
1983+
1984+
return i915_gem_object_pin(obj, vm, NULL, 0, 0, flags);
1985+
}
1986+
1987+
static struct i915_vma *eb_parse(struct i915_execbuffer *eb)
19591988
{
19601989
struct intel_engine_pool_node *pool;
19611990
struct i915_vma *vma;
1991+
u64 batch_start;
1992+
u64 shadow_batch_start;
19621993
int err;
19631994

19641995
pool = intel_engine_pool_get(&eb->engine->pool, eb->batch_len);
19651996
if (IS_ERR(pool))
19661997
return ERR_CAST(pool);
19671998

1968-
err = intel_engine_cmd_parser(eb->engine,
1999+
vma = shadow_batch_pin(eb, pool->obj);
2000+
if (IS_ERR(vma))
2001+
goto err;
2002+
2003+
batch_start = gen8_canonical_addr(eb->batch->node.start) +
2004+
eb->batch_start_offset;
2005+
2006+
shadow_batch_start = gen8_canonical_addr(vma->node.start);
2007+
2008+
err = intel_engine_cmd_parser(eb->gem_context,
2009+
eb->engine,
19692010
eb->batch->obj,
1970-
pool->obj,
2011+
batch_start,
19712012
eb->batch_start_offset,
19722013
eb->batch_len,
1973-
is_master);
2014+
pool->obj,
2015+
shadow_batch_start);
2016+
19742017
if (err) {
1975-
if (err == -EACCES) /* unhandled chained batch */
2018+
i915_vma_unpin(vma);
2019+
2020+
/*
2021+
* Unsafe GGTT-backed buffers can still be submitted safely
2022+
* as non-secure.
2023+
* For PPGTT backing however, we have no choice but to forcibly
2024+
* reject unsafe buffers
2025+
*/
2026+
if (CMDPARSER_USES_GGTT(eb->i915) && (err == -EACCES))
2027+
/* Execute original buffer non-secure */
19762028
vma = NULL;
19772029
else
19782030
vma = ERR_PTR(err);
19792031
goto err;
19802032
}
19812033

1982-
vma = i915_gem_object_ggtt_pin(pool->obj, NULL, 0, 0, 0);
1983-
if (IS_ERR(vma))
1984-
goto err;
1985-
19862034
eb->vma[eb->buffer_count] = i915_vma_get(vma);
19872035
eb->flags[eb->buffer_count] =
19882036
__EXEC_OBJECT_HAS_PIN | __EXEC_OBJECT_HAS_REF;
19892037
vma->exec_flags = &eb->flags[eb->buffer_count];
19902038
eb->buffer_count++;
19912039

2040+
eb->batch_start_offset = 0;
2041+
eb->batch = vma;
2042+
2043+
if (CMDPARSER_USES_GGTT(eb->i915))
2044+
eb->batch_flags |= I915_DISPATCH_SECURE;
2045+
2046+
/* eb->batch_len unchanged */
2047+
19922048
vma->private = pool;
19932049
return vma;
19942050

@@ -2421,6 +2477,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
24212477
struct drm_i915_gem_exec_object2 *exec,
24222478
struct drm_syncobj **fences)
24232479
{
2480+
struct drm_i915_private *i915 = to_i915(dev);
24242481
struct i915_execbuffer eb;
24252482
struct dma_fence *in_fence = NULL;
24262483
struct dma_fence *exec_fence = NULL;
@@ -2432,7 +2489,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
24322489
BUILD_BUG_ON(__EXEC_OBJECT_INTERNAL_FLAGS &
24332490
~__EXEC_OBJECT_UNKNOWN_FLAGS);
24342491

2435-
eb.i915 = to_i915(dev);
2492+
eb.i915 = i915;
24362493
eb.file = file;
24372494
eb.args = args;
24382495
if (DBG_FORCE_RELOC || !(args->flags & I915_EXEC_NO_RELOC))
@@ -2452,8 +2509,15 @@ i915_gem_do_execbuffer(struct drm_device *dev,
24522509

24532510
eb.batch_flags = 0;
24542511
if (args->flags & I915_EXEC_SECURE) {
2512+
if (INTEL_GEN(i915) >= 11)
2513+
return -ENODEV;
2514+
2515+
/* Return -EPERM to trigger fallback code on old binaries. */
2516+
if (!HAS_SECURE_BATCHES(i915))
2517+
return -EPERM;
2518+
24552519
if (!drm_is_current_master(file) || !capable(CAP_SYS_ADMIN))
2456-
return -EPERM;
2520+
return -EPERM;
24572521

24582522
eb.batch_flags |= I915_DISPATCH_SECURE;
24592523
}
@@ -2530,34 +2594,19 @@ i915_gem_do_execbuffer(struct drm_device *dev,
25302594
goto err_vma;
25312595
}
25322596

2597+
if (eb.batch_len == 0)
2598+
eb.batch_len = eb.batch->size - eb.batch_start_offset;
2599+
25332600
if (eb_use_cmdparser(&eb)) {
25342601
struct i915_vma *vma;
25352602

2536-
vma = eb_parse(&eb, drm_is_current_master(file));
2603+
vma = eb_parse(&eb);
25372604
if (IS_ERR(vma)) {
25382605
err = PTR_ERR(vma);
25392606
goto err_vma;
25402607
}
2541-
2542-
if (vma) {
2543-
/*
2544-
* Batch parsed and accepted:
2545-
*
2546-
* Set the DISPATCH_SECURE bit to remove the NON_SECURE
2547-
* bit from MI_BATCH_BUFFER_START commands issued in
2548-
* the dispatch_execbuffer implementations. We
2549-
* specifically don't want that set on batches the
2550-
* command parser has accepted.
2551-
*/
2552-
eb.batch_flags |= I915_DISPATCH_SECURE;
2553-
eb.batch_start_offset = 0;
2554-
eb.batch = vma;
2555-
}
25562608
}
25572609

2558-
if (eb.batch_len == 0)
2559-
eb.batch_len = eb.batch->size - eb.batch_start_offset;
2560-
25612610
/*
25622611
* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
25632612
* batch" bit. Hence we need to pin secure batches into the global gtt.

drivers/gpu/drm/i915/gt/intel_engine_types.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,12 +475,13 @@ struct intel_engine_cs {
475475

476476
struct intel_engine_hangcheck hangcheck;
477477

478-
#define I915_ENGINE_NEEDS_CMD_PARSER BIT(0)
478+
#define I915_ENGINE_USING_CMD_PARSER BIT(0)
479479
#define I915_ENGINE_SUPPORTS_STATS BIT(1)
480480
#define I915_ENGINE_HAS_PREEMPTION BIT(2)
481481
#define I915_ENGINE_HAS_SEMAPHORES BIT(3)
482482
#define I915_ENGINE_NEEDS_BREADCRUMB_TASKLET BIT(4)
483483
#define I915_ENGINE_IS_VIRTUAL BIT(5)
484+
#define I915_ENGINE_REQUIRES_CMD_PARSER BIT(7)
484485
unsigned int flags;
485486

486487
/*
@@ -541,9 +542,15 @@ struct intel_engine_cs {
541542
};
542543

543544
static inline bool
544-
intel_engine_needs_cmd_parser(const struct intel_engine_cs *engine)
545+
intel_engine_using_cmd_parser(const struct intel_engine_cs *engine)
545546
{
546-
return engine->flags & I915_ENGINE_NEEDS_CMD_PARSER;
547+
return engine->flags & I915_ENGINE_USING_CMD_PARSER;
548+
}
549+
550+
static inline bool
551+
intel_engine_requires_cmd_parser(const struct intel_engine_cs *engine)
552+
{
553+
return engine->flags & I915_ENGINE_REQUIRES_CMD_PARSER;
547554
}
548555

549556
static inline bool

drivers/gpu/drm/i915/gt/intel_gt_pm.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ static int __gt_unpark(struct intel_wakeref *wf)
3838
gt->awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
3939
GEM_BUG_ON(!gt->awake);
4040

41+
if (NEEDS_RC6_CTX_CORRUPTION_WA(i915))
42+
intel_uncore_forcewake_get(&i915->uncore, FORCEWAKE_ALL);
43+
4144
intel_enable_gt_powersave(i915);
4245

4346
i915_update_gfx_val(i915);
@@ -67,6 +70,11 @@ static int __gt_park(struct intel_wakeref *wf)
6770
if (INTEL_GEN(i915) >= 6)
6871
gen6_rps_idle(i915);
6972

73+
if (NEEDS_RC6_CTX_CORRUPTION_WA(i915)) {
74+
i915_rc6_ctx_wa_check(i915);
75+
intel_uncore_forcewake_put(&i915->uncore, FORCEWAKE_ALL);
76+
}
77+
7078
/* Everything switched off, flush any residual interrupt just in case */
7179
intel_synchronize_irq(i915);
7280

0 commit comments

Comments
 (0)