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 <jon.bloomfield@intel.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Dave Airlie <airlied@redhat.com> Cc: Takashi Iwai <tiwai@suse.de> Cc: Tyler Hicks <tyhicks@canonical.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
This commit is contained in:
parent
435e8fc059
commit
0f2f397583
2 changed files with 110 additions and 10 deletions
|
@ -444,6 +444,47 @@ static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = {
|
||||||
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
|
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For Gen9 we can still rely on the h/w to enforce cmd security, and only
|
||||||
|
* need to re-enforce the register access checks. We therefore only need to
|
||||||
|
* teach the cmdparser how to find the end of each command, and identify
|
||||||
|
* register accesses. The table doesn't need to reject any commands, and so
|
||||||
|
* the only commands listed here are:
|
||||||
|
* 1) Those that touch registers
|
||||||
|
* 2) Those that do not have the default 8-bit length
|
||||||
|
*
|
||||||
|
* Note that the default MI length mask chosen for this table is 0xFF, not
|
||||||
|
* the 0x3F used on older devices. This is because the vast majority of MI
|
||||||
|
* cmds on Gen9 use a standard 8-bit Length field.
|
||||||
|
* All the Gen9 blitter instructions are standard 0xFF length mask, and
|
||||||
|
* none allow access to non-general registers, so in fact no BLT cmds are
|
||||||
|
* included in the table at all.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static const struct drm_i915_cmd_descriptor gen9_blt_cmds[] = {
|
||||||
|
CMD( MI_NOOP, SMI, F, 1, S ),
|
||||||
|
CMD( MI_USER_INTERRUPT, SMI, F, 1, S ),
|
||||||
|
CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, S ),
|
||||||
|
CMD( MI_FLUSH, SMI, F, 1, S ),
|
||||||
|
CMD( MI_ARB_CHECK, SMI, F, 1, S ),
|
||||||
|
CMD( MI_REPORT_HEAD, SMI, F, 1, S ),
|
||||||
|
CMD( MI_ARB_ON_OFF, SMI, F, 1, S ),
|
||||||
|
CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ),
|
||||||
|
CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, S ),
|
||||||
|
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, S ),
|
||||||
|
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, S ),
|
||||||
|
CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W,
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ),
|
||||||
|
CMD( MI_UPDATE_GTT, SMI, !F, 0x3FF, S ),
|
||||||
|
CMD( MI_STORE_REGISTER_MEM_GEN8, SMI, F, 4, W,
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC } ),
|
||||||
|
CMD( MI_FLUSH_DW, SMI, !F, 0x3F, S ),
|
||||||
|
CMD( MI_LOAD_REGISTER_MEM_GEN8, SMI, F, 4, W,
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC } ),
|
||||||
|
CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, W,
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 1 } ),
|
||||||
|
};
|
||||||
|
|
||||||
static const struct drm_i915_cmd_descriptor noop_desc =
|
static const struct drm_i915_cmd_descriptor noop_desc =
|
||||||
CMD(MI_NOOP, SMI, F, 1, S);
|
CMD(MI_NOOP, SMI, F, 1, S);
|
||||||
|
|
||||||
|
@ -490,6 +531,11 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmd_table[] = {
|
||||||
{ hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) },
|
{ hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_cmd_table gen9_blt_cmd_table[] = {
|
||||||
|
{ gen9_blt_cmds, ARRAY_SIZE(gen9_blt_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register whitelists, sorted by increasing register offset.
|
* Register whitelists, sorted by increasing register offset.
|
||||||
*/
|
*/
|
||||||
|
@ -605,6 +651,29 @@ static const struct drm_i915_reg_descriptor gen7_blt_regs[] = {
|
||||||
REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
|
REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_descriptor gen9_blt_regs[] = {
|
||||||
|
REG64_IDX(RING_TIMESTAMP, RENDER_RING_BASE),
|
||||||
|
REG64_IDX(RING_TIMESTAMP, BSD_RING_BASE),
|
||||||
|
REG32(BCS_SWCTRL),
|
||||||
|
REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
|
||||||
|
REG64_IDX(BCS_GPR, 0),
|
||||||
|
REG64_IDX(BCS_GPR, 1),
|
||||||
|
REG64_IDX(BCS_GPR, 2),
|
||||||
|
REG64_IDX(BCS_GPR, 3),
|
||||||
|
REG64_IDX(BCS_GPR, 4),
|
||||||
|
REG64_IDX(BCS_GPR, 5),
|
||||||
|
REG64_IDX(BCS_GPR, 6),
|
||||||
|
REG64_IDX(BCS_GPR, 7),
|
||||||
|
REG64_IDX(BCS_GPR, 8),
|
||||||
|
REG64_IDX(BCS_GPR, 9),
|
||||||
|
REG64_IDX(BCS_GPR, 10),
|
||||||
|
REG64_IDX(BCS_GPR, 11),
|
||||||
|
REG64_IDX(BCS_GPR, 12),
|
||||||
|
REG64_IDX(BCS_GPR, 13),
|
||||||
|
REG64_IDX(BCS_GPR, 14),
|
||||||
|
REG64_IDX(BCS_GPR, 15),
|
||||||
|
};
|
||||||
|
|
||||||
#undef REG64
|
#undef REG64
|
||||||
#undef REG32
|
#undef REG32
|
||||||
|
|
||||||
|
@ -630,6 +699,10 @@ static const struct drm_i915_reg_table hsw_blt_reg_tables[] = {
|
||||||
{ gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs) },
|
{ gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_table gen9_blt_reg_tables[] = {
|
||||||
|
{ gen9_blt_regs, ARRAY_SIZE(gen9_blt_regs) },
|
||||||
|
};
|
||||||
|
|
||||||
static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
|
static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
|
||||||
{
|
{
|
||||||
u32 client = cmd_header >> INSTR_CLIENT_SHIFT;
|
u32 client = cmd_header >> INSTR_CLIENT_SHIFT;
|
||||||
|
@ -685,6 +758,17 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 gen9_blt_get_cmd_length_mask(u32 cmd_header)
|
||||||
|
{
|
||||||
|
u32 client = cmd_header >> INSTR_CLIENT_SHIFT;
|
||||||
|
|
||||||
|
if (client == INSTR_MI_CLIENT || client == INSTR_BC_CLIENT)
|
||||||
|
return 0xFF;
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool validate_cmds_sorted(const struct intel_engine_cs *engine,
|
static bool validate_cmds_sorted(const struct intel_engine_cs *engine,
|
||||||
const struct drm_i915_cmd_table *cmd_tables,
|
const struct drm_i915_cmd_table *cmd_tables,
|
||||||
int cmd_table_count)
|
int cmd_table_count)
|
||||||
|
@ -842,7 +926,8 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
|
||||||
int cmd_table_count;
|
int cmd_table_count;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!IS_GEN(engine->i915, 7))
|
if (!IS_GEN(engine->i915, 7) && !(IS_GEN(engine->i915, 9) &&
|
||||||
|
engine->class == COPY_ENGINE_CLASS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (engine->class) {
|
switch (engine->class) {
|
||||||
|
@ -863,7 +948,6 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
|
||||||
engine->reg_tables = ivb_render_reg_tables;
|
engine->reg_tables = ivb_render_reg_tables;
|
||||||
engine->reg_table_count = ARRAY_SIZE(ivb_render_reg_tables);
|
engine->reg_table_count = ARRAY_SIZE(ivb_render_reg_tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
|
engine->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
|
||||||
break;
|
break;
|
||||||
case VIDEO_DECODE_CLASS:
|
case VIDEO_DECODE_CLASS:
|
||||||
|
@ -872,7 +956,16 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
|
||||||
engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
|
engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
|
||||||
break;
|
break;
|
||||||
case COPY_ENGINE_CLASS:
|
case COPY_ENGINE_CLASS:
|
||||||
if (IS_HASWELL(engine->i915)) {
|
engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
|
||||||
|
if (IS_GEN(engine->i915, 9)) {
|
||||||
|
cmd_tables = gen9_blt_cmd_table;
|
||||||
|
cmd_table_count = ARRAY_SIZE(gen9_blt_cmd_table);
|
||||||
|
engine->get_cmd_length_mask =
|
||||||
|
gen9_blt_get_cmd_length_mask;
|
||||||
|
|
||||||
|
/* BCS Engine unsafe without parser */
|
||||||
|
engine->flags |= I915_ENGINE_REQUIRES_CMD_PARSER;
|
||||||
|
} else if (IS_HASWELL(engine->i915)) {
|
||||||
cmd_tables = hsw_blt_ring_cmd_table;
|
cmd_tables = hsw_blt_ring_cmd_table;
|
||||||
cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmd_table);
|
cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmd_table);
|
||||||
} else {
|
} else {
|
||||||
|
@ -880,15 +973,17 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
|
||||||
cmd_table_count = ARRAY_SIZE(gen7_blt_cmd_table);
|
cmd_table_count = ARRAY_SIZE(gen7_blt_cmd_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_HASWELL(engine->i915)) {
|
if (IS_GEN(engine->i915, 9)) {
|
||||||
|
engine->reg_tables = gen9_blt_reg_tables;
|
||||||
|
engine->reg_table_count =
|
||||||
|
ARRAY_SIZE(gen9_blt_reg_tables);
|
||||||
|
} else if (IS_HASWELL(engine->i915)) {
|
||||||
engine->reg_tables = hsw_blt_reg_tables;
|
engine->reg_tables = hsw_blt_reg_tables;
|
||||||
engine->reg_table_count = ARRAY_SIZE(hsw_blt_reg_tables);
|
engine->reg_table_count = ARRAY_SIZE(hsw_blt_reg_tables);
|
||||||
} else {
|
} else {
|
||||||
engine->reg_tables = ivb_blt_reg_tables;
|
engine->reg_tables = ivb_blt_reg_tables;
|
||||||
engine->reg_table_count = ARRAY_SIZE(ivb_blt_reg_tables);
|
engine->reg_table_count = ARRAY_SIZE(ivb_blt_reg_tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
|
|
||||||
break;
|
break;
|
||||||
case VIDEO_ENHANCEMENT_CLASS:
|
case VIDEO_ENHANCEMENT_CLASS:
|
||||||
cmd_tables = hsw_vebox_cmd_table;
|
cmd_tables = hsw_vebox_cmd_table;
|
||||||
|
@ -1261,9 +1356,9 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the batch buffer contains a chained batch, return an
|
* We don't try to handle BATCH_BUFFER_START because it adds
|
||||||
* error that tells the caller to abort and dispatch the
|
* non-trivial complexity. Instead we abort the scan and return
|
||||||
* workload as a non-secure batch.
|
* and error to indicate that the batch is unsafe.
|
||||||
*/
|
*/
|
||||||
if (desc->cmd.value == MI_BATCH_BUFFER_START) {
|
if (desc->cmd.value == MI_BATCH_BUFFER_START) {
|
||||||
ret = -EACCES;
|
ret = -EACCES;
|
||||||
|
@ -1342,6 +1437,7 @@ int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)
|
||||||
* the parser enabled.
|
* the parser enabled.
|
||||||
* 9. Don't whitelist or handle oacontrol specially, as ownership
|
* 9. Don't whitelist or handle oacontrol specially, as ownership
|
||||||
* for oacontrol state is moving to i915-perf.
|
* for oacontrol state is moving to i915-perf.
|
||||||
|
* 10. Support for Gen9 BCS Parsing
|
||||||
*/
|
*/
|
||||||
return 9;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,6 +555,10 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
||||||
*/
|
*/
|
||||||
#define BCS_SWCTRL _MMIO(0x22200)
|
#define BCS_SWCTRL _MMIO(0x22200)
|
||||||
|
|
||||||
|
/* There are 16 GPR registers */
|
||||||
|
#define BCS_GPR(n) _MMIO(0x22600 + (n) * 8)
|
||||||
|
#define BCS_GPR_UDW(n) _MMIO(0x22600 + (n) * 8 + 4)
|
||||||
|
|
||||||
#define GPGPU_THREADS_DISPATCHED _MMIO(0x2290)
|
#define GPGPU_THREADS_DISPATCHED _MMIO(0x2290)
|
||||||
#define GPGPU_THREADS_DISPATCHED_UDW _MMIO(0x2290 + 4)
|
#define GPGPU_THREADS_DISPATCHED_UDW _MMIO(0x2290 + 4)
|
||||||
#define HS_INVOCATION_COUNT _MMIO(0x2300)
|
#define HS_INVOCATION_COUNT _MMIO(0x2300)
|
||||||
|
|
Loading…
Add table
Reference in a new issue