Skip to content

Commit 0f2f397

Browse files
drm/i915: Add gen9 BCS cmdparsing
For gen9 we enable cmdparsing on the BCS ring, specifically to catch inadvertent accesses to sensitive registers Unlike gen7/hsw, we use the parser only to block certain registers. We can rely on h/w to block restricted commands, so the command tables only provide enough info to allow the parser to delineate each command, and identify commands that access registers. Note: This patch deliberately ignores checkpatch issues in favour of matching the style of the surrounding code. We'll correct the entire file in one go in a later patch. v3: rebase (Mika) v4: Add RING_TIMESTAMP registers to whitelist (Jon) Signed-off-by: Jon Bloomfield <[email protected]> Cc: Tony Luck <[email protected]> Cc: Dave Airlie <[email protected]> Cc: Takashi Iwai <[email protected]> Cc: Tyler Hicks <[email protected]> Signed-off-by: Mika Kuoppala <[email protected]> Reviewed-by: Chris Wilson <[email protected]>
1 parent 435e8fc commit 0f2f397

File tree

2 files changed

+110
-10
lines changed

2 files changed

+110
-10
lines changed

drivers/gpu/drm/i915/i915_cmd_parser.c

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,47 @@ static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = {
444444
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
445445
};
446446

447+
/*
448+
* For Gen9 we can still rely on the h/w to enforce cmd security, and only
449+
* need to re-enforce the register access checks. We therefore only need to
450+
* teach the cmdparser how to find the end of each command, and identify
451+
* register accesses. The table doesn't need to reject any commands, and so
452+
* the only commands listed here are:
453+
* 1) Those that touch registers
454+
* 2) Those that do not have the default 8-bit length
455+
*
456+
* Note that the default MI length mask chosen for this table is 0xFF, not
457+
* the 0x3F used on older devices. This is because the vast majority of MI
458+
* cmds on Gen9 use a standard 8-bit Length field.
459+
* All the Gen9 blitter instructions are standard 0xFF length mask, and
460+
* none allow access to non-general registers, so in fact no BLT cmds are
461+
* included in the table at all.
462+
*
463+
*/
464+
static const struct drm_i915_cmd_descriptor gen9_blt_cmds[] = {
465+
CMD( MI_NOOP, SMI, F, 1, S ),
466+
CMD( MI_USER_INTERRUPT, SMI, F, 1, S ),
467+
CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, S ),
468+
CMD( MI_FLUSH, SMI, F, 1, S ),
469+
CMD( MI_ARB_CHECK, SMI, F, 1, S ),
470+
CMD( MI_REPORT_HEAD, SMI, F, 1, S ),
471+
CMD( MI_ARB_ON_OFF, SMI, F, 1, S ),
472+
CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ),
473+
CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, S ),
474+
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, S ),
475+
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ),
476+
CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W,
477+
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ),
478+
CMD( MI_UPDATE_GTT, SMI, !F, 0x3FF, S ),
479+
CMD( MI_STORE_REGISTER_MEM_GEN8, SMI, F, 4, W,
480+
.reg = { .offset = 1, .mask = 0x007FFFFC } ),
481+
CMD( MI_FLUSH_DW, SMI, !F, 0x3F, S ),
482+
CMD( MI_LOAD_REGISTER_MEM_GEN8, SMI, F, 4, W,
483+
.reg = { .offset = 1, .mask = 0x007FFFFC } ),
484+
CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, W,
485+
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 1 } ),
486+
};
487+
447488
static const struct drm_i915_cmd_descriptor noop_desc =
448489
CMD(MI_NOOP, SMI, F, 1, S);
449490

@@ -490,6 +531,11 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmd_table[] = {
490531
{ hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) },
491532
};
492533

534+
static const struct drm_i915_cmd_table gen9_blt_cmd_table[] = {
535+
{ gen9_blt_cmds, ARRAY_SIZE(gen9_blt_cmds) },
536+
};
537+
538+
493539
/*
494540
* Register whitelists, sorted by increasing register offset.
495541
*/
@@ -605,6 +651,29 @@ static const struct drm_i915_reg_descriptor gen7_blt_regs[] = {
605651
REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
606652
};
607653

654+
static const struct drm_i915_reg_descriptor gen9_blt_regs[] = {
655+
REG64_IDX(RING_TIMESTAMP, RENDER_RING_BASE),
656+
REG64_IDX(RING_TIMESTAMP, BSD_RING_BASE),
657+
REG32(BCS_SWCTRL),
658+
REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
659+
REG64_IDX(BCS_GPR, 0),
660+
REG64_IDX(BCS_GPR, 1),
661+
REG64_IDX(BCS_GPR, 2),
662+
REG64_IDX(BCS_GPR, 3),
663+
REG64_IDX(BCS_GPR, 4),
664+
REG64_IDX(BCS_GPR, 5),
665+
REG64_IDX(BCS_GPR, 6),
666+
REG64_IDX(BCS_GPR, 7),
667+
REG64_IDX(BCS_GPR, 8),
668+
REG64_IDX(BCS_GPR, 9),
669+
REG64_IDX(BCS_GPR, 10),
670+
REG64_IDX(BCS_GPR, 11),
671+
REG64_IDX(BCS_GPR, 12),
672+
REG64_IDX(BCS_GPR, 13),
673+
REG64_IDX(BCS_GPR, 14),
674+
REG64_IDX(BCS_GPR, 15),
675+
};
676+
608677
#undef REG64
609678
#undef REG32
610679

