Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6ba2df1 authored by Jon Bloomfield's avatar Jon Bloomfield Committed by Greg Kroah-Hartman
Browse files

drm/i915: Add gen9 BCS cmdparsing



commit 0f2f39758341df70202ae1c42d5a1e4ee392b6d3 upstream.

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: default avatarJon 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: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: default avatarChris Wilson <chris.p.wilson@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 05e5cf18
Loading
Loading
Loading
Loading
+106 −10
Original line number Diff line number Diff line
@@ -442,6 +442,47 @@ static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = {
	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 =
	CMD(MI_NOOP, SMI, F, 1, S);

@@ -488,6 +529,11 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmd_table[] = {
	{ 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.
 */
@@ -603,6 +649,29 @@ static const struct drm_i915_reg_descriptor gen7_blt_regs[] = {
	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 REG32

@@ -628,6 +697,10 @@ static const struct drm_i915_reg_table hsw_blt_reg_tables[] = {
	{ 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)
{
	u32 client = cmd_header >> INSTR_CLIENT_SHIFT;
@@ -683,6 +756,17 @@ static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
	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,
				 const struct drm_i915_cmd_table *cmd_tables,
				 int cmd_table_count)
@@ -840,7 +924,8 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
	int cmd_table_count;
	int ret;

	if (!IS_GEN7(engine->i915))
	if (!IS_GEN7(engine->i915) && !(IS_GEN9(engine->i915) &&
					engine->id == BCS))
		return;

	switch (engine->id) {
@@ -861,7 +946,6 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
			engine->reg_tables = 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;
		break;
	case VCS:
@@ -870,7 +954,16 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
		engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
		break;
	case BCS:
		if (IS_HASWELL(engine->i915)) {
		engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
		if (IS_GEN9(engine->i915)) {
			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_table_count = ARRAY_SIZE(hsw_blt_ring_cmd_table);
		} else {
@@ -878,15 +971,17 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
			cmd_table_count = ARRAY_SIZE(gen7_blt_cmd_table);
		}

		if (IS_HASWELL(engine->i915)) {
		if (IS_GEN9(engine->i915)) {
			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_table_count = ARRAY_SIZE(hsw_blt_reg_tables);
		} else {
			engine->reg_tables = 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;
	case VECS:
		cmd_tables = hsw_vebox_cmd_table;
@@ -1260,9 +1355,9 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
		}

		/*
		 * If the batch buffer contains a chained batch, return an
		 * error that tells the caller to abort and dispatch the
		 * workload as a non-secure batch.
		 * We don't try to handle BATCH_BUFFER_START because it adds
		 * non-trivial complexity. Instead we abort the scan and return
		 * and error to indicate that the batch is unsafe.
		 */
		if (desc->cmd.value == MI_BATCH_BUFFER_START) {
			ret = -EACCES;
@@ -1341,6 +1436,7 @@ int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv)
	 *    the parser enabled.
	 * 9. Don't whitelist or handle oacontrol specially, as ownership
	 *    for oacontrol state is moving to i915-perf.
	 * 10. Support for Gen9 BCS Parsing
	 */
	return 9;
	return 10;
}
+2 −1
Original line number Diff line number Diff line
@@ -140,7 +140,8 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
	if (enable_ppgtt == 0 && INTEL_GEN(dev_priv) < 9)
		return 0;

	if (enable_ppgtt == 1)
	/* Full PPGTT is required by the Gen9 cmdparser */
	if (enable_ppgtt == 1 && INTEL_GEN(dev_priv) != 9)
		return 1;

	if (enable_ppgtt == 2 && has_full_ppgtt)
+4 −0
Original line number Diff line number Diff line
@@ -568,6 +568,10 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 */
#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_UDW	_MMIO(0x2290 + 4)
#define HS_INVOCATION_COUNT             _MMIO(0x2300)