diff --git a/Makefile.am b/Makefile.am
index 94250964..e139bb44 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,7 +21,7 @@
 
 ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
 
-SUBDIRS = lib tools scripts benchmarks
+SUBDIRS = lib tools scripts benchmarks cve
 
 if BUILD_TESTS
 SUBDIRS += tests
diff --git a/configure.ac b/configure.ac
index f9e4942e..23fd9f30 100644
--- a/configure.ac
+++ b/configure.ac
@@ -311,6 +311,7 @@ AC_CONFIG_FILES([
 		 tools/null_state_gen/Makefile
 		 tools/registers/Makefile
 		 overlay/Makefile
+		 cve/Makefile
 		 ])
 
 AC_CONFIG_FILES([tools/intel_aubdump], [chmod +x tools/intel_aubdump])
diff --git a/cve/Makefile.am b/cve/Makefile.am
new file mode 100644
index 00000000..b8419ecd
--- /dev/null
+++ b/cve/Makefile.am
@@ -0,0 +1,14 @@
+include Makefile.sources
+
+cve_PROGRAMS = $(cve_prog_list)
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/include/drm-uapi \
+	-I$(top_srcdir)/lib \
+	-I$(top_srcdir)/lib/stubs/syscalls
+
+AM_CFLAGS = -I$(top_srcdir)/include/drm-uapi \
+	    $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(LIBUNWIND_CFLAGS) \
+	    $(WERROR_CFLAGS) -D_GNU_SOURCE
+LDADD = $(top_builddir)/lib/libintel_tools.la
diff --git a/cve/Makefile.sources b/cve/Makefile.sources
new file mode 100644
index 00000000..2b02f958
--- /dev/null
+++ b/cve/Makefile.sources
@@ -0,0 +1,5 @@
+cvedir=$(libexecdir)/igt-gpu-tools/cve
+
+cve_prog_list =				\	
+	cve-2019-0155
+	$(NULL)
diff --git a/cve/cve-2019-0155.c b/cve/cve-2019-0155.c
new file mode 100644
index 00000000..5f6ca60a
--- /dev/null
+++ b/cve/cve-2019-0155.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Can be compiled with:
+ * gcc -Wall -static -o cve-2019-0155 cve-2019-0155.c
+*/
+
+#define VERSION 1
+#define CHECK_WRITE_BLOCK_WITHOUT_PARSER 0
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define ASSERT(x, s) do {	\
+	if (!(x)) { \
+		printf("Failed to %s, %s (%d)\n", (s), \
+			       strerror(errno), errno);	\
+		exit(EXIT_FAILURE); \
+		} \
+	} while(0)
+
+static int do_ioctl(const int fd, const unsigned long nr, void *arg)
+{
+	int ret;
+
+	do
+		ret = ioctl(fd, nr, arg);
+	while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+	return ret;
+}
+
+static int is_driver_i915(const int fd)
+{
+	struct _drm_version {
+		int version_major;
+		int version_minor;
+		int version_patchlevel;
+
+		size_t name_len;
+		char *name;
+		size_t date_len;
+		char *date;
+		size_t desc_len;
+		char *desc;
+	} v = { 0, };
+	char name[256] = { 0, };
+	int ret;
+
+	v.name_len = sizeof(name) - 1;
+	v.name = name;
+
+	ret = do_ioctl(fd, _IOWR(0x40, 0x00, struct _drm_version), &v);
+	ASSERT(ret == 0, "get name");
+
+	name[v.name_len] = 0;
+
+	return !strcmp(name, "i915");
+}
+
+static int cmd_parser_version(const int fd)
+{
+	int ret, version = 0;
+	struct _drm_i915_getparam_t {
+		int32_t param;
+		uint64_t value;
+	} q = { 28,
+		(uint64_t)&version };
+
+	ret = do_ioctl(fd, _IOWR(0x40, 0x40 + 0x06, struct _drm_i915_getparam_t), &q);
+	ASSERT(ret == 0, "get param");
+
+	return version;
+}
+
+#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags))
+#define MI_BATCH_BUFFER_END     MI_INSTR(0x0a, 0)
+#define MI_LOAD_REGISTER_IMM    MI_INSTR(0x22, (3-2))
+
+static int is_write_blocked(const int fd)
+{
+	int ret;
+	uint32_t handle;
+
+	struct _drm_i915_gem_execbuffer2 {
+		uint64_t buffers_ptr;
+		uint32_t buffer_count;
+		uint32_t batch_start_offset;
+		uint32_t batch_len;
+		uint32_t DR1;
+		uint32_t DR4;
+		uint32_t num_cliprects;
+		uint64_t cliprects_ptr;
+		uint64_t flags;
+		uint64_t rsvd1;
+		uint64_t rsvd2;
+	} execbuf = { 0, };
+
+	struct _drm_i915_gem_exec_object2 {
+		uint32_t handle;
+		uint32_t relocation_count;
+		uint64_t relocs_ptr;
+		uint64_t alignment;
+		uint64_t offset;
+		uint64_t flags;
+		uint64_t rsvd1;
+		uint64_t rsvd2;
+	} execobj[1] = { { 0, } };
+
+	struct _drm_i915_gem_create {
+		uint64_t size;
+		uint32_t handle;
+		uint32_t pad;
+	} createobj = { 0, };
+
+	struct _drm_i915_gem_pwrite {
+		uint32_t handle;
+		uint32_t pad;
+		uint64_t offset;
+		uint64_t size;
+		uint64_t data_ptr;
+	} pwrite = { 0, };
+
+	const uint32_t batch[] = {
+		MI_LOAD_REGISTER_IMM,
+		0x2221c,
+		0x0,
+		0,
+		MI_BATCH_BUFFER_END,
+	};
+
+	createobj.handle = 0;
+	createobj.size = 4096;
+
+	ret = do_ioctl(fd, _IOWR(0x40, 0x40+0x1b, struct _drm_i915_gem_create), &createobj);
+	ASSERT(ret == 0, "create object");
+
+	handle = createobj.handle;
+
+	pwrite.handle = handle;
+	pwrite.size = sizeof(batch);
+	pwrite.data_ptr = (uintptr_t)batch;
+
+	ret = do_ioctl(fd, _IOWR(0x40, 0x40+0x1d, struct _drm_i915_gem_pwrite), &pwrite);
+	ASSERT(ret == 0, "write object");
+
+	execobj[0].handle = handle;
+
+	execbuf.buffers_ptr = (uintptr_t)execobj;
+	execbuf.buffer_count = 1;
+	execbuf.flags = 3; /* select blitter engine (bcs0) */
+
+	ret = do_ioctl(fd, _IOWR(0x40, 0x40+0x29, struct _drm_i915_gem_execbuffer2), &execbuf);
+	if (ret) {
+		if (errno == EACCES || errno == EINVAL)
+			return 1;
+	}
+
+	return 0;
+}
+
+#define INTEL_VGA_DEVICE(x, y) (x)
+
+static const uint32_t gen9_ids[] = {
+
+	INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */
+
+	INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */
+
+	INTEL_VGA_DEVICE(0x1902, info), /* DT  GT1 */
+	INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */
+	INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */
+
+	INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */
+	INTEL_VGA_DEVICE(0x1921, info),  /* ULT GT2F */
+
+	INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */
+
+	INTEL_VGA_DEVICE(0x1912, info), /* DT  GT2 */
+	INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */
+	INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */
+	INTEL_VGA_DEVICE(0x191D, info),  /* WKS GT2 */
+
+	INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */
+
+	INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */
+	INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */
+	INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */
+	INTEL_VGA_DEVICE(0x192D, info),  /* SRV GT3 */
+
+	INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */
+	INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */
+	INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */
+	INTEL_VGA_DEVICE(0x192A, info), /* SRV GT4 */
+	INTEL_VGA_DEVICE(0x193A, info),  /* SRV GT4e */
+
+	INTEL_VGA_DEVICE(0x0A84, info),
+	INTEL_VGA_DEVICE(0x1A84, info),
+	INTEL_VGA_DEVICE(0x1A85, info),
+	INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */
+	INTEL_VGA_DEVICE(0x5A85, info),  /* APL HD Graphics 500 */
+
+	INTEL_VGA_DEVICE(0x3184, info),
+	INTEL_VGA_DEVICE(0x3185, info),
+
+	INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */
+	INTEL_VGA_DEVICE(0x5913, info),  /* ULT GT1.5 */
+
+	INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */
+	INTEL_VGA_DEVICE(0x5915, info),  /* ULX GT1.5 */
+
+	INTEL_VGA_DEVICE(0x5902, info), /* DT  GT1 */
+	INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */
+	INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */
+	INTEL_VGA_DEVICE(0x590A, info), /* SRV GT1 */
+
+	INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */
+	INTEL_VGA_DEVICE(0x5921, info),  /* ULT GT2F */
+
+	INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */
+
+	INTEL_VGA_DEVICE(0x5917, info), /* Mobile GT2 */
+	INTEL_VGA_DEVICE(0x5912, info), /* DT  GT2 */
+	INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */
+	INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */
+	INTEL_VGA_DEVICE(0x591D, info), /* WKS GT2 */
+
+	INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */
+
+	INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */
+	INTEL_VGA_DEVICE(0x5927, info), /* ULT GT3 */
+
+	INTEL_VGA_DEVICE(0x593B, info), /* Halo GT4 */
+
+	INTEL_VGA_DEVICE(0x591C, info),  /* ULX GT2 */
+	INTEL_VGA_DEVICE(0x87C0, info), /* ULX GT2 */
+
+	INTEL_VGA_DEVICE(0x87CA, info),
+
+	INTEL_VGA_DEVICE(0x9B21, info),
+	INTEL_VGA_DEVICE(0x9BAA, info),
+	INTEL_VGA_DEVICE(0x9BAB, info),
+	INTEL_VGA_DEVICE(0x9BAC, info),
+	INTEL_VGA_DEVICE(0x9BA0, info),
+	INTEL_VGA_DEVICE(0x9BA5, info),
+	INTEL_VGA_DEVICE(0x9BA8, info),
+	INTEL_VGA_DEVICE(0x9BA4, info),
+	INTEL_VGA_DEVICE(0x9BA2, info),
+
+	INTEL_VGA_DEVICE(0x9B41, info),
+	INTEL_VGA_DEVICE(0x9BCA, info),
+	INTEL_VGA_DEVICE(0x9BCB, info),
+	INTEL_VGA_DEVICE(0x9BCC, info),
+	INTEL_VGA_DEVICE(0x9BC0, info),
+	INTEL_VGA_DEVICE(0x9BC5, info),
+	INTEL_VGA_DEVICE(0x9BC8, info),
+	INTEL_VGA_DEVICE(0x9BC4, info),
+	INTEL_VGA_DEVICE(0x9BC2, info),
+	INTEL_VGA_DEVICE(0x9BC6, info),
+	INTEL_VGA_DEVICE(0x9BE6, info),
+	INTEL_VGA_DEVICE(0x9BF6, info),
+
+	INTEL_VGA_DEVICE(0x3E90, info), /* SRV GT1 */
+	INTEL_VGA_DEVICE(0x3E93, info), /* SRV GT1 */
+	INTEL_VGA_DEVICE(0x3E99, info),  /* SRV GT1 */
+
+	INTEL_VGA_DEVICE(0x3E91, info), /* SRV GT2 */
+	INTEL_VGA_DEVICE(0x3E92, info), /* SRV GT2 */
+	INTEL_VGA_DEVICE(0x3E96, info), /* SRV GT2 */
+	INTEL_VGA_DEVICE(0x3E98, info), /* SRV GT2 */
+	INTEL_VGA_DEVICE(0x3E9A, info),  /* SRV GT2 */
+
+	INTEL_VGA_DEVICE(0x3E9C, info),
+
+	INTEL_VGA_DEVICE(0x3E9B, info), /* Halo GT2 */
+	INTEL_VGA_DEVICE(0x3E94, info),  /* Halo GT2 */
+
+	INTEL_VGA_DEVICE(0x3EA9, info),
+
+	INTEL_VGA_DEVICE(0x3EA5, info), /* ULT GT3 */
+	INTEL_VGA_DEVICE(0x3EA6, info), /* ULT GT3 */
+	INTEL_VGA_DEVICE(0x3EA7, info), /* ULT GT3 */
+	INTEL_VGA_DEVICE(0x3EA8, info), /* ULT GT3 */
+
+	INTEL_VGA_DEVICE(0x3EA1, info),
+	INTEL_VGA_DEVICE(0x3EA4, info),
+
+	INTEL_VGA_DEVICE(0x3EA0, info),
+	INTEL_VGA_DEVICE(0x3EA3, info),
+
+	INTEL_VGA_DEVICE(0x3EA2, info),
+};
+
+static int is_platform_gen9(void)
+{
+	const char * const id_file =
+		"/sys/bus/pci/drivers/i915/0000:00:02.0/device";
+	char idstr[32] = {0, };
+	uint32_t id = 0;
+	int fd, ret, i;
+
+	fd = open(id_file, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	ret = read(fd, idstr, 6);
+	if (ret != 6)
+		return -1;
+
+	close(fd);
+
+	idstr[6] = 0;
+
+	id = strtol(idstr, NULL, 16);
+
+	for (i = 0; i < sizeof(gen9_ids)/sizeof(uint32_t); i++)
+		if (id == gen9_ids[i])
+			return 1;
+
+	return 0;
+}
+
+static int is_fd_safe(const int fd)
+{
+	int parser_version = -1;
+	int write_block = 0;
+
+	parser_version = cmd_parser_version(fd);
+	printf("  Command parser version: %d\n", parser_version);
+	if (parser_version >= 10) {
+		printf("  Command parsing for blt engine supported\n");
+	} else if (!CHECK_WRITE_BLOCK_WITHOUT_PARSER) {
+		printf("  There is no blitter command parser\n");
+		return 0;
+	}
+
+	write_block = is_write_blocked(fd);
+
+	printf("  Unsafe write %s\n", write_block ? "blocked" : "possible!");
+
+	return write_block;
+}
+
+struct stats {
+	int checked;
+	int safe;
+	int failed;
+};
+
+static void check_path(const char *path, struct stats *stats)
+{
+	int fd;
+	int is_safe;
+
+	fd = open(path, O_RDWR);
+	if (fd == -1) {
+		if (errno != ENOENT) {
+			printf("Opening %s failed with %s (%d)\n",
+			       path, strerror(errno), errno);
+			stats->failed++;
+		}
+
+		return;
+	}
+
+	if (!is_driver_i915(fd)) {
+		close(fd);
+		return;
+	}
+
+	printf("Checking %s:\n", path);
+
+	is_safe = is_fd_safe(fd);
+	printf("  Device %s : %s\n\n", path, is_safe ? "SAFE" : "VULNERABLE");
+	if (is_safe)
+		stats->safe++;
+
+	stats->checked++;
+
+	close (fd);
+}
+
+static int check_devices(void)
+{
+	const char * const cardbase = "/dev/dri/card";
+	const char * const renderbase = "/dev/dri/renderD";
+	char path[256];
+	int i;
+	struct stats s = { 0, 0, 0 };
+
+	for (i = 0; i < 16; i++) {
+		sprintf(path, "%s%d", cardbase, i);
+		check_path(path, &s);
+
+		sprintf(path, "%s%d", renderbase, i + 128);
+		check_path(path, &s);
+	}
+
+	if (s.failed && !s.checked) {
+		printf("Failed to open devices, need root?\n");
+		return -1;
+	}
+
+	if (!s.checked) {
+		printf ("Didn't find anything to check\n");
+		return -1;
+	}
+
+	return s.checked == s.safe;
+}
+
+int main(int argc, char *argv[])
+{
+	int safe = 0;
+	int ret;
+
+	printf("Intel cve-2019-0155 (blt mmio vulnerability) checker version %d\n\n", VERSION);
+
+	sync();
+
+	ret = is_platform_gen9();
+	if (ret == 0) {
+		safe = 1;
+		printf("Your platform is not affected\n");
+	} else if (ret == -1) {
+		printf("Unable to determine platform type\n");
+	}
+
+	if (safe != 1)
+		safe = check_devices();
+
+	if (safe < 0) {
+		printf("Unable to determine system state due to errors\n");
+		return EXIT_FAILURE;
+	}
+
+	printf("\nYour system is %s against cve-2019-0155\n", safe ? "SAFE" : "VULNERABLE");
+
+	return safe ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/cve/meson.build b/cve/meson.build
new file mode 100644
index 00000000..990181c6
--- /dev/null
+++ b/cve/meson.build
@@ -0,0 +1,12 @@
+cve_progs = [
+	'cve-2019-0155',
+]
+
+cvedir = join_paths(libexecdir, 'cve')
+
+foreach prog : cve_progs
+	executable(prog, prog + '.c',
+		   install : true,
+		   install_dir : cvedir,
+		   dependencies : igt_deps)
+endforeach
diff --git a/meson.build b/meson.build
index 4d5003ba..27ad9567 100644
--- a/meson.build
+++ b/meson.build
@@ -302,6 +302,7 @@ if libdrm_intel.found()
 endif
 subdir('overlay')
 subdir('man')
+subdir('cve')
 
 gtk_doc = dependency('gtk-doc', required : build_docs)
 python3 = find_program('python3', required : build_docs)