@@ -630,6 +699,10 @@ static const struct drm_i915_reg_table hsw_blt_reg_tables[] = {
630699
{ gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs) },
631700
};
632701

702+
static const struct drm_i915_reg_table gen9_blt_reg_tables[] = {
703+
{ gen9_blt_regs, ARRAY_SIZE(gen9_blt_regs) },
704+
};
705+
633706
static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
634707
{
635708
u32 client = cmd_header >> INSTR_CLIENT_SHIFT;
@@ -685,6 +758,17 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
685758
return 0;
686759
}
687760

761+
static u32 gen9_blt_get_cmd_length_mask(u32 cmd_header)
762+
{
763+
u32 client = cmd_header >> INSTR_CLIENT_SHIFT;
764+
765+
if (client == INSTR_MI_CLIENT || client == INSTR_BC_CLIENT)
766+
return 0xFF;
767+
768+
DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header);
769+
return 0;
770+
}
771+
688772
static bool validate_cmds_sorted(const struct intel_engine_cs *engine,
689773
const struct drm_i915_cmd_table *cmd_tables,
690774
int cmd_table_count)
@@ -842,7 +926,8 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
842926
int cmd_table_count;
843927
int ret;
844928

845-
if (!IS_GEN(engine->i915, 7))
929+
if (!IS_GEN(engine->i915, 7) && !(IS_GEN(engine->i915, 9) &&
930+
engine->class == COPY_ENGINE_CLASS))
846931
return;
847932

848933
switch (engine->class) {
@@ -863,7 +948,6 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
863948
engine->reg_tables = ivb_render_reg_tables;
864949
engine->reg_table_count = ARRAY_SIZE(ivb_render_reg_tables);
865950
}
866-
867951
engine->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
868952
break;
869953
case VIDEO_DECODE_CLASS:
@@ -872,23 +956,34 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
872956
engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
873957
break;
874958
case COPY_ENGINE_CLASS:
875-
if (IS_HASWELL(engine->i915)) {
959+
engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
960+
if (IS_GEN(engine->i915, 9)) {
961+
cmd_tables = gen9_blt_cmd_table;
962+
cmd_table_count = ARRAY_SIZE(gen9_blt_cmd_table);
963+
engine->get_cmd_length_mask =
964+
gen9_blt_get_cmd_length_mask;
965+
966+
/* BCS Engine unsafe without parser */
967+
engine->flags |= I915_ENGINE_REQUIRES_CMD_PARSER;
968+
} else if (IS_HASWELL(engine->i915)) {
876969
cmd_tables = hsw_blt_ring_cmd_table;
877970
cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmd_table);
878971
} else {
879972
cmd_tables = gen7_blt_cmd_table;
880973
cmd_table_count = ARRAY_SIZE(gen7_blt_cmd_table);
881974
}
882975

883-
if (IS_HASWELL(engine->i915)) {
976+
if (IS_GEN(engine->i915, 9)) {
977+
engine->reg_tables = gen9_blt_reg_tables;
978+
engine->reg_table_count =
979+
ARRAY_SIZE(gen9_blt_reg_tables);
980+
} else if (IS_HASWELL(engine->i915)) {
884981
engine->reg_tables = hsw_blt_reg_tables;
885982
engine->reg_table_count = ARRAY_SIZE(hsw_blt_reg_tables);
886983
} else {
887984
engine->reg_tables = ivb_blt_reg_tables;
888985
engine->reg_table_count = ARRAY_SIZE(ivb_blt_reg_tables);
889986
}
890-
891-
engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
892987
break;
893988
case VIDEO_ENHANCEMENT_CLASS:
894989
cmd_tables = hsw_vebox_cmd_table;
@@ -1261,9 +1356,9 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
12611356
}
12621357

12631358
/*
1264-
* If the batch buffer contains a chained batch, return an
1265-
* error that tells the caller to abort and dispatch the
1266-
* workload as a non-secure batch.
1359+
* We don't try to handle BATCH_BUFFER_START because it adds
1360+
* non-trivial complexity. Instead we abort the scan and return
1361+
* and error to indicate that the batch is unsafe.
12671362
*/
12681363
if (desc->cmd.value == MI_BATCH_BUFFER_START) {
12691364
ret = -EACCES;
@@ -1342,6 +1437,7 @@ int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)
13421437
* the parser enabled.
13431438
* 9. Don't whitelist or handle oacontrol specially, as ownership
13441439
* for oacontrol state is moving to i915-perf.
1440+
* 10. Support for Gen9 BCS Parsing
13451441
*/
1346-
return 9;
1442+
return 10;
13471443
}

drivers/gpu/drm/i915/i915_reg.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,10 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
555555
*/
556556
#define BCS_SWCTRL _MMIO(0x22200)
557557

558+
/* There are 16 GPR registers */
559+
#define BCS_GPR(n) _MMIO(0x22600 + (n) * 8)
560+
#define BCS_GPR_UDW(n) _MMIO(0x22600 + (n) * 8 + 4)
561+
558562
#define GPGPU_THREADS_DISPATCHED _MMIO(0x2290)
559563
#define GPGPU_THREADS_DISPATCHED_UDW _MMIO(0x2290 + 4)
560564
#define HS_INVOCATION_COUNT _MMIO(0x2300)

0 commit comments

Comments
 (0)