[x86] i915: Add mitigations for two hardware security flaws
This commit is contained in:
parent
c2443a2e97
commit
feec1caa94
|
@ -32,6 +32,20 @@ linux (4.19.67-2+deb10u2) UNRELEASED; urgency=medium
|
||||||
- kvm: Add helper function for creating VM worker threads
|
- kvm: Add helper function for creating VM worker threads
|
||||||
- kvm: x86: mmu: Recovery of shattered NX large pages
|
- kvm: x86: mmu: Recovery of shattered NX large pages
|
||||||
- Documentation: Add ITLB_MULTIHIT documentation
|
- Documentation: Add ITLB_MULTIHIT documentation
|
||||||
|
* [x86] i915: Mitigate local privilege escalation on gen9 (CVE-2019-0155):
|
||||||
|
- drm/i915: Rename gen7 cmdparser tables
|
||||||
|
- drm/i915: Disable Secure Batches for gen6+
|
||||||
|
- drm/i915: Remove Master tables from cmdparser
|
||||||
|
- drm/i915: Add support for mandatory cmdparsing
|
||||||
|
- drm/i915: Support ro ppgtt mapped cmdparser shadow buffers
|
||||||
|
- drm/i915: Allow parsing of unsized batches
|
||||||
|
- drm/i915: Add gen9 BCS cmdparsing
|
||||||
|
- drm/i915/cmdparser: Use explicit goto for error paths
|
||||||
|
- drm/i915/cmdparser: Add support for backward jumps
|
||||||
|
- drm/i915/cmdparser: Ignore Length operands during command matching
|
||||||
|
* [x86] i915: Mitigate local denial-of-service on gen8/gen9 (CVE-2019-0154):
|
||||||
|
- drm/i915: Lower RM timeout to avoid DSI hard hangs
|
||||||
|
- drm/i915/gen8+: Add RC6 CTX corruption WA
|
||||||
|
|
||||||
-- Ben Hutchings <ben@decadent.org.uk> Sun, 20 Oct 2019 14:21:28 +0100
|
-- Ben Hutchings <ben@decadent.org.uk> Sun, 20 Oct 2019 14:21:28 +0100
|
||||||
|
|
||||||
|
|
176
debian/patches/bugfix/x86/i915/0001-drm-i915-Rename-gen7-cmdparser-tables.patch
vendored
Normal file
176
debian/patches/bugfix/x86/i915/0001-drm-i915-Rename-gen7-cmdparser-tables.patch
vendored
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Fri, 20 Apr 2018 14:26:01 -0700
|
||||||
|
Subject: drm/i915: Rename gen7 cmdparser tables
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 0a2f661b6c21815a7fa60e30babe975fee8e73c6 upstream.
|
||||||
|
|
||||||
|
We're about to introduce some new tables for later gens, and the
|
||||||
|
current naming for the gen7 tables will no longer make sense.
|
||||||
|
|
||||||
|
v2: rebase
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 70 +++++++++++++-------------
|
||||||
|
1 file changed, 35 insertions(+), 35 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -211,7 +211,7 @@ struct drm_i915_cmd_table {
|
||||||
|
|
||||||
|
/* Command Mask Fixed Len Action
|
||||||
|
---------------------------------------------------------- */
|
||||||
|
-static const struct drm_i915_cmd_descriptor common_cmds[] = {
|
||||||
|
+static const struct drm_i915_cmd_descriptor gen7_common_cmds[] = {
|
||||||
|
CMD( MI_NOOP, SMI, F, 1, S ),
|
||||||
|
CMD( MI_USER_INTERRUPT, SMI, F, 1, R ),
|
||||||
|
CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ),
|
||||||
|
@@ -244,7 +244,7 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
CMD( MI_BATCH_BUFFER_START, SMI, !F, 0xFF, S ),
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_descriptor render_cmds[] = {
|
||||||
|
+static const struct drm_i915_cmd_descriptor gen7_render_cmds[] = {
|
||||||
|
CMD( MI_FLUSH, SMI, F, 1, S ),
|
||||||
|
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
|
||||||
|
CMD( MI_PREDICATE, SMI, F, 1, S ),
|
||||||
|
@@ -328,7 +328,7 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
CMD( GFX_OP_3DSTATE_BINDING_TABLE_EDIT_PS, S3D, !F, 0x1FF, S ),
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_descriptor video_cmds[] = {
|
||||||
|
+static const struct drm_i915_cmd_descriptor gen7_video_cmds[] = {
|
||||||
|
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
|
||||||
|
CMD( MI_SET_APPID, SMI, F, 1, S ),
|
||||||
|
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B,
|
||||||
|
@@ -372,7 +372,7 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
CMD( MFX_WAIT, SMFX, F, 1, S ),
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_descriptor vecs_cmds[] = {
|
||||||
|
+static const struct drm_i915_cmd_descriptor gen7_vecs_cmds[] = {
|
||||||
|
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
|
||||||
|
CMD( MI_SET_APPID, SMI, F, 1, S ),
|
||||||
|
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B,
|
||||||
|
@@ -410,7 +410,7 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
}}, ),
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_descriptor blt_cmds[] = {
|
||||||
|
+static const struct drm_i915_cmd_descriptor gen7_blt_cmds[] = {
|
||||||
|
CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ),
|
||||||
|
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3FF, B,
|
||||||
|
.bits = {{
|
||||||
|
@@ -463,35 +463,35 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
#undef B
|
||||||
|
#undef M
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_table gen7_render_cmds[] = {
|
||||||
|
- { common_cmds, ARRAY_SIZE(common_cmds) },
|
||||||
|
- { render_cmds, ARRAY_SIZE(render_cmds) },
|
||||||
|
+static const struct drm_i915_cmd_table gen7_render_cmd_table[] = {
|
||||||
|
+ { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
+ { gen7_render_cmds, ARRAY_SIZE(gen7_render_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_table hsw_render_ring_cmds[] = {
|
||||||
|
- { common_cmds, ARRAY_SIZE(common_cmds) },
|
||||||
|
- { render_cmds, ARRAY_SIZE(render_cmds) },
|
||||||
|
+static const struct drm_i915_cmd_table hsw_render_ring_cmd_table[] = {
|
||||||
|
+ { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
+ { gen7_render_cmds, ARRAY_SIZE(gen7_render_cmds) },
|
||||||
|
{ hsw_render_cmds, ARRAY_SIZE(hsw_render_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_table gen7_video_cmds[] = {
|
||||||
|
- { common_cmds, ARRAY_SIZE(common_cmds) },
|
||||||
|
- { video_cmds, ARRAY_SIZE(video_cmds) },
|
||||||
|
+static const struct drm_i915_cmd_table gen7_video_cmd_table[] = {
|
||||||
|
+ { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
+ { gen7_video_cmds, ARRAY_SIZE(gen7_video_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_table hsw_vebox_cmds[] = {
|
||||||
|
- { common_cmds, ARRAY_SIZE(common_cmds) },
|
||||||
|
- { vecs_cmds, ARRAY_SIZE(vecs_cmds) },
|
||||||
|
+static const struct drm_i915_cmd_table hsw_vebox_cmd_table[] = {
|
||||||
|
+ { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
+ { gen7_vecs_cmds, ARRAY_SIZE(gen7_vecs_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_table gen7_blt_cmds[] = {
|
||||||
|
- { common_cmds, ARRAY_SIZE(common_cmds) },
|
||||||
|
- { blt_cmds, ARRAY_SIZE(blt_cmds) },
|
||||||
|
+static const struct drm_i915_cmd_table gen7_blt_cmd_table[] = {
|
||||||
|
+ { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
+ { gen7_blt_cmds, ARRAY_SIZE(gen7_blt_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = {
|
||||||
|
- { common_cmds, ARRAY_SIZE(common_cmds) },
|
||||||
|
- { blt_cmds, ARRAY_SIZE(blt_cmds) },
|
||||||
|
+static const struct drm_i915_cmd_table hsw_blt_ring_cmd_table[] = {
|
||||||
|
+ { gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
+ { gen7_blt_cmds, ARRAY_SIZE(gen7_blt_cmds) },
|
||||||
|
{ hsw_blt_cmds, ARRAY_SIZE(hsw_blt_cmds) },
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -871,12 +871,12 @@ void intel_engine_init_cmd_parser(struct
|
||||||
|
switch (engine->id) {
|
||||||
|
case RCS:
|
||||||
|
if (IS_HASWELL(engine->i915)) {
|
||||||
|
- cmd_tables = hsw_render_ring_cmds;
|
||||||
|
+ cmd_tables = hsw_render_ring_cmd_table;
|
||||||
|
cmd_table_count =
|
||||||
|
- ARRAY_SIZE(hsw_render_ring_cmds);
|
||||||
|
+ ARRAY_SIZE(hsw_render_ring_cmd_table);
|
||||||
|
} else {
|
||||||
|
- cmd_tables = gen7_render_cmds;
|
||||||
|
- cmd_table_count = ARRAY_SIZE(gen7_render_cmds);
|
||||||
|
+ cmd_tables = gen7_render_cmd_table;
|
||||||
|
+ cmd_table_count = ARRAY_SIZE(gen7_render_cmd_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_HASWELL(engine->i915)) {
|
||||||
|
@@ -890,17 +890,17 @@ void intel_engine_init_cmd_parser(struct
|
||||||
|
engine->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
|
||||||
|
break;
|
||||||
|
case VCS:
|
||||||
|
- cmd_tables = gen7_video_cmds;
|
||||||
|
- cmd_table_count = ARRAY_SIZE(gen7_video_cmds);
|
||||||
|
+ cmd_tables = gen7_video_cmd_table;
|
||||||
|
+ cmd_table_count = ARRAY_SIZE(gen7_video_cmd_table);
|
||||||
|
engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
|
||||||
|
break;
|
||||||
|
case BCS:
|
||||||
|
if (IS_HASWELL(engine->i915)) {
|
||||||
|
- cmd_tables = hsw_blt_ring_cmds;
|
||||||
|
- cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmds);
|
||||||
|
+ cmd_tables = hsw_blt_ring_cmd_table;
|
||||||
|
+ cmd_table_count = ARRAY_SIZE(hsw_blt_ring_cmd_table);
|
||||||
|
} else {
|
||||||
|
- cmd_tables = gen7_blt_cmds;
|
||||||
|
- cmd_table_count = ARRAY_SIZE(gen7_blt_cmds);
|
||||||
|
+ cmd_tables = gen7_blt_cmd_table;
|
||||||
|
+ cmd_table_count = ARRAY_SIZE(gen7_blt_cmd_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_HASWELL(engine->i915)) {
|
||||||
|
@@ -914,8 +914,8 @@ void intel_engine_init_cmd_parser(struct
|
||||||
|
engine->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
|
||||||
|
break;
|
||||||
|
case VECS:
|
||||||
|
- cmd_tables = hsw_vebox_cmds;
|
||||||
|
- cmd_table_count = ARRAY_SIZE(hsw_vebox_cmds);
|
||||||
|
+ cmd_tables = hsw_vebox_cmd_table;
|
||||||
|
+ cmd_table_count = ARRAY_SIZE(hsw_vebox_cmd_table);
|
||||||
|
/* VECS can use the same length_mask function as VCS */
|
||||||
|
engine->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
|
||||||
|
break;
|
93
debian/patches/bugfix/x86/i915/0002-drm-i915-Disable-Secure-Batches-for-gen6.patch
vendored
Normal file
93
debian/patches/bugfix/x86/i915/0002-drm-i915-Disable-Secure-Batches-for-gen6.patch
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Fri, 8 Jun 2018 08:53:46 -0700
|
||||||
|
Subject: drm/i915: Disable Secure Batches for gen6+
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 44157641d448cbc0c4b73c5231d2b911f0cb0427 upstream.
|
||||||
|
|
||||||
|
Retroactively stop reporting support for secure batches
|
||||||
|
through the api for gen6+ so that older binaries trigger
|
||||||
|
the fallback path instead.
|
||||||
|
|
||||||
|
Older binaries use secure batches pre gen6 to access resources
|
||||||
|
that are not available to normal usermode processes. However,
|
||||||
|
all known userspace explicitly checks for HAS_SECURE_BATCHES
|
||||||
|
before relying on the secure batch feature.
|
||||||
|
|
||||||
|
Since there are no known binaries relying on this for newer gens
|
||||||
|
we can kill secure batches from gen6, via I915_PARAM_HAS_SECURE_BATCHES.
|
||||||
|
|
||||||
|
v2: rebase (Mika)
|
||||||
|
v3: rebase (Mika)
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_drv.c | 2 +-
|
||||||
|
drivers/gpu/drm/i915/i915_drv.h | 2 ++
|
||||||
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 ++++++++++--
|
||||||
|
3 files changed, 13 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.c
|
||||||
|
@@ -351,7 +351,7 @@ static int i915_getparam_ioctl(struct dr
|
||||||
|
value = HAS_LEGACY_SEMAPHORES(dev_priv);
|
||||||
|
break;
|
||||||
|
case I915_PARAM_HAS_SECURE_BATCHES:
|
||||||
|
- value = capable(CAP_SYS_ADMIN);
|
||||||
|
+ value = HAS_SECURE_BATCHES(dev_priv) && capable(CAP_SYS_ADMIN);
|
||||||
|
break;
|
||||||
|
case I915_PARAM_CMD_PARSER_VERSION:
|
||||||
|
value = i915_cmd_parser_get_version(dev_priv);
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
@@ -2517,6 +2517,8 @@ intel_info(const struct drm_i915_private
|
||||||
|
|
||||||
|
#define HAS_LEGACY_SEMAPHORES(dev_priv) IS_GEN7(dev_priv)
|
||||||
|
|
||||||
|
+#define HAS_SECURE_BATCHES(dev_priv) (INTEL_GEN(dev_priv) < 6)
|
||||||
|
+
|
||||||
|
#define HAS_LLC(dev_priv) ((dev_priv)->info.has_llc)
|
||||||
|
#define HAS_SNOOP(dev_priv) ((dev_priv)->info.has_snoop)
|
||||||
|
#define HAS_EDRAM(dev_priv) (!!((dev_priv)->edram_cap & EDRAM_ENABLED))
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
@@ -2177,6 +2177,7 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
struct drm_i915_gem_exec_object2 *exec,
|
||||||
|
struct drm_syncobj **fences)
|
||||||
|
{
|
||||||
|
+ struct drm_i915_private *i915 = to_i915(dev);
|
||||||
|
struct i915_execbuffer eb;
|
||||||
|
struct dma_fence *in_fence = NULL;
|
||||||
|
struct sync_file *out_fence = NULL;
|
||||||
|
@@ -2187,7 +2188,7 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
BUILD_BUG_ON(__EXEC_OBJECT_INTERNAL_FLAGS &
|
||||||
|
~__EXEC_OBJECT_UNKNOWN_FLAGS);
|
||||||
|
|
||||||
|
- eb.i915 = to_i915(dev);
|
||||||
|
+ eb.i915 = i915;
|
||||||
|
eb.file = file;
|
||||||
|
eb.args = args;
|
||||||
|
if (DBG_FORCE_RELOC || !(args->flags & I915_EXEC_NO_RELOC))
|
||||||
|
@@ -2209,8 +2210,15 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
|
||||||
|
eb.batch_flags = 0;
|
||||||
|
if (args->flags & I915_EXEC_SECURE) {
|
||||||
|
+ if (INTEL_GEN(i915) >= 11)
|
||||||
|
+ return -ENODEV;
|
||||||
|
+
|
||||||
|
+ /* Return -EPERM to trigger fallback code on old binaries. */
|
||||||
|
+ if (!HAS_SECURE_BATCHES(i915))
|
||||||
|
+ return -EPERM;
|
||||||
|
+
|
||||||
|
if (!drm_is_current_master(file) || !capable(CAP_SYS_ADMIN))
|
||||||
|
- return -EPERM;
|
||||||
|
+ return -EPERM;
|
||||||
|
|
||||||
|
eb.batch_flags |= I915_DISPATCH_SECURE;
|
||||||
|
}
|
295
debian/patches/bugfix/x86/i915/0003-drm-i915-Remove-Master-tables-from-cmdparser.patch
vendored
Normal file
295
debian/patches/bugfix/x86/i915/0003-drm-i915-Remove-Master-tables-from-cmdparser.patch
vendored
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Fri, 8 Jun 2018 10:05:26 -0700
|
||||||
|
Subject: drm/i915: Remove Master tables from cmdparser
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 66d8aba1cd6db34af10de465c0d52af679288cb6 upstream.
|
||||||
|
|
||||||
|
The previous patch has killed support for secure batches
|
||||||
|
on gen6+, and hence the cmdparsers master tables are
|
||||||
|
now dead code. Remove them.
|
||||||
|
|
||||||
|
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>
|
||||||
|
Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 84 ++++++----------------
|
||||||
|
drivers/gpu/drm/i915/i915_drv.h | 3 +-
|
||||||
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +-
|
||||||
|
3 files changed, 26 insertions(+), 68 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -51,13 +51,11 @@
|
||||||
|
* granting userspace undue privileges. There are three categories of privilege.
|
||||||
|
*
|
||||||
|
* First, commands which are explicitly defined as privileged or which should
|
||||||
|
- * only be used by the kernel driver. The parser generally rejects such
|
||||||
|
- * commands, though it may allow some from the drm master process.
|
||||||
|
+ * only be used by the kernel driver. The parser rejects such commands
|
||||||
|
*
|
||||||
|
* Second, commands which access registers. To support correct/enhanced
|
||||||
|
* userspace functionality, particularly certain OpenGL extensions, the parser
|
||||||
|
- * provides a whitelist of registers which userspace may safely access (for both
|
||||||
|
- * normal and drm master processes).
|
||||||
|
+ * provides a whitelist of registers which userspace may safely access
|
||||||
|
*
|
||||||
|
* Third, commands which access privileged memory (i.e. GGTT, HWS page, etc).
|
||||||
|
* The parser always rejects such commands.
|
||||||
|
@@ -82,9 +80,9 @@
|
||||||
|
* in the per-engine command tables.
|
||||||
|
*
|
||||||
|
* Other command table entries map fairly directly to high level categories
|
||||||
|
- * mentioned above: rejected, master-only, register whitelist. The parser
|
||||||
|
- * implements a number of checks, including the privileged memory checks, via a
|
||||||
|
- * general bitmasking mechanism.
|
||||||
|
+ * mentioned above: rejected, register whitelist. The parser implements a number
|
||||||
|
+ * of checks, including the privileged memory checks, via a general bitmasking
|
||||||
|
+ * mechanism.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -102,8 +100,6 @@ struct drm_i915_cmd_descriptor {
|
||||||
|
* CMD_DESC_REJECT: The command is never allowed
|
||||||
|
* CMD_DESC_REGISTER: The command should be checked against the
|
||||||
|
* register whitelist for the appropriate ring
|
||||||
|
- * CMD_DESC_MASTER: The command is allowed if the submitting process
|
||||||
|
- * is the DRM master
|
||||||
|
*/
|
||||||
|
u32 flags;
|
||||||
|
#define CMD_DESC_FIXED (1<<0)
|
||||||
|
@@ -111,7 +107,6 @@ struct drm_i915_cmd_descriptor {
|
||||||
|
#define CMD_DESC_REJECT (1<<2)
|
||||||
|
#define CMD_DESC_REGISTER (1<<3)
|
||||||
|
#define CMD_DESC_BITMASK (1<<4)
|
||||||
|
-#define CMD_DESC_MASTER (1<<5)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The command's unique identification bits and the bitmask to get them.
|
||||||
|
@@ -207,14 +202,13 @@ struct drm_i915_cmd_table {
|
||||||
|
#define R CMD_DESC_REJECT
|
||||||
|
#define W CMD_DESC_REGISTER
|
||||||
|
#define B CMD_DESC_BITMASK
|
||||||
|
-#define M CMD_DESC_MASTER
|
||||||
|
|
||||||
|
/* Command Mask Fixed Len Action
|
||||||
|
---------------------------------------------------------- */
|
||||||
|
static const struct drm_i915_cmd_descriptor gen7_common_cmds[] = {
|
||||||
|
CMD( MI_NOOP, SMI, F, 1, S ),
|
||||||
|
CMD( MI_USER_INTERRUPT, SMI, F, 1, R ),
|
||||||
|
- CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, M ),
|
||||||
|
+ CMD( MI_WAIT_FOR_EVENT, SMI, F, 1, R ),
|
||||||
|
CMD( MI_ARB_CHECK, SMI, F, 1, S ),
|
||||||
|
CMD( MI_REPORT_HEAD, SMI, F, 1, S ),
|
||||||
|
CMD( MI_SUSPEND_FLUSH, SMI, F, 1, S ),
|
||||||
|
@@ -311,7 +305,7 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ),
|
||||||
|
CMD( MI_SET_APPID, SMI, F, 1, S ),
|
||||||
|
CMD( MI_RS_CONTEXT, SMI, F, 1, S ),
|
||||||
|
- CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ),
|
||||||
|
+ CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ),
|
||||||
|
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
|
||||||
|
CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, W,
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 1 } ),
|
||||||
|
@@ -444,7 +438,7 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_cmd_descriptor hsw_blt_cmds[] = {
|
||||||
|
- CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ),
|
||||||
|
+ CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, R ),
|
||||||
|
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -461,7 +455,6 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
#undef R
|
||||||
|
#undef W
|
||||||
|
#undef B
|
||||||
|
-#undef M
|
||||||
|
|
||||||
|
static const struct drm_i915_cmd_table gen7_render_cmd_table[] = {
|
||||||
|
{ gen7_common_cmds, ARRAY_SIZE(gen7_common_cmds) },
|
||||||
|
@@ -610,47 +603,29 @@ static const struct drm_i915_reg_descrip
|
||||||
|
REG64_IDX(RING_TIMESTAMP, BLT_RING_BASE),
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct drm_i915_reg_descriptor ivb_master_regs[] = {
|
||||||
|
- REG32(FORCEWAKE_MT),
|
||||||
|
- REG32(DERRMR),
|
||||||
|
- REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_A)),
|
||||||
|
- REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_B)),
|
||||||
|
- REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_C)),
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-static const struct drm_i915_reg_descriptor hsw_master_regs[] = {
|
||||||
|
- REG32(FORCEWAKE_MT),
|
||||||
|
- REG32(DERRMR),
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
#undef REG64
|
||||||
|
#undef REG32
|
||||||
|
|
||||||
|
struct drm_i915_reg_table {
|
||||||
|
const struct drm_i915_reg_descriptor *regs;
|
||||||
|
int num_regs;
|
||||||
|
- bool master;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_table ivb_render_reg_tables[] = {
|
||||||
|
- { gen7_render_regs, ARRAY_SIZE(gen7_render_regs), false },
|
||||||
|
- { ivb_master_regs, ARRAY_SIZE(ivb_master_regs), true },
|
||||||
|
+ { gen7_render_regs, ARRAY_SIZE(gen7_render_regs) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_table ivb_blt_reg_tables[] = {
|
||||||
|
- { gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs), false },
|
||||||
|
- { ivb_master_regs, ARRAY_SIZE(ivb_master_regs), true },
|
||||||
|
+ { gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_table hsw_render_reg_tables[] = {
|
||||||
|
- { gen7_render_regs, ARRAY_SIZE(gen7_render_regs), false },
|
||||||
|
- { hsw_render_regs, ARRAY_SIZE(hsw_render_regs), false },
|
||||||
|
- { hsw_master_regs, ARRAY_SIZE(hsw_master_regs), true },
|
||||||
|
+ { gen7_render_regs, ARRAY_SIZE(gen7_render_regs) },
|
||||||
|
+ { hsw_render_regs, ARRAY_SIZE(hsw_render_regs) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_table hsw_blt_reg_tables[] = {
|
||||||
|
- { gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs), false },
|
||||||
|
- { hsw_master_regs, ARRAY_SIZE(hsw_master_regs), true },
|
||||||
|
+ { gen7_blt_regs, ARRAY_SIZE(gen7_blt_regs) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
|
||||||
|
@@ -1027,22 +1002,16 @@ __find_reg(const struct drm_i915_reg_des
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_i915_reg_descriptor *
|
||||||
|
-find_reg(const struct intel_engine_cs *engine, bool is_master, u32 addr)
|
||||||
|
+find_reg(const struct intel_engine_cs *engine, u32 addr)
|
||||||
|
{
|
||||||
|
const struct drm_i915_reg_table *table = engine->reg_tables;
|
||||||
|
+ const struct drm_i915_reg_descriptor *reg = NULL;
|
||||||
|
int count = engine->reg_table_count;
|
||||||
|
|
||||||
|
- for (; count > 0; ++table, --count) {
|
||||||
|
- if (!table->master || is_master) {
|
||||||
|
- const struct drm_i915_reg_descriptor *reg;
|
||||||
|
-
|
||||||
|
- reg = __find_reg(table->regs, table->num_regs, addr);
|
||||||
|
- if (reg != NULL)
|
||||||
|
- return reg;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ for (; !reg && (count > 0); ++table, --count)
|
||||||
|
+ reg = __find_reg(table->regs, table->num_regs, addr);
|
||||||
|
|
||||||
|
- return NULL;
|
||||||
|
+ return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a vmap'd pointer to dst_obj, which the caller must unmap */
|
||||||
|
@@ -1127,8 +1096,7 @@ unpin_src:
|
||||||
|
|
||||||
|
static bool check_cmd(const struct intel_engine_cs *engine,
|
||||||
|
const struct drm_i915_cmd_descriptor *desc,
|
||||||
|
- const u32 *cmd, u32 length,
|
||||||
|
- const bool is_master)
|
||||||
|
+ const u32 *cmd, u32 length)
|
||||||
|
{
|
||||||
|
if (desc->flags & CMD_DESC_SKIP)
|
||||||
|
return true;
|
||||||
|
@@ -1138,12 +1106,6 @@ static bool check_cmd(const struct intel
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((desc->flags & CMD_DESC_MASTER) && !is_master) {
|
||||||
|
- DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n",
|
||||||
|
- *cmd);
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (desc->flags & CMD_DESC_REGISTER) {
|
||||||
|
/*
|
||||||
|
* Get the distance between individual register offset
|
||||||
|
@@ -1157,7 +1119,7 @@ static bool check_cmd(const struct intel
|
||||||
|
offset += step) {
|
||||||
|
const u32 reg_addr = cmd[offset] & desc->reg.mask;
|
||||||
|
const struct drm_i915_reg_descriptor *reg =
|
||||||
|
- find_reg(engine, is_master, reg_addr);
|
||||||
|
+ find_reg(engine, reg_addr);
|
||||||
|
|
||||||
|
if (!reg) {
|
||||||
|
DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (%s)\n",
|
||||||
|
@@ -1244,7 +1206,6 @@ static bool check_cmd(const struct intel
|
||||||
|
* @shadow_batch_obj: copy of the batch buffer in question
|
||||||
|
* @batch_start_offset: byte offset in the batch at which execution starts
|
||||||
|
* @batch_len: length of the commands in batch_obj
|
||||||
|
- * @is_master: is the submitting process the drm master?
|
||||||
|
*
|
||||||
|
* Parses the specified batch buffer looking for privilege violations as
|
||||||
|
* described in the overview.
|
||||||
|
@@ -1256,8 +1217,7 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
struct drm_i915_gem_object *batch_obj,
|
||||||
|
struct drm_i915_gem_object *shadow_batch_obj,
|
||||||
|
u32 batch_start_offset,
|
||||||
|
- u32 batch_len,
|
||||||
|
- bool is_master)
|
||||||
|
+ u32 batch_len)
|
||||||
|
{
|
||||||
|
u32 *cmd, *batch_end;
|
||||||
|
struct drm_i915_cmd_descriptor default_desc = noop_desc;
|
||||||
|
@@ -1323,7 +1283,7 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!check_cmd(engine, desc, cmd, length, is_master)) {
|
||||||
|
+ if (!check_cmd(engine, desc, cmd, length)) {
|
||||||
|
ret = -EACCES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
@@ -3343,8 +3343,7 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
struct drm_i915_gem_object *batch_obj,
|
||||||
|
struct drm_i915_gem_object *shadow_batch_obj,
|
||||||
|
u32 batch_start_offset,
|
||||||
|
- u32 batch_len,
|
||||||
|
- bool is_master);
|
||||||
|
+ u32 batch_len);
|
||||||
|
|
||||||
|
/* i915_perf.c */
|
||||||
|
extern void i915_perf_init(struct drm_i915_private *dev_priv);
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
@@ -1893,7 +1893,7 @@ static int i915_reset_gen7_sol_offsets(s
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static struct i915_vma *eb_parse(struct i915_execbuffer *eb, bool is_master)
|
||||||
|
+static struct i915_vma *eb_parse(struct i915_execbuffer *eb)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_object *shadow_batch_obj;
|
||||||
|
struct i915_vma *vma;
|
||||||
|
@@ -1908,8 +1908,7 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
eb->batch->obj,
|
||||||
|
shadow_batch_obj,
|
||||||
|
eb->batch_start_offset,
|
||||||
|
- eb->batch_len,
|
||||||
|
- is_master);
|
||||||
|
+ eb->batch_len);
|
||||||
|
if (err) {
|
||||||
|
if (err == -EACCES) /* unhandled chained batch */
|
||||||
|
vma = NULL;
|
||||||
|
@@ -2308,7 +2307,7 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
if (eb_use_cmdparser(&eb)) {
|
||||||
|
struct i915_vma *vma;
|
||||||
|
|
||||||
|
- vma = eb_parse(&eb, drm_is_current_master(file));
|
||||||
|
+ vma = eb_parse(&eb);
|
||||||
|
if (IS_ERR(vma)) {
|
||||||
|
err = PTR_ERR(vma);
|
||||||
|
goto err_vma;
|
110
debian/patches/bugfix/x86/i915/0004-drm-i915-Add-support-for-mandatory-cmdparsing.patch
vendored
Normal file
110
debian/patches/bugfix/x86/i915/0004-drm-i915-Add-support-for-mandatory-cmdparsing.patch
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Wed, 1 Aug 2018 09:33:59 -0700
|
||||||
|
Subject: drm/i915: Add support for mandatory cmdparsing
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 311a50e76a33d1e029563c24b2ff6db0c02b5afe upstream.
|
||||||
|
|
||||||
|
The existing cmdparser for gen7 can be bypassed by specifying
|
||||||
|
batch_len=0 in the execbuf call. This is safe because bypassing
|
||||||
|
simply reduces the cmd-set available.
|
||||||
|
|
||||||
|
In a later patch we will introduce cmdparsing for gen9, as a
|
||||||
|
security measure, which must be strictly enforced since without
|
||||||
|
it we are vulnerable to DoS attacks.
|
||||||
|
|
||||||
|
Introduce the concept of 'required' cmd parsing that cannot be
|
||||||
|
bypassed by submitting zero-length bb's.
|
||||||
|
|
||||||
|
v2: rebase (Mika)
|
||||||
|
v2: rebase (Mika)
|
||||||
|
v3: fix conflict on engine flags (Mika)
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 6 +++---
|
||||||
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 ++-
|
||||||
|
drivers/gpu/drm/i915/intel_ringbuffer.h | 17 ++++++++++++-----
|
||||||
|
3 files changed, 17 insertions(+), 9 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -916,7 +916,7 @@ void intel_engine_init_cmd_parser(struct
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- engine->flags |= I915_ENGINE_NEEDS_CMD_PARSER;
|
||||||
|
+ engine->flags |= I915_ENGINE_USING_CMD_PARSER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -928,7 +928,7 @@ void intel_engine_init_cmd_parser(struct
|
||||||
|
*/
|
||||||
|
void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine)
|
||||||
|
{
|
||||||
|
- if (!intel_engine_needs_cmd_parser(engine))
|
||||||
|
+ if (!intel_engine_using_cmd_parser(engine))
|
||||||
|
return;
|
||||||
|
|
||||||
|
fini_hash_table(engine);
|
||||||
|
@@ -1317,7 +1317,7 @@ int i915_cmd_parser_get_version(struct d
|
||||||
|
|
||||||
|
/* If the command parser is not enabled, report 0 - unsupported */
|
||||||
|
for_each_engine(engine, dev_priv, id) {
|
||||||
|
- if (intel_engine_needs_cmd_parser(engine)) {
|
||||||
|
+ if (intel_engine_using_cmd_parser(engine)) {
|
||||||
|
active = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
@@ -309,7 +309,8 @@ static inline u64 gen8_noncanonical_addr
|
||||||
|
|
||||||
|
static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
|
||||||
|
{
|
||||||
|
- return intel_engine_needs_cmd_parser(eb->engine) && eb->batch_len;
|
||||||
|
+ return intel_engine_requires_cmd_parser(eb->engine) ||
|
||||||
|
+ (intel_engine_using_cmd_parser(eb->engine) && eb->batch_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eb_create(struct i915_execbuffer *eb)
|
||||||
|
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
|
||||||
|
@@ -584,9 +584,10 @@ struct intel_engine_cs {
|
||||||
|
|
||||||
|
struct intel_engine_hangcheck hangcheck;
|
||||||
|
|
||||||
|
-#define I915_ENGINE_NEEDS_CMD_PARSER BIT(0)
|
||||||
|
-#define I915_ENGINE_SUPPORTS_STATS BIT(1)
|
||||||
|
-#define I915_ENGINE_HAS_PREEMPTION BIT(2)
|
||||||
|
+#define I915_ENGINE_USING_CMD_PARSER BIT(0)
|
||||||
|
+#define I915_ENGINE_SUPPORTS_STATS BIT(1)
|
||||||
|
+#define I915_ENGINE_HAS_PREEMPTION BIT(2)
|
||||||
|
+#define I915_ENGINE_REQUIRES_CMD_PARSER BIT(3)
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -647,9 +648,15 @@ struct intel_engine_cs {
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
-intel_engine_needs_cmd_parser(const struct intel_engine_cs *engine)
|
||||||
|
+intel_engine_using_cmd_parser(const struct intel_engine_cs *engine)
|
||||||
|
{
|
||||||
|
- return engine->flags & I915_ENGINE_NEEDS_CMD_PARSER;
|
||||||
|
+ return engine->flags & I915_ENGINE_USING_CMD_PARSER;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline bool
|
||||||
|
+intel_engine_requires_cmd_parser(const struct intel_engine_cs *engine)
|
||||||
|
+{
|
||||||
|
+ return engine->flags & I915_ENGINE_REQUIRES_CMD_PARSER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
198
debian/patches/bugfix/x86/i915/0005-drm-i915-Support-ro-ppgtt-mapped-cmdparser-shadow-bu.patch
vendored
Normal file
198
debian/patches/bugfix/x86/i915/0005-drm-i915-Support-ro-ppgtt-mapped-cmdparser-shadow-bu.patch
vendored
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Tue, 22 May 2018 13:59:06 -0700
|
||||||
|
Subject: drm/i915: Support ro ppgtt mapped cmdparser shadow buffers
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 4f7af1948abcb18b4772fe1bcd84d7d27d96258c upstream.
|
||||||
|
|
||||||
|
For Gen7, the original cmdparser motive was to permit limited
|
||||||
|
use of register read/write instructions in unprivileged BB's.
|
||||||
|
This worked by copying the user supplied bb to a kmd owned
|
||||||
|
bb, and running it in secure mode, from the ggtt, only if
|
||||||
|
the scanner finds no unsafe commands or registers.
|
||||||
|
|
||||||
|
For Gen8+ we can't use this same technique because running bb's
|
||||||
|
from the ggtt also disables access to ppgtt space. But we also
|
||||||
|
do not actually require 'secure' execution since we are only
|
||||||
|
trying to reduce the available command/register set. Instead we
|
||||||
|
will copy the user buffer to a kmd owned read-only bb in ppgtt,
|
||||||
|
and run in the usual non-secure mode.
|
||||||
|
|
||||||
|
Note that ro pages are only supported by ppgtt (not ggtt), but
|
||||||
|
luckily that's exactly what we need.
|
||||||
|
|
||||||
|
Add the required paths to map the shadow buffer to ppgtt ro for Gen8+
|
||||||
|
|
||||||
|
v2: IS_GEN7/IS_GEN (Mika)
|
||||||
|
v3: rebase
|
||||||
|
v4: rebase
|
||||||
|
v5: rebase
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_drv.h | 14 ++++++
|
||||||
|
drivers/gpu/drm/i915/i915_gem.c | 16 +++++-
|
||||||
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 57 +++++++++++++++-------
|
||||||
|
3 files changed, 68 insertions(+), 19 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
@@ -2496,6 +2496,12 @@ intel_info(const struct drm_i915_private
|
||||||
|
#define IS_GEN9_LP(dev_priv) (IS_GEN9(dev_priv) && IS_LP(dev_priv))
|
||||||
|
#define IS_GEN9_BC(dev_priv) (IS_GEN9(dev_priv) && !IS_LP(dev_priv))
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * The Gen7 cmdparser copies the scanned buffer to the ggtt for execution
|
||||||
|
+ * All later gens can run the final buffer from the ppgtt
|
||||||
|
+ */
|
||||||
|
+#define CMDPARSER_USES_GGTT(dev_priv) IS_GEN7(dev_priv)
|
||||||
|
+
|
||||||
|
#define ENGINE_MASK(id) BIT(id)
|
||||||
|
#define RENDER_RING ENGINE_MASK(RCS)
|
||||||
|
#define BSD_RING ENGINE_MASK(VCS)
|
||||||
|
@@ -2946,6 +2952,14 @@ i915_gem_object_ggtt_pin(struct drm_i915
|
||||||
|
u64 alignment,
|
||||||
|
u64 flags);
|
||||||
|
|
||||||
|
+struct i915_vma * __must_check
|
||||||
|
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
||||||
|
+ struct i915_address_space *vm,
|
||||||
|
+ const struct i915_ggtt_view *view,
|
||||||
|
+ u64 size,
|
||||||
|
+ u64 alignment,
|
||||||
|
+ u64 flags);
|
||||||
|
+
|
||||||
|
int i915_gem_object_unbind(struct drm_i915_gem_object *obj);
|
||||||
|
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
||||||
|
@@ -4414,6 +4414,20 @@ i915_gem_object_ggtt_pin(struct drm_i915
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
||||||
|
struct i915_address_space *vm = &dev_priv->ggtt.vm;
|
||||||
|
+
|
||||||
|
+ return i915_gem_object_pin(obj, vm, view, size, alignment,
|
||||||
|
+ flags | PIN_GLOBAL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+struct i915_vma *
|
||||||
|
+i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
||||||
|
+ struct i915_address_space *vm,
|
||||||
|
+ const struct i915_ggtt_view *view,
|
||||||
|
+ u64 size,
|
||||||
|
+ u64 alignment,
|
||||||
|
+ u64 flags)
|
||||||
|
+{
|
||||||
|
+ struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
||||||
|
struct i915_vma *vma;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
@@ -4477,7 +4491,7 @@ i915_gem_object_ggtt_pin(struct drm_i915
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = i915_vma_pin(vma, size, alignment, flags | PIN_GLOBAL);
|
||||||
|
+ ret = i915_vma_pin(vma, size, alignment, flags);
|
||||||
|
if (ret)
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
@@ -1894,6 +1894,33 @@ static int i915_reset_gen7_sol_offsets(s
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static struct i915_vma *
|
||||||
|
+shadow_batch_pin(struct i915_execbuffer *eb, struct drm_i915_gem_object *obj)
|
||||||
|
+{
|
||||||
|
+ struct drm_i915_private *dev_priv = eb->i915;
|
||||||
|
+ struct i915_address_space *vm;
|
||||||
|
+ u64 flags;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * PPGTT backed shadow buffers must be mapped RO, to prevent
|
||||||
|
+ * post-scan tampering
|
||||||
|
+ */
|
||||||
|
+ if (CMDPARSER_USES_GGTT(dev_priv)) {
|
||||||
|
+ flags = PIN_GLOBAL;
|
||||||
|
+ vm = &dev_priv->ggtt.vm;
|
||||||
|
+ eb->batch_flags |= I915_DISPATCH_SECURE;
|
||||||
|
+ } else if (eb->vm->has_read_only) {
|
||||||
|
+ flags = PIN_USER;
|
||||||
|
+ vm = eb->vm;
|
||||||
|
+ i915_gem_object_set_readonly(obj);
|
||||||
|
+ } else {
|
||||||
|
+ DRM_DEBUG("Cannot prevent post-scan tampering without RO capable vm\n");
|
||||||
|
+ return ERR_PTR(-EINVAL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return i915_gem_object_pin(obj, vm, NULL, 0, 0, flags);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static struct i915_vma *eb_parse(struct i915_execbuffer *eb)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_object *shadow_batch_obj;
|
||||||
|
@@ -1911,14 +1938,21 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
eb->batch_start_offset,
|
||||||
|
eb->batch_len);
|
||||||
|
if (err) {
|
||||||
|
- if (err == -EACCES) /* unhandled chained batch */
|
||||||
|
+ /*
|
||||||
|
+ * Unsafe GGTT-backed buffers can still be submitted safely
|
||||||
|
+ * as non-secure.
|
||||||
|
+ * For PPGTT backing however, we have no choice but to forcibly
|
||||||
|
+ * reject unsafe buffers
|
||||||
|
+ */
|
||||||
|
+ if (CMDPARSER_USES_GGTT(eb->i915) && (err == -EACCES))
|
||||||
|
+ /* Execute original buffer non-secure */
|
||||||
|
vma = NULL;
|
||||||
|
else
|
||||||
|
vma = ERR_PTR(err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
- vma = i915_gem_object_ggtt_pin(shadow_batch_obj, NULL, 0, 0, 0);
|
||||||
|
+ vma = shadow_batch_pin(eb, shadow_batch_obj);
|
||||||
|
if (IS_ERR(vma))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
@@ -1927,7 +1961,9 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
__EXEC_OBJECT_HAS_PIN | __EXEC_OBJECT_HAS_REF;
|
||||||
|
vma->exec_flags = &eb->flags[eb->buffer_count];
|
||||||
|
eb->buffer_count++;
|
||||||
|
-
|
||||||
|
+ eb->batch_start_offset = 0;
|
||||||
|
+ eb->batch = vma;
|
||||||
|
+ /* eb->batch_len unchanged */
|
||||||
|
out:
|
||||||
|
i915_gem_object_unpin_pages(shadow_batch_obj);
|
||||||
|
return vma;
|
||||||
|
@@ -2313,21 +2349,6 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
err = PTR_ERR(vma);
|
||||||
|
goto err_vma;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- if (vma) {
|
||||||
|
- /*
|
||||||
|
- * Batch parsed and accepted:
|
||||||
|
- *
|
||||||
|
- * Set the DISPATCH_SECURE bit to remove the NON_SECURE
|
||||||
|
- * bit from MI_BATCH_BUFFER_START commands issued in
|
||||||
|
- * the dispatch_execbuffer implementations. We
|
||||||
|
- * specifically don't want that set on batches the
|
||||||
|
- * command parser has accepted.
|
||||||
|
- */
|
||||||
|
- eb.batch_flags |= I915_DISPATCH_SECURE;
|
||||||
|
- eb.batch_start_offset = 0;
|
||||||
|
- eb.batch = vma;
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eb.batch_len == 0)
|
57
debian/patches/bugfix/x86/i915/0006-drm-i915-Allow-parsing-of-unsized-batches.patch
vendored
Normal file
57
debian/patches/bugfix/x86/i915/0006-drm-i915-Allow-parsing-of-unsized-batches.patch
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Wed, 1 Aug 2018 09:45:50 -0700
|
||||||
|
Subject: drm/i915: Allow parsing of unsized batches
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 435e8fc059dbe0eec823a75c22da2972390ba9e0 upstream.
|
||||||
|
|
||||||
|
In "drm/i915: Add support for mandatory cmdparsing" we introduced the
|
||||||
|
concept of mandatory parsing. This allows the cmdparser to be invoked
|
||||||
|
even when user passes batch_len=0 to the execbuf ioctl's.
|
||||||
|
|
||||||
|
However, the cmdparser needs to know the extents of the buffer being
|
||||||
|
scanned. Refactor the code to ensure the cmdparser uses the actual
|
||||||
|
object size, instead of the incoming length, if user passes 0.
|
||||||
|
|
||||||
|
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>
|
||||||
|
Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 +++++----
|
||||||
|
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
@@ -310,7 +310,8 @@ static inline u64 gen8_noncanonical_addr
|
||||||
|
static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
|
||||||
|
{
|
||||||
|
return intel_engine_requires_cmd_parser(eb->engine) ||
|
||||||
|
- (intel_engine_using_cmd_parser(eb->engine) && eb->batch_len);
|
||||||
|
+ (intel_engine_using_cmd_parser(eb->engine) &&
|
||||||
|
+ eb->args->batch_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eb_create(struct i915_execbuffer *eb)
|
||||||
|
@@ -2341,6 +2342,9 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
goto err_vma;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (eb.batch_len == 0)
|
||||||
|
+ eb.batch_len = eb.batch->size - eb.batch_start_offset;
|
||||||
|
+
|
||||||
|
if (eb_use_cmdparser(&eb)) {
|
||||||
|
struct i915_vma *vma;
|
||||||
|
|
||||||
|
@@ -2351,9 +2355,6 @@ i915_gem_do_execbuffer(struct drm_device
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (eb.batch_len == 0)
|
||||||
|
- eb.batch_len = eb.batch->size - eb.batch_start_offset;
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
|
||||||
|
* batch" bit. Hence we need to pin secure batches into the global gtt.
|
|
@ -0,0 +1,258 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Mon, 23 Apr 2018 11:12:15 -0700
|
||||||
|
Subject: drm/i915: Add gen9 BCS cmdparsing
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 116 ++++++++++++++++++++++---
|
||||||
|
drivers/gpu/drm/i915/i915_gem_gtt.c | 3 +-
|
||||||
|
drivers/gpu/drm/i915/i915_reg.h | 4 +
|
||||||
|
3 files changed, 112 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -442,6 +442,47 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
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 h
|
||||||
|
{ 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_descrip
|
||||||
|
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 h
|
||||||
|
{ 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(
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * 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;
|
||||||
|
@@ -1342,6 +1437,7 @@ int i915_cmd_parser_get_version(struct d
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
|
||||||
|
@@ -158,7 +158,8 @@ int intel_sanitize_enable_ppgtt(struct d
|
||||||
|
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)
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_reg.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
||||||
|
@@ -471,6 +471,10 @@ static inline bool i915_mmio_reg_valid(i
|
||||||
|
*/
|
||||||
|
#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)
|
94
debian/patches/bugfix/x86/i915/0008-drm-i915-cmdparser-Use-explicit-goto-for-error-paths.patch
vendored
Normal file
94
debian/patches/bugfix/x86/i915/0008-drm-i915-cmdparser-Use-explicit-goto-for-error-paths.patch
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Thu, 27 Sep 2018 10:23:17 -0700
|
||||||
|
Subject: drm/i915/cmdparser: Use explicit goto for error paths
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 0546a29cd884fb8184731c79ab008927ca8859d0 upstream.
|
||||||
|
|
||||||
|
In the next patch we will be adding a second valid
|
||||||
|
termination condition which will require a small
|
||||||
|
amount of refactoring to share logic with the BB_END
|
||||||
|
case.
|
||||||
|
|
||||||
|
Refactor all error conditions to jump to a dedicated
|
||||||
|
exit path, with 'break' reserved only for a successful
|
||||||
|
parse.
|
||||||
|
|
||||||
|
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: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 25 +++++++++++++------------
|
||||||
|
1 file changed, 13 insertions(+), 12 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -1337,21 +1337,15 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
do {
|
||||||
|
u32 length;
|
||||||
|
|
||||||
|
- if (*cmd == MI_BATCH_BUFFER_END) {
|
||||||
|
- if (needs_clflush_after) {
|
||||||
|
- void *ptr = page_mask_bits(shadow_batch_obj->mm.mapping);
|
||||||
|
- drm_clflush_virt_range(ptr,
|
||||||
|
- (void *)(cmd + 1) - ptr);
|
||||||
|
- }
|
||||||
|
+ if (*cmd == MI_BATCH_BUFFER_END)
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
|
||||||
|
desc = find_cmd(engine, *cmd, desc, &default_desc);
|
||||||
|
if (!desc) {
|
||||||
|
DRM_DEBUG_DRIVER("CMD: Unrecognized command: 0x%08X\n",
|
||||||
|
*cmd);
|
||||||
|
ret = -EINVAL;
|
||||||
|
- break;
|
||||||
|
+ goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1361,7 +1355,7 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
*/
|
||||||
|
if (desc->cmd.value == MI_BATCH_BUFFER_START) {
|
||||||
|
ret = -EACCES;
|
||||||
|
- break;
|
||||||
|
+ goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc->flags & CMD_DESC_FIXED)
|
||||||
|
@@ -1375,22 +1369,29 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
length,
|
||||||
|
batch_end - cmd);
|
||||||
|
ret = -EINVAL;
|
||||||
|
- break;
|
||||||
|
+ goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_cmd(engine, desc, cmd, length)) {
|
||||||
|
ret = -EACCES;
|
||||||
|
- break;
|
||||||
|
+ goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd += length;
|
||||||
|
if (cmd >= batch_end) {
|
||||||
|
DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
- break;
|
||||||
|
+ goto err;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
+ if (needs_clflush_after) {
|
||||||
|
+ void *ptr = page_mask_bits(shadow_batch_obj->mm.mapping);
|
||||||
|
+
|
||||||
|
+ drm_clflush_virt_range(ptr, (void *)(cmd + 1) - ptr);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+err:
|
||||||
|
i915_gem_object_unpin_map(shadow_batch_obj);
|
||||||
|
return ret;
|
||||||
|
}
|
404
debian/patches/bugfix/x86/i915/0009-drm-i915-cmdparser-Add-support-for-backward-jumps.patch
vendored
Normal file
404
debian/patches/bugfix/x86/i915/0009-drm-i915-cmdparser-Add-support-for-backward-jumps.patch
vendored
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Thu, 20 Sep 2018 09:58:36 -0700
|
||||||
|
Subject: drm/i915/cmdparser: Add support for backward jumps
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit f8c08d8faee5567803c8c533865296ca30286bbf upstream.
|
||||||
|
|
||||||
|
To keep things manageable, the pre-gen9 cmdparser does not
|
||||||
|
attempt to track any form of nested BB_START's. This did not
|
||||||
|
prevent usermode from using nested starts, or even chained
|
||||||
|
batches because the cmdparser is not strictly enforced pre gen9.
|
||||||
|
|
||||||
|
Instead, the existence of a nested BB_START would cause the batch
|
||||||
|
to be emitted in insecure mode, and any privileged capabilities
|
||||||
|
would not be available.
|
||||||
|
|
||||||
|
For Gen9, the cmdparser becomes mandatory (for BCS at least), and
|
||||||
|
so not providing any form of nested BB_START support becomes
|
||||||
|
overly restrictive. Any such batch will simply not run.
|
||||||
|
|
||||||
|
We make heavy use of backward jumps in igt, and it is much easier
|
||||||
|
to add support for this restricted subset of nested jumps, than to
|
||||||
|
rewrite the whole of our test suite to avoid them.
|
||||||
|
|
||||||
|
Add the required logic to support limited backward jumps, to
|
||||||
|
instructions that have already been validated by the parser.
|
||||||
|
|
||||||
|
Note that it's not sufficient to simply approve any BB_START
|
||||||
|
that jumps backwards in the buffer because this would allow an
|
||||||
|
attacker to embed a rogue instruction sequence within the
|
||||||
|
operand words of a harmless instruction (say LRI) and jump to
|
||||||
|
that.
|
||||||
|
|
||||||
|
We introduce a bit array to track every instr offset successfully
|
||||||
|
validated, and test the target of BB_START against this. If the
|
||||||
|
target offset hits, it is re-written to the same offset in the
|
||||||
|
shadow buffer and the BB_START cmd is allowed.
|
||||||
|
|
||||||
|
Note: This patch deliberately ignores checkpatch issues in the
|
||||||
|
cmdtables, in order to match the style of the surrounding code.
|
||||||
|
We'll correct the entire file in one go in a later patch.
|
||||||
|
|
||||||
|
v2: set dispatch secure late (Mika)
|
||||||
|
v3: rebase (Mika)
|
||||||
|
v4: Clear whitelist on each parse
|
||||||
|
Minor review updates (Chris)
|
||||||
|
v5: Correct backward jump batching
|
||||||
|
v6: fix compilation error due to struct eb shuffle (Mika)
|
||||||
|
|
||||||
|
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: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
|
||||||
|
Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 151 +++++++++++++++++++--
|
||||||
|
drivers/gpu/drm/i915/i915_drv.h | 9 +-
|
||||||
|
drivers/gpu/drm/i915/i915_gem_context.c | 5 +
|
||||||
|
drivers/gpu/drm/i915/i915_gem_context.h | 6 +
|
||||||
|
drivers/gpu/drm/i915/i915_gem_execbuffer.c | 34 +++--
|
||||||
|
5 files changed, 179 insertions(+), 26 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -481,6 +481,19 @@ static const struct drm_i915_cmd_descrip
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC } ),
|
||||||
|
CMD( MI_LOAD_REGISTER_REG, SMI, !F, 0xFF, W,
|
||||||
|
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 1 } ),
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * We allow BB_START but apply further checks. We just sanitize the
|
||||||
|
+ * basic fields here.
|
||||||
|
+ */
|
||||||
|
+#define MI_BB_START_OPERAND_MASK GENMASK(SMI-1, 0)
|
||||||
|
+#define MI_BB_START_OPERAND_EXPECT (MI_BATCH_PPGTT_HSW | 1)
|
||||||
|
+ CMD( MI_BATCH_BUFFER_START_GEN8, SMI, !F, 0xFF, B,
|
||||||
|
+ .bits = {{
|
||||||
|
+ .offset = 0,
|
||||||
|
+ .mask = MI_BB_START_OPERAND_MASK,
|
||||||
|
+ .expected = MI_BB_START_OPERAND_EXPECT,
|
||||||
|
+ }}, ),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_i915_cmd_descriptor noop_desc =
|
||||||
|
@@ -1292,15 +1305,113 @@ static bool check_cmd(const struct intel
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int check_bbstart(const struct i915_gem_context *ctx,
|
||||||
|
+ u32 *cmd, u32 offset, u32 length,
|
||||||
|
+ u32 batch_len,
|
||||||
|
+ u64 batch_start,
|
||||||
|
+ u64 shadow_batch_start)
|
||||||
|
+{
|
||||||
|
+ u64 jump_offset, jump_target;
|
||||||
|
+ u32 target_cmd_offset, target_cmd_index;
|
||||||
|
+
|
||||||
|
+ /* For igt compatibility on older platforms */
|
||||||
|
+ if (CMDPARSER_USES_GGTT(ctx->i915)) {
|
||||||
|
+ DRM_DEBUG("CMD: Rejecting BB_START for ggtt based submission\n");
|
||||||
|
+ return -EACCES;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (length != 3) {
|
||||||
|
+ DRM_DEBUG("CMD: Recursive BB_START with bad length(%u)\n",
|
||||||
|
+ length);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ jump_target = *(u64*)(cmd+1);
|
||||||
|
+ jump_offset = jump_target - batch_start;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Any underflow of jump_target is guaranteed to be outside the range
|
||||||
|
+ * of a u32, so >= test catches both too large and too small
|
||||||
|
+ */
|
||||||
|
+ if (jump_offset >= batch_len) {
|
||||||
|
+ DRM_DEBUG("CMD: BB_START to 0x%llx jumps out of BB\n",
|
||||||
|
+ jump_target);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * This cannot overflow a u32 because we already checked jump_offset
|
||||||
|
+ * is within the BB, and the batch_len is a u32
|
||||||
|
+ */
|
||||||
|
+ target_cmd_offset = lower_32_bits(jump_offset);
|
||||||
|
+ target_cmd_index = target_cmd_offset / sizeof(u32);
|
||||||
|
+
|
||||||
|
+ *(u64*)(cmd + 1) = shadow_batch_start + target_cmd_offset;
|
||||||
|
+
|
||||||
|
+ if (target_cmd_index == offset)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (ctx->jump_whitelist_cmds <= target_cmd_index) {
|
||||||
|
+ DRM_DEBUG("CMD: Rejecting BB_START - truncated whitelist array\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ } else if (!test_bit(target_cmd_index, ctx->jump_whitelist)) {
|
||||||
|
+ DRM_DEBUG("CMD: BB_START to 0x%llx not a previously executed cmd\n",
|
||||||
|
+ jump_target);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void init_whitelist(struct i915_gem_context *ctx, u32 batch_len)
|
||||||
|
+{
|
||||||
|
+ const u32 batch_cmds = DIV_ROUND_UP(batch_len, sizeof(u32));
|
||||||
|
+ const u32 exact_size = BITS_TO_LONGS(batch_cmds);
|
||||||
|
+ u32 next_size = BITS_TO_LONGS(roundup_pow_of_two(batch_cmds));
|
||||||
|
+ unsigned long *next_whitelist;
|
||||||
|
+
|
||||||
|
+ if (CMDPARSER_USES_GGTT(ctx->i915))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (batch_cmds <= ctx->jump_whitelist_cmds) {
|
||||||
|
+ memset(ctx->jump_whitelist, 0, exact_size * sizeof(u32));
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+again:
|
||||||
|
+ next_whitelist = kcalloc(next_size, sizeof(long), GFP_KERNEL);
|
||||||
|
+ if (next_whitelist) {
|
||||||
|
+ kfree(ctx->jump_whitelist);
|
||||||
|
+ ctx->jump_whitelist = next_whitelist;
|
||||||
|
+ ctx->jump_whitelist_cmds =
|
||||||
|
+ next_size * BITS_PER_BYTE * sizeof(long);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (next_size > exact_size) {
|
||||||
|
+ next_size = exact_size;
|
||||||
|
+ goto again;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ DRM_DEBUG("CMD: Failed to extend whitelist. BB_START may be disallowed\n");
|
||||||
|
+ memset(ctx->jump_whitelist, 0,
|
||||||
|
+ BITS_TO_LONGS(ctx->jump_whitelist_cmds) * sizeof(u32));
|
||||||
|
+
|
||||||
|
+ return;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#define LENGTH_BIAS 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i915_parse_cmds() - parse a submitted batch buffer for privilege violations
|
||||||
|
+ * @ctx: the context in which the batch is to execute
|
||||||
|
* @engine: the engine on which the batch is to execute
|
||||||
|
* @batch_obj: the batch buffer in question
|
||||||
|
- * @shadow_batch_obj: copy of the batch buffer in question
|
||||||
|
+ * @batch_start: Canonical base address of batch
|
||||||
|
* @batch_start_offset: byte offset in the batch at which execution starts
|
||||||
|
* @batch_len: length of the commands in batch_obj
|
||||||
|
+ * @shadow_batch_obj: copy of the batch buffer in question
|
||||||
|
+ * @shadow_batch_start: Canonical base address of shadow_batch_obj
|
||||||
|
*
|
||||||
|
* Parses the specified batch buffer looking for privilege violations as
|
||||||
|
* described in the overview.
|
||||||
|
@@ -1308,13 +1419,17 @@ static bool check_cmd(const struct intel
|
||||||
|
* Return: non-zero if the parser finds violations or otherwise fails; -EACCES
|
||||||
|
* if the batch appears legal but should use hardware parsing
|
||||||
|
*/
|
||||||
|
-int intel_engine_cmd_parser(struct intel_engine_cs *engine,
|
||||||
|
+
|
||||||
|
+int intel_engine_cmd_parser(struct i915_gem_context *ctx,
|
||||||
|
+ struct intel_engine_cs *engine,
|
||||||
|
struct drm_i915_gem_object *batch_obj,
|
||||||
|
- struct drm_i915_gem_object *shadow_batch_obj,
|
||||||
|
+ u64 batch_start,
|
||||||
|
u32 batch_start_offset,
|
||||||
|
- u32 batch_len)
|
||||||
|
+ u32 batch_len,
|
||||||
|
+ struct drm_i915_gem_object *shadow_batch_obj,
|
||||||
|
+ u64 shadow_batch_start)
|
||||||
|
{
|
||||||
|
- u32 *cmd, *batch_end;
|
||||||
|
+ u32 *cmd, *batch_end, offset = 0;
|
||||||
|
struct drm_i915_cmd_descriptor default_desc = noop_desc;
|
||||||
|
const struct drm_i915_cmd_descriptor *desc = &default_desc;
|
||||||
|
bool needs_clflush_after = false;
|
||||||
|
@@ -1328,6 +1443,8 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
return PTR_ERR(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ init_whitelist(ctx, batch_len);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* We use the batch length as size because the shadow object is as
|
||||||
|
* large or larger and copy_batch() will write MI_NOPs to the extra
|
||||||
|
@@ -1348,16 +1465,6 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * 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;
|
||||||
|
- goto err;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (desc->flags & CMD_DESC_FIXED)
|
||||||
|
length = desc->length.fixed;
|
||||||
|
else
|
||||||
|
@@ -1377,7 +1484,21 @@ int intel_engine_cmd_parser(struct intel
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (desc->cmd.value == MI_BATCH_BUFFER_START) {
|
||||||
|
+ ret = check_bbstart(ctx, cmd, offset, length,
|
||||||
|
+ batch_len, batch_start,
|
||||||
|
+ shadow_batch_start);
|
||||||
|
+
|
||||||
|
+ if (ret)
|
||||||
|
+ goto err;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (ctx->jump_whitelist_cmds > offset)
|
||||||
|
+ set_bit(offset, ctx->jump_whitelist);
|
||||||
|
+
|
||||||
|
cmd += length;
|
||||||
|
+ offset += length;
|
||||||
|
if (cmd >= batch_end) {
|
||||||
|
DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
@@ -3353,11 +3353,14 @@ const char *i915_cache_level_str(struct
|
||||||
|
int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv);
|
||||||
|
void intel_engine_init_cmd_parser(struct intel_engine_cs *engine);
|
||||||
|
void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine);
|
||||||
|
-int intel_engine_cmd_parser(struct intel_engine_cs *engine,
|
||||||
|
+int intel_engine_cmd_parser(struct i915_gem_context *cxt,
|
||||||
|
+ struct intel_engine_cs *engine,
|
||||||
|
struct drm_i915_gem_object *batch_obj,
|
||||||
|
- struct drm_i915_gem_object *shadow_batch_obj,
|
||||||
|
+ u64 user_batch_start,
|
||||||
|
u32 batch_start_offset,
|
||||||
|
- u32 batch_len);
|
||||||
|
+ u32 batch_len,
|
||||||
|
+ struct drm_i915_gem_object *shadow_batch_obj,
|
||||||
|
+ u64 shadow_batch_start);
|
||||||
|
|
||||||
|
/* i915_perf.c */
|
||||||
|
extern void i915_perf_init(struct drm_i915_private *dev_priv);
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_context.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
|
||||||
|
@@ -124,6 +124,8 @@ static void i915_gem_context_free(struct
|
||||||
|
|
||||||
|
i915_ppgtt_put(ctx->ppgtt);
|
||||||
|
|
||||||
|
+ kfree(ctx->jump_whitelist);
|
||||||
|
+
|
||||||
|
for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
|
||||||
|
struct intel_context *ce = &ctx->__engine[n];
|
||||||
|
|
||||||
|
@@ -339,6 +341,9 @@ __create_hw_context(struct drm_i915_priv
|
||||||
|
else
|
||||||
|
ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE;
|
||||||
|
|
||||||
|
+ ctx->jump_whitelist = NULL;
|
||||||
|
+ ctx->jump_whitelist_cmds = 0;
|
||||||
|
+
|
||||||
|
return ctx;
|
||||||
|
|
||||||
|
err_pid:
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_context.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_context.h
|
||||||
|
@@ -183,6 +183,12 @@ struct i915_gem_context {
|
||||||
|
/** remap_slice: Bitmask of cache lines that need remapping */
|
||||||
|
u8 remap_slice;
|
||||||
|
|
||||||
|
+ /** jump_whitelist: Bit array for tracking cmds during cmdparsing */
|
||||||
|
+ unsigned long *jump_whitelist;
|
||||||
|
+
|
||||||
|
+ /** jump_whitelist_cmds: No of cmd slots available */
|
||||||
|
+ u32 jump_whitelist_cmds;
|
||||||
|
+
|
||||||
|
/** handles_vma: rbtree to look up our context specific obj/vma for
|
||||||
|
* the user handle. (user handles are per fd, but the binding is
|
||||||
|
* per vm, which may be one per context or shared with the global GTT)
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
|
||||||
|
@@ -1909,7 +1909,6 @@ shadow_batch_pin(struct i915_execbuffer
|
||||||
|
if (CMDPARSER_USES_GGTT(dev_priv)) {
|
||||||
|
flags = PIN_GLOBAL;
|
||||||
|
vm = &dev_priv->ggtt.vm;
|
||||||
|
- eb->batch_flags |= I915_DISPATCH_SECURE;
|
||||||
|
} else if (eb->vm->has_read_only) {
|
||||||
|
flags = PIN_USER;
|
||||||
|
vm = eb->vm;
|
||||||
|
@@ -1926,6 +1925,8 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_object *shadow_batch_obj;
|
||||||
|
struct i915_vma *vma;
|
||||||
|
+ u64 batch_start;
|
||||||
|
+ u64 shadow_batch_start;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
shadow_batch_obj = i915_gem_batch_pool_get(&eb->engine->batch_pool,
|
||||||
|
@@ -1933,12 +1934,27 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
if (IS_ERR(shadow_batch_obj))
|
||||||
|
return ERR_CAST(shadow_batch_obj);
|
||||||
|
|
||||||
|
- err = intel_engine_cmd_parser(eb->engine,
|
||||||
|
+ vma = shadow_batch_pin(eb, shadow_batch_obj);
|
||||||
|
+ if (IS_ERR(vma))
|
||||||
|
+ goto out;
|
||||||
|
+
|
||||||
|
+ batch_start = gen8_canonical_addr(eb->batch->node.start) +
|
||||||
|
+ eb->batch_start_offset;
|
||||||
|
+
|
||||||
|
+ shadow_batch_start = gen8_canonical_addr(vma->node.start);
|
||||||
|
+
|
||||||
|
+ err = intel_engine_cmd_parser(eb->ctx,
|
||||||
|
+ eb->engine,
|
||||||
|
eb->batch->obj,
|
||||||
|
- shadow_batch_obj,
|
||||||
|
+ batch_start,
|
||||||
|
eb->batch_start_offset,
|
||||||
|
- eb->batch_len);
|
||||||
|
+ eb->batch_len,
|
||||||
|
+ shadow_batch_obj,
|
||||||
|
+ shadow_batch_start);
|
||||||
|
+
|
||||||
|
if (err) {
|
||||||
|
+ i915_vma_unpin(vma);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Unsafe GGTT-backed buffers can still be submitted safely
|
||||||
|
* as non-secure.
|
||||||
|
@@ -1950,12 +1966,9 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
vma = NULL;
|
||||||
|
else
|
||||||
|
vma = ERR_PTR(err);
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
|
||||||
|
- vma = shadow_batch_pin(eb, shadow_batch_obj);
|
||||||
|
- if (IS_ERR(vma))
|
||||||
|
goto out;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
eb->vma[eb->buffer_count] = i915_vma_get(vma);
|
||||||
|
eb->flags[eb->buffer_count] =
|
||||||
|
@@ -1964,7 +1977,12 @@ static struct i915_vma *eb_parse(struct
|
||||||
|
eb->buffer_count++;
|
||||||
|
eb->batch_start_offset = 0;
|
||||||
|
eb->batch = vma;
|
||||||
|
+
|
||||||
|
/* eb->batch_len unchanged */
|
||||||
|
+
|
||||||
|
+ if (CMDPARSER_USES_GGTT(eb->i915))
|
||||||
|
+ eb->batch_flags |= I915_DISPATCH_SECURE;
|
||||||
|
+
|
||||||
|
out:
|
||||||
|
i915_gem_object_unpin_pages(shadow_batch_obj);
|
||||||
|
return vma;
|
37
debian/patches/bugfix/x86/i915/0010-drm-i915-cmdparser-Ignore-Length-operands-during-com.patch
vendored
Normal file
37
debian/patches/bugfix/x86/i915/0010-drm-i915-cmdparser-Ignore-Length-operands-during-com.patch
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
From: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Date: Thu, 20 Sep 2018 09:45:10 -0700
|
||||||
|
Subject: drm/i915/cmdparser: Ignore Length operands during command matching
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0155
|
||||||
|
|
||||||
|
commit 926abff21a8f29ef159a3ac893b05c6e50e043c3 upstream.
|
||||||
|
|
||||||
|
Some of the gen instruction macros (e.g. MI_DISPLAY_FLIP) have the
|
||||||
|
length directly encoded in them. Since these are used directly in
|
||||||
|
the tables, the Length becomes part of the comparison used for
|
||||||
|
matching during parsing. Thus, if the cmd being parsed has a
|
||||||
|
different length to that in the table, it is not matched and the
|
||||||
|
cmd is accepted via the default variable length path.
|
||||||
|
|
||||||
|
Fix by masking out everything except the Opcode in the cmd tables
|
||||||
|
|
||||||
|
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: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
Reviewed-by: Chris Wilson <chris.p.wilson@intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
|
||||||
|
@@ -187,7 +187,7 @@ struct drm_i915_cmd_table {
|
||||||
|
#define CMD(op, opm, f, lm, fl, ...) \
|
||||||
|
{ \
|
||||||
|
.flags = (fl) | ((f) ? CMD_DESC_FIXED : 0), \
|
||||||
|
- .cmd = { (op), ~0u << (opm) }, \
|
||||||
|
+ .cmd = { (op & ~0u << (opm)), ~0u << (opm) }, \
|
||||||
|
.length = { (lm) }, \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
}
|
72
debian/patches/bugfix/x86/i915/0011-drm-i915-Lower-RM-timeout-to-avoid-DSI-hard-hangs.patch
vendored
Normal file
72
debian/patches/bugfix/x86/i915/0011-drm-i915-Lower-RM-timeout-to-avoid-DSI-hard-hangs.patch
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
From: Uma Shankar <uma.shankar@intel.com>
|
||||||
|
Date: Tue, 7 Aug 2018 21:15:35 +0530
|
||||||
|
Subject: drm/i915: Lower RM timeout to avoid DSI hard hangs
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0154
|
||||||
|
|
||||||
|
commit 1d85a299c4db57c55e0229615132c964d17aa765 upstream.
|
||||||
|
|
||||||
|
In BXT/APL, device 2 MMIO reads from MIPI controller requires its PLL
|
||||||
|
to be turned ON. When MIPI PLL is turned off (MIPI Display is not
|
||||||
|
active or connected), and someone (host or GT engine) tries to read
|
||||||
|
MIPI registers, it causes hard hang. This is a hardware restriction
|
||||||
|
or limitation.
|
||||||
|
|
||||||
|
Driver by itself doesn't read MIPI registers when MIPI display is off.
|
||||||
|
But any userspace application can submit unprivileged batch buffer for
|
||||||
|
execution. In that batch buffer there can be mmio reads. And these
|
||||||
|
reads are allowed even for unprivileged applications. If these
|
||||||
|
register reads are for MIPI DSI controller and MIPI display is not
|
||||||
|
active during that time, then the MMIO read operation causes system
|
||||||
|
hard hang and only way to recover is hard reboot. A genuine
|
||||||
|
process/application won't submit batch buffer like this and doesn't
|
||||||
|
cause any issue. But on a compromised system, a malign userspace
|
||||||
|
process/app can generate such batch buffer and can trigger system
|
||||||
|
hard hang (denial of service attack).
|
||||||
|
|
||||||
|
The fix is to lower the internal MMIO timeout value to an optimum
|
||||||
|
value of 950us as recommended by hardware team. If the timeout is
|
||||||
|
beyond 1ms (which will hit for any value we choose if MMIO READ on a
|
||||||
|
DSI specific register is performed without PLL ON), it causes the
|
||||||
|
system hang. But if the timeout value is lower than it will be below
|
||||||
|
the threshold (even if timeout happens) and system will not get into
|
||||||
|
a hung state. This will avoid a system hang without losing any
|
||||||
|
programming or GT interrupts, taking the worst case of lowest CDCLK
|
||||||
|
frequency and early DC5 abort into account.
|
||||||
|
|
||||||
|
Signed-off-by: Uma Shankar <uma.shankar@intel.com>
|
||||||
|
Reviewed-by: Jon Bloomfield <jon.bloomfield@intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_reg.h | 4 ++++
|
||||||
|
drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++
|
||||||
|
2 files changed, 12 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_reg.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
||||||
|
@@ -7009,6 +7009,10 @@ enum {
|
||||||
|
#define SKL_CSR_DC5_DC6_COUNT _MMIO(0x8002C)
|
||||||
|
#define BXT_CSR_DC3_DC5_COUNT _MMIO(0x80038)
|
||||||
|
|
||||||
|
+/* Display Internal Timeout Register */
|
||||||
|
+#define RM_TIMEOUT _MMIO(0x42060)
|
||||||
|
+#define MMIO_TIMEOUT_US(us) ((us) << 0)
|
||||||
|
+
|
||||||
|
/* interrupts */
|
||||||
|
#define DE_MASTER_IRQ_CONTROL (1 << 31)
|
||||||
|
#define DE_SPRITEB_FLIP_DONE (1 << 29)
|
||||||
|
--- a/drivers/gpu/drm/i915/intel_pm.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/intel_pm.c
|
||||||
|
@@ -114,6 +114,14 @@ static void bxt_init_clock_gating(struct
|
||||||
|
*/
|
||||||
|
I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
|
||||||
|
PWM1_GATING_DIS | PWM2_GATING_DIS);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Lower the display internal timeout.
|
||||||
|
+ * This is needed to avoid any hard hangs when DSI port PLL
|
||||||
|
+ * is off and a MMIO access is attempted by any privilege
|
||||||
|
+ * application, using batch buffers or any other means.
|
||||||
|
+ */
|
||||||
|
+ I915_WRITE(RM_TIMEOUT, MMIO_TIMEOUT_US(950));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void glk_init_clock_gating(struct drm_i915_private *dev_priv)
|
282
debian/patches/bugfix/x86/i915/0012-drm-i915-gen8-Add-RC6-CTX-corruption-WA.patch
vendored
Normal file
282
debian/patches/bugfix/x86/i915/0012-drm-i915-gen8-Add-RC6-CTX-corruption-WA.patch
vendored
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
From: Imre Deak <imre.deak@intel.com>
|
||||||
|
Date: Mon, 9 Jul 2018 18:24:27 +0300
|
||||||
|
Subject: drm/i915/gen8+: Add RC6 CTX corruption WA
|
||||||
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-0154
|
||||||
|
|
||||||
|
commit 7e34f4e4aad3fd34c02b294a3cf2321adf5b4438 upstream.
|
||||||
|
|
||||||
|
In some circumstances the RC6 context can get corrupted. We can detect
|
||||||
|
this and take the required action, that is disable RC6 and runtime PM.
|
||||||
|
The HW recovers from the corrupted state after a system suspend/resume
|
||||||
|
cycle, so detect the recovery and re-enable RC6 and runtime PM.
|
||||||
|
|
||||||
|
v2: rebase (Mika)
|
||||||
|
v3:
|
||||||
|
- Move intel_suspend_gt_powersave() to the end of the GEM suspend
|
||||||
|
sequence.
|
||||||
|
- Add commit message.
|
||||||
|
v4:
|
||||||
|
- Rebased on intel_uncore_forcewake_put(i915->uncore, ...) API
|
||||||
|
change.
|
||||||
|
v5: rebased on gem/gt split (Mika)
|
||||||
|
|
||||||
|
Signed-off-by: Imre Deak <imre.deak@intel.com>
|
||||||
|
Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
|
||||||
|
---
|
||||||
|
drivers/gpu/drm/i915/i915_drv.c | 3 +
|
||||||
|
drivers/gpu/drm/i915/i915_drv.h | 7 +-
|
||||||
|
drivers/gpu/drm/i915/i915_gem.c | 8 +++
|
||||||
|
drivers/gpu/drm/i915/i915_reg.h | 2 +
|
||||||
|
drivers/gpu/drm/i915/intel_drv.h | 3 +
|
||||||
|
drivers/gpu/drm/i915/intel_pm.c | 107 ++++++++++++++++++++++++++++++-
|
||||||
|
6 files changed, 126 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.c
|
||||||
|
@@ -1621,6 +1621,7 @@ static int i915_drm_suspend_late(struct
|
||||||
|
i915_gem_suspend_late(dev_priv);
|
||||||
|
|
||||||
|
intel_display_set_init_power(dev_priv, false);
|
||||||
|
+ i915_rc6_ctx_wa_suspend(dev_priv);
|
||||||
|
intel_uncore_suspend(dev_priv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1847,6 +1848,8 @@ static int i915_drm_resume_early(struct
|
||||||
|
else
|
||||||
|
intel_display_set_init_power(dev_priv, true);
|
||||||
|
|
||||||
|
+ i915_rc6_ctx_wa_resume(dev_priv);
|
||||||
|
+
|
||||||
|
intel_engines_sanitize(dev_priv);
|
||||||
|
|
||||||
|
enable_rpm_wakeref_asserts(dev_priv);
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_drv.h
|
||||||
|
@@ -801,6 +801,7 @@ struct intel_rps {
|
||||||
|
|
||||||
|
struct intel_rc6 {
|
||||||
|
bool enabled;
|
||||||
|
+ bool ctx_corrupted;
|
||||||
|
u64 prev_hw_residency[4];
|
||||||
|
u64 cur_residency[4];
|
||||||
|
};
|
||||||
|
@@ -2557,10 +2558,12 @@ intel_info(const struct drm_i915_private
|
||||||
|
/* Early gen2 have a totally busted CS tlb and require pinned batches. */
|
||||||
|
#define HAS_BROKEN_CS_TLB(dev_priv) (IS_I830(dev_priv) || IS_I845G(dev_priv))
|
||||||
|
|
||||||
|
+#define NEEDS_RC6_CTX_CORRUPTION_WA(dev_priv) \
|
||||||
|
+ (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) == 9)
|
||||||
|
+
|
||||||
|
/* WaRsDisableCoarsePowerGating:skl,cnl */
|
||||||
|
#define NEEDS_WaRsDisableCoarsePowerGating(dev_priv) \
|
||||||
|
- (IS_CANNONLAKE(dev_priv) || \
|
||||||
|
- IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv))
|
||||||
|
+ (IS_CANNONLAKE(dev_priv) || INTEL_GEN(dev_priv) == 9)
|
||||||
|
|
||||||
|
#define HAS_GMBUS_IRQ(dev_priv) (INTEL_GEN(dev_priv) >= 4)
|
||||||
|
#define HAS_GMBUS_BURST_READ(dev_priv) (INTEL_GEN(dev_priv) >= 10 || \
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_gem.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
||||||
|
@@ -174,6 +174,11 @@ static u32 __i915_gem_park(struct drm_i9
|
||||||
|
if (INTEL_GEN(i915) >= 6)
|
||||||
|
gen6_rps_idle(i915);
|
||||||
|
|
||||||
|
+ if (NEEDS_RC6_CTX_CORRUPTION_WA(i915)) {
|
||||||
|
+ i915_rc6_ctx_wa_check(i915);
|
||||||
|
+ intel_uncore_forcewake_put(i915, FORCEWAKE_ALL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ);
|
||||||
|
|
||||||
|
intel_runtime_pm_put(i915);
|
||||||
|
@@ -220,6 +225,9 @@ void i915_gem_unpark(struct drm_i915_pri
|
||||||
|
*/
|
||||||
|
intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ);
|
||||||
|
|
||||||
|
+ if (NEEDS_RC6_CTX_CORRUPTION_WA(i915))
|
||||||
|
+ intel_uncore_forcewake_get(i915, FORCEWAKE_ALL);
|
||||||
|
+
|
||||||
|
i915->gt.awake = true;
|
||||||
|
if (unlikely(++i915->gt.epoch == 0)) /* keep 0 as invalid */
|
||||||
|
i915->gt.epoch = 1;
|
||||||
|
--- a/drivers/gpu/drm/i915/i915_reg.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
||||||
|
@@ -387,6 +387,8 @@ static inline bool i915_mmio_reg_valid(i
|
||||||
|
#define ECOCHK_PPGTT_WT_HSW (0x2 << 3)
|
||||||
|
#define ECOCHK_PPGTT_WB_HSW (0x3 << 3)
|
||||||
|
|
||||||
|
+#define GEN8_RC6_CTX_INFO _MMIO(0x8504)
|
||||||
|
+
|
||||||
|
#define GAC_ECO_BITS _MMIO(0x14090)
|
||||||
|
#define ECOBITS_SNB_BIT (1 << 13)
|
||||||
|
#define ECOBITS_PPGTT_CACHE64B (3 << 8)
|
||||||
|
--- a/drivers/gpu/drm/i915/intel_drv.h
|
||||||
|
+++ b/drivers/gpu/drm/i915/intel_drv.h
|
||||||
|
@@ -2064,6 +2064,9 @@ void intel_sanitize_gt_powersave(struct
|
||||||
|
void intel_enable_gt_powersave(struct drm_i915_private *dev_priv);
|
||||||
|
void intel_disable_gt_powersave(struct drm_i915_private *dev_priv);
|
||||||
|
void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv);
|
||||||
|
+bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915);
|
||||||
|
+void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915);
|
||||||
|
+void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915);
|
||||||
|
void gen6_rps_busy(struct drm_i915_private *dev_priv);
|
||||||
|
void gen6_rps_reset_ei(struct drm_i915_private *dev_priv);
|
||||||
|
void gen6_rps_idle(struct drm_i915_private *dev_priv);
|
||||||
|
--- a/drivers/gpu/drm/i915/intel_pm.c
|
||||||
|
+++ b/drivers/gpu/drm/i915/intel_pm.c
|
||||||
|
@@ -8196,6 +8196,95 @@ static void intel_init_emon(struct drm_i
|
||||||
|
dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static bool i915_rc6_ctx_corrupted(struct drm_i915_private *dev_priv)
|
||||||
|
+{
|
||||||
|
+ return !I915_READ(GEN8_RC6_CTX_INFO);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void i915_rc6_ctx_wa_init(struct drm_i915_private *i915)
|
||||||
|
+{
|
||||||
|
+ if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (i915_rc6_ctx_corrupted(i915)) {
|
||||||
|
+ DRM_INFO("RC6 context corrupted, disabling runtime power management\n");
|
||||||
|
+ i915->gt_pm.rc6.ctx_corrupted = true;
|
||||||
|
+ intel_runtime_pm_get(i915);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void i915_rc6_ctx_wa_cleanup(struct drm_i915_private *i915)
|
||||||
|
+{
|
||||||
|
+ if (i915->gt_pm.rc6.ctx_corrupted) {
|
||||||
|
+ intel_runtime_pm_put(i915);
|
||||||
|
+ i915->gt_pm.rc6.ctx_corrupted = false;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * i915_rc6_ctx_wa_suspend - system suspend sequence for the RC6 CTX WA
|
||||||
|
+ * @i915: i915 device
|
||||||
|
+ *
|
||||||
|
+ * Perform any steps needed to clean up the RC6 CTX WA before system suspend.
|
||||||
|
+ */
|
||||||
|
+void i915_rc6_ctx_wa_suspend(struct drm_i915_private *i915)
|
||||||
|
+{
|
||||||
|
+ if (i915->gt_pm.rc6.ctx_corrupted)
|
||||||
|
+ intel_runtime_pm_put(i915);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * i915_rc6_ctx_wa_resume - system resume sequence for the RC6 CTX WA
|
||||||
|
+ * @i915: i915 device
|
||||||
|
+ *
|
||||||
|
+ * Perform any steps needed to re-init the RC6 CTX WA after system resume.
|
||||||
|
+ */
|
||||||
|
+void i915_rc6_ctx_wa_resume(struct drm_i915_private *i915)
|
||||||
|
+{
|
||||||
|
+ if (!i915->gt_pm.rc6.ctx_corrupted)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (i915_rc6_ctx_corrupted(i915)) {
|
||||||
|
+ intel_runtime_pm_get(i915);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ DRM_INFO("RC6 context restored, re-enabling runtime power management\n");
|
||||||
|
+ i915->gt_pm.rc6.ctx_corrupted = false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void intel_disable_rc6(struct drm_i915_private *dev_priv);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * i915_rc6_ctx_wa_check - check for a new RC6 CTX corruption
|
||||||
|
+ * @i915: i915 device
|
||||||
|
+ *
|
||||||
|
+ * Check if an RC6 CTX corruption has happened since the last check and if so
|
||||||
|
+ * disable RC6 and runtime power management.
|
||||||
|
+ *
|
||||||
|
+ * Return false if no context corruption has happened since the last call of
|
||||||
|
+ * this function, true otherwise.
|
||||||
|
+*/
|
||||||
|
+bool i915_rc6_ctx_wa_check(struct drm_i915_private *i915)
|
||||||
|
+{
|
||||||
|
+ if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ if (i915->gt_pm.rc6.ctx_corrupted)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ if (!i915_rc6_ctx_corrupted(i915))
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ DRM_NOTE("RC6 context corruption, disabling runtime power management\n");
|
||||||
|
+
|
||||||
|
+ intel_disable_rc6(i915);
|
||||||
|
+ i915->gt_pm.rc6.ctx_corrupted = true;
|
||||||
|
+ intel_runtime_pm_get_noresume(i915);
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
struct intel_rps *rps = &dev_priv->gt_pm.rps;
|
||||||
|
@@ -8211,6 +8300,8 @@ void intel_init_gt_powersave(struct drm_
|
||||||
|
|
||||||
|
mutex_lock(&dev_priv->pcu_lock);
|
||||||
|
|
||||||
|
+ i915_rc6_ctx_wa_init(dev_priv);
|
||||||
|
+
|
||||||
|
/* Initialize RPS limits (for userspace) */
|
||||||
|
if (IS_CHERRYVIEW(dev_priv))
|
||||||
|
cherryview_init_gt_powersave(dev_priv);
|
||||||
|
@@ -8257,6 +8348,8 @@ void intel_cleanup_gt_powersave(struct d
|
||||||
|
if (IS_VALLEYVIEW(dev_priv))
|
||||||
|
valleyview_cleanup_gt_powersave(dev_priv);
|
||||||
|
|
||||||
|
+ i915_rc6_ctx_wa_cleanup(dev_priv);
|
||||||
|
+
|
||||||
|
if (!HAS_RC6(dev_priv))
|
||||||
|
intel_runtime_pm_put(dev_priv);
|
||||||
|
}
|
||||||
|
@@ -8301,7 +8394,7 @@ static inline void intel_disable_llc_pst
|
||||||
|
i915->gt_pm.llc_pstate.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void intel_disable_rc6(struct drm_i915_private *dev_priv)
|
||||||
|
+static void __intel_disable_rc6(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
lockdep_assert_held(&dev_priv->pcu_lock);
|
||||||
|
|
||||||
|
@@ -8320,6 +8413,13 @@ static void intel_disable_rc6(struct drm
|
||||||
|
dev_priv->gt_pm.rc6.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void intel_disable_rc6(struct drm_i915_private *dev_priv)
|
||||||
|
+{
|
||||||
|
+ mutex_lock(&dev_priv->pcu_lock);
|
||||||
|
+ __intel_disable_rc6(dev_priv);
|
||||||
|
+ mutex_unlock(&dev_priv->pcu_lock);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void intel_disable_rps(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
lockdep_assert_held(&dev_priv->pcu_lock);
|
||||||
|
@@ -8345,7 +8445,7 @@ void intel_disable_gt_powersave(struct d
|
||||||
|
{
|
||||||
|
mutex_lock(&dev_priv->pcu_lock);
|
||||||
|
|
||||||
|
- intel_disable_rc6(dev_priv);
|
||||||
|
+ __intel_disable_rc6(dev_priv);
|
||||||
|
intel_disable_rps(dev_priv);
|
||||||
|
if (HAS_LLC(dev_priv))
|
||||||
|
intel_disable_llc_pstate(dev_priv);
|
||||||
|
@@ -8372,6 +8472,9 @@ static void intel_enable_rc6(struct drm_
|
||||||
|
if (dev_priv->gt_pm.rc6.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ if (dev_priv->gt_pm.rc6.ctx_corrupted)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
if (IS_CHERRYVIEW(dev_priv))
|
||||||
|
cherryview_enable_rc6(dev_priv);
|
||||||
|
else if (IS_VALLEYVIEW(dev_priv))
|
|
@ -284,6 +284,18 @@ bugfix/x86/itlb_multihit/0023-KVM-vmx-svm-always-run-with-EFER.NXE-1-when-shadow
|
||||||
bugfix/x86/itlb_multihit/0024-kvm-mmu-ITLB_MULTIHIT-mitigation.patch
|
bugfix/x86/itlb_multihit/0024-kvm-mmu-ITLB_MULTIHIT-mitigation.patch
|
||||||
bugfix/x86/itlb_multihit/0025-kvm-Add-helper-function-for-creating-VM-worker-threa.patch
|
bugfix/x86/itlb_multihit/0025-kvm-Add-helper-function-for-creating-VM-worker-threa.patch
|
||||||
bugfix/x86/itlb_multihit/0026-kvm-x86-mmu-Recovery-of-shattered-NX-large-pages.patch
|
bugfix/x86/itlb_multihit/0026-kvm-x86-mmu-Recovery-of-shattered-NX-large-pages.patch
|
||||||
|
bugfix/x86/i915/0001-drm-i915-Rename-gen7-cmdparser-tables.patch
|
||||||
|
bugfix/x86/i915/0002-drm-i915-Disable-Secure-Batches-for-gen6.patch
|
||||||
|
bugfix/x86/i915/0003-drm-i915-Remove-Master-tables-from-cmdparser.patch
|
||||||
|
bugfix/x86/i915/0004-drm-i915-Add-support-for-mandatory-cmdparsing.patch
|
||||||
|
bugfix/x86/i915/0005-drm-i915-Support-ro-ppgtt-mapped-cmdparser-shadow-bu.patch
|
||||||
|
bugfix/x86/i915/0006-drm-i915-Allow-parsing-of-unsized-batches.patch
|
||||||
|
bugfix/x86/i915/0007-drm-i915-Add-gen9-BCS-cmdparsing.patch
|
||||||
|
bugfix/x86/i915/0008-drm-i915-cmdparser-Use-explicit-goto-for-error-paths.patch
|
||||||
|
bugfix/x86/i915/0009-drm-i915-cmdparser-Add-support-for-backward-jumps.patch
|
||||||
|
bugfix/x86/i915/0010-drm-i915-cmdparser-Ignore-Length-operands-during-com.patch
|
||||||
|
bugfix/x86/i915/0011-drm-i915-Lower-RM-timeout-to-avoid-DSI-hard-hangs.patch
|
||||||
|
bugfix/x86/i915/0012-drm-i915-gen8-Add-RC6-CTX-corruption-WA.patch
|
||||||
|
|
||||||
# ABI maintenance
|
# ABI maintenance
|
||||||
debian/abi/powerpc-avoid-abi-change-for-disabling-tm.patch
|
debian/abi/powerpc-avoid-abi-change-for-disabling-tm.patch
|
||||||
|
|
Loading…
Reference in New Issue