All of lore.kernel.org
 help / color / mirror / Atom feed
* [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor
@ 2017-12-24 10:07 Arbel Moshe
  2017-12-24 10:07 ` [PATCH 1/5] x86: Add utility to run function in User Mode Arbel Moshe
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Arbel Moshe @ 2017-12-24 10:07 UTC (permalink / raw)
  To: pbonzini, rkrcmar, kvm; +Cc: idan.brown, liran.alon

Hi,
This series adds a set of unit tests to series:
"KVM: x86: Add support for VMware backdoor I/O ports & Pseduo-PMCs"

The series is split into the following patches:
1. Add an x86 utility to run a function in User Mode.
2. Add a test utility to run a function in User Mode / Kernel Mode, catch an
exception, and run a callback to test function return value.
3. Add CR4 PCE bit definition.
4. Add x86_64 segment descriptor struct.
5. Add VMware backdoor tests:
Test VMware port and VMware RDPMC backdoors, both in user mode and kernel
mode.

Thanks,
Arbel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/5] x86: Add utility to run function in User Mode
  2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
@ 2017-12-24 10:07 ` Arbel Moshe
  2017-12-24 10:07 ` [PATCH 2/5] x86: Add Test Utility to run in User Mode and catch exceptions Arbel Moshe
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Arbel Moshe @ 2017-12-24 10:07 UTC (permalink / raw)
  To: pbonzini, rkrcmar, kvm
  Cc: idan.brown, liran.alon, Arbel Moshe, Konrad Rzeszutek Wilk

Add usermode util that enables running a function in user mode.
In addition, it enables catching an exception which is raised from
the user-mode function.

Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 lib/x86/usermode.c  | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/usermode.h  |  30 ++++++++++++++
 x86/Makefile.common |   1 +
 3 files changed, 144 insertions(+)
 create mode 100644 lib/x86/usermode.c
 create mode 100644 lib/x86/usermode.h

diff --git a/lib/x86/usermode.c b/lib/x86/usermode.c
new file mode 100644
index 0000000..323d84d
--- /dev/null
+++ b/lib/x86/usermode.c
@@ -0,0 +1,113 @@
+#include "x86/msr.h"
+#include "x86/processor.h"
+#include "x86/apic-defs.h"
+#include "x86/apic.h"
+#include "x86/desc.h"
+#include "x86/isr.h"
+#include "alloc.h"
+#include "setjmp.h"
+#include "usermode.h"
+
+#include "libcflat.h"
+#include <stdint.h>
+
+#define USERMODE_STACK_SIZE	0x2000
+#define RET_TO_KERNEL_IRQ	0x20
+
+jmp_buf jmpbuf;
+
+static void restore_exec_to_jmpbuf(void)
+{
+	longjmp(jmpbuf, 1);
+}
+
+static void restore_exec_to_jmpbuf_exception_handler(struct ex_regs *regs)
+{
+	/* longjmp must happen after iret, so do not do it now.  */
+	regs->rip = (unsigned long)&restore_exec_to_jmpbuf;
+	regs->cs = KERNEL_CS;
+}
+
+uint64_t run_in_user(usermode_func func, unsigned int fault_vector,
+		uint64_t arg1, uint64_t arg2, uint64_t arg3,
+		uint64_t arg4, bool *raised_vector)
+{
+	extern char ret_to_kernel;
+	uint64_t rax = 0;
+	static unsigned char user_stack[USERMODE_STACK_SIZE];
+
+	*raised_vector = 0;
+	set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3);
+	handle_exception(fault_vector,
+			restore_exec_to_jmpbuf_exception_handler);
+
+	if (setjmp(jmpbuf) != 0) {
+		*raised_vector = 1;
+		return 0;
+	}
+
+	asm volatile (
+			/* Backing Up Stack in rdi */
+			"mov %%rsp, %%rdi\n\t"
+			/* Load user_ds to DS and ES */
+			"mov %[user_ds], %%ax\n\t"
+			"mov %%ax, %%ds\n\t"
+			"mov %%ax, %%es\n\t"
+			/* IRET into user mode */
+			"pushq %[user_ds]\n\t"
+			"pushq %[user_stack_top]\n\t"
+			"pushfq\n\t"
+			"pushq %[user_cs]\n\t"
+			"pushq $user_mode\n\t"
+			"iretq\n"
+
+			"user_mode:\n\t"
+			/* Back up registers before invoking func */
+			"push %%rbx\n\t"
+			"push %%rcx\n\t"
+			"push %%rdx\n\t"
+			"push %%r8\n\t"
+			"push %%r9\n\t"
+			"push %%r10\n\t"
+			"push %%r11\n\t"
+			"push %%rdi\n\t"
+			"push %%rsi\n\t"
+			/* Call user mode function */
+			"mov %[arg1], %%rdi\n\t"
+			"mov %[arg2], %%rsi\n\t"
+			"mov %[arg3], %%rdx\n\t"
+			"mov %[arg4], %%rcx\n\t"
+			"call %[func]\n\t"
+			/* Restore registers */
+			"pop %%rsi\n\t"
+			"pop %%rdi\n\t"
+			"pop %%r11\n\t"
+			"pop %%r10\n\t"
+			"pop %%r9\n\t"
+			"pop %%r8\n\t"
+			"pop %%rdx\n\t"
+			"pop %%rcx\n\t"
+			"pop %%rbx\n\t"
+			/* Return to kernel via system call */
+			"int %[kernel_entry_vector]\n\t"
+			/* Kernel Mode */
+			"ret_to_kernel:\n\t"
+			"mov %%rdi, %%rsp\n\t"
+			:
+			"+a"(rax)
+			:
+			[arg1]"m"(arg1),
+			[arg2]"m"(arg2),
+			[arg3]"m"(arg3),
+			[arg4]"m"(arg4),
+			[func]"m"(func),
+			[user_ds]"i"(USER_DS),
+			[user_cs]"i"(USER_CS),
+			[user_stack_top]"r"(user_stack +
+					sizeof(user_stack)),
+			[kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ)
+			:
+			"rsi", "rdi", "rcx", "rdx");
+
+	return rax;
+}
diff --git a/lib/x86/usermode.h b/lib/x86/usermode.h
new file mode 100644
index 0000000..4e005e6
--- /dev/null
+++ b/lib/x86/usermode.h
@@ -0,0 +1,30 @@
+#ifndef _USERMODE_H_
+#define _USERMODE_H_
+
+#include "x86/msr.h"
+#include "x86/processor.h"
+#include "x86/apic-defs.h"
+#include "x86/apic.h"
+#include "x86/desc.h"
+#include "x86/isr.h"
+#include "alloc.h"
+#include "setjmp.h"
+
+#include "libcflat.h"
+#include <stdint.h>
+
+typedef uint64_t (*usermode_func)(void);
+
+/*
+ * Run function in user mode
+ * Supports running functions with up to 4 arguments.
+ * fault_vector: exception vector that might get thrown during the function.
+ * raised_vector: outputs true if exception occurred.
+ *
+ * returns: return value returned by function, or 0 if an exception occurred.
+ */
+uint64_t run_in_user(usermode_func func, unsigned int fault_vector,
+		uint64_t arg1, uint64_t arg2, uint64_t arg3,
+		uint64_t arg4, bool *raised_vector);
+
+#endif
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 5f7eac4..8a9d245 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -19,6 +19,7 @@ cflatobjs += lib/x86/desc.o
 cflatobjs += lib/x86/isr.o
 cflatobjs += lib/x86/acpi.o
 cflatobjs += lib/x86/stack.o
+cflatobjs += lib/x86/usermode.o
 
 OBJDIRS += lib/x86
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/5] x86: Add Test Utility to run in User Mode and catch exceptions
  2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
  2017-12-24 10:07 ` [PATCH 1/5] x86: Add utility to run function in User Mode Arbel Moshe
@ 2017-12-24 10:07 ` Arbel Moshe
  2017-12-24 10:07 ` [PATCH 3/5] x86: Add Definition for PCE bit in CR4 Arbel Moshe
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Arbel Moshe @ 2017-12-24 10:07 UTC (permalink / raw)
  To: pbonzini, rkrcmar, kvm
  Cc: idan.brown, liran.alon, Arbel Moshe, Konrad Rzeszutek Wilk

Add a test utility that enables:
1. Running test function in User Mode or Kernel Mode.
2. Catching an exception.
3. Running a callback function to test return val.

Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 lib/x86/fault_test.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/fault_test.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 x86/Makefile.common  |  1 +
 3 files changed, 95 insertions(+)
 create mode 100644 lib/x86/fault_test.c
 create mode 100644 lib/x86/fault_test.h

diff --git a/lib/x86/fault_test.c b/lib/x86/fault_test.c
new file mode 100644
index 0000000..71ac982
--- /dev/null
+++ b/lib/x86/fault_test.c
@@ -0,0 +1,52 @@
+#include "fault_test.h"
+
+jmp_buf jmpbuf;
+
+static void restore_exec_to_jmpbuf(void)
+{
+	longjmp(jmpbuf, 1);
+}
+
+static void fault_test_fault(struct ex_regs *regs)
+{
+	regs->rip = (unsigned long)&restore_exec_to_jmpbuf;
+}
+
+static bool fault_test(struct fault_test_arg *arg)
+{
+	uint64_t val;
+	bool raised_vector = false;
+	test_fault_func func = (test_fault_func) arg->func;
+	/* Init as success in case there isn't callback */
+	bool callback_success = true;
+
+	if (arg->usermode) {
+		val = run_in_user((usermode_func) func, arg->fault_vector,
+				arg->arg[0], arg->arg[1], arg->arg[2],
+				arg->arg[3], &raised_vector);
+	} else {
+		handle_exception(arg->fault_vector, fault_test_fault);
+		if (setjmp(jmpbuf) == 0)
+			val = func(arg->arg[0], arg->arg[1], arg->arg[2],
+					arg->arg[3]);
+		else
+			raised_vector = true;
+	}
+
+	if (!raised_vector) {
+		arg->retval = val;
+		if (arg->callback != NULL)
+			callback_success = arg->callback(arg);
+	}
+
+	return arg->should_fault ?
+		raised_vector : (!raised_vector && callback_success);
+}
+
+void test_run(struct fault_test *test)
+{
+	bool passed = fault_test(&(test->arg));
+
+	report("%s", passed, test->name);
+}
+
diff --git a/lib/x86/fault_test.h b/lib/x86/fault_test.h
new file mode 100644
index 0000000..dfa715b
--- /dev/null
+++ b/lib/x86/fault_test.h
@@ -0,0 +1,42 @@
+#ifndef __FAULT_TEST__
+#define __FAULT_TEST__
+
+#include "x86/msr.h"
+#include "x86/processor.h"
+#include "x86/apic-defs.h"
+#include "x86/apic.h"
+#include "x86/desc.h"
+#include "x86/isr.h"
+#include "alloc.h"
+#include "setjmp.h"
+#include "usermode.h"
+
+#include "libcflat.h"
+#include <stdint.h>
+
+#define FAULT_TEST(nm, a) { .name = nm, .arg = a}
+
+struct fault_test_arg;
+
+typedef uint64_t (*test_fault_func)(uint64_t arg1, uint64_t arg2,
+		uint64_t arg3, uint64_t arg4);
+typedef bool (*test_fault_callback)(struct fault_test_arg *arg);
+
+struct fault_test_arg {
+	bool usermode;
+	unsigned int fault_vector;
+	bool should_fault;
+	uint64_t arg[4];
+	uint64_t retval;
+	test_fault_func func;
+	test_fault_callback callback;
+};
+
+struct fault_test {
+	const char *name;
+	struct fault_test_arg arg;
+};
+
+void test_run(struct fault_test *test);
+
+#endif
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 8a9d245..cbd5847 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -20,6 +20,7 @@ cflatobjs += lib/x86/isr.o
 cflatobjs += lib/x86/acpi.o
 cflatobjs += lib/x86/stack.o
 cflatobjs += lib/x86/usermode.o
+cflatobjs += lib/x86/fault_test.o
 
 OBJDIRS += lib/x86
 
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/5] x86: Add Definition for PCE bit in CR4
  2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
  2017-12-24 10:07 ` [PATCH 1/5] x86: Add utility to run function in User Mode Arbel Moshe
  2017-12-24 10:07 ` [PATCH 2/5] x86: Add Test Utility to run in User Mode and catch exceptions Arbel Moshe
@ 2017-12-24 10:07 ` Arbel Moshe
  2017-12-24 10:08 ` [PATCH 4/5] x86: Add definition for 64 bit Segment descriptor Arbel Moshe
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Arbel Moshe @ 2017-12-24 10:07 UTC (permalink / raw)
  To: pbonzini, rkrcmar, kvm
  Cc: idan.brown, liran.alon, Arbel Moshe, Konrad Rzeszutek Wilk

Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 lib/x86/processor.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 2473862..e850029 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -27,6 +27,7 @@
 #define X86_CR4_PSE    0x00000010
 #define X86_CR4_PAE    0x00000020
 #define X86_CR4_MCE    0x00000040
+#define X86_CR4_PCE    0x00000100
 #define X86_CR4_VMXE   0x00002000
 #define X86_CR4_PCIDE  0x00020000
 #define X86_CR4_SMAP   0x00200000
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/5] x86: Add definition for 64 bit Segment descriptor
  2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
                   ` (2 preceding siblings ...)
  2017-12-24 10:07 ` [PATCH 3/5] x86: Add Definition for PCE bit in CR4 Arbel Moshe
@ 2017-12-24 10:08 ` Arbel Moshe
  2017-12-24 10:08 ` [PATCH 5/5] x86: Add VMware backdoor unit test Arbel Moshe
  2018-02-14 12:06 ` [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Paolo Bonzini
  5 siblings, 0 replies; 7+ messages in thread
From: Arbel Moshe @ 2017-12-24 10:08 UTC (permalink / raw)
  To: pbonzini, rkrcmar, kvm
  Cc: idan.brown, liran.alon, Arbel Moshe, Konrad Rzeszutek Wilk

Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 lib/x86/desc.h | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/lib/x86/desc.h b/lib/x86/desc.h
index 3bf8fbe..181b59e 100644
--- a/lib/x86/desc.h
+++ b/lib/x86/desc.h
@@ -167,6 +167,31 @@ typedef struct {
 	u8 base_high;
 } gdt_entry_t;
 
+struct segment_desc64 {
+	uint16_t limit1;
+	uint16_t base1;
+	uint8_t  base2;
+	union {
+		uint16_t  type_limit_flags;      /* Type and limit flags */
+		struct {
+			uint16_t type:4;
+			uint16_t s:1;
+			uint16_t dpl:2;
+			uint16_t p:1;
+			uint16_t limit:4;
+			uint16_t avl:1;
+			uint16_t l:1;
+			uint16_t db:1;
+			uint16_t g:1;
+		} __attribute__((__packed__));
+	} __attribute__((__packed__));
+	uint8_t  base3;
+	uint32_t base4;
+	uint32_t zero;
+} __attribute__((__packed__));
+
+#define DESC_BUSY ((uint64_t) 1 << 41)
+
 extern idt_entry_t boot_idt[256];
 
 #ifndef __x86_64__
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/5] x86: Add VMware backdoor unit test
  2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
                   ` (3 preceding siblings ...)
  2017-12-24 10:08 ` [PATCH 4/5] x86: Add definition for 64 bit Segment descriptor Arbel Moshe
@ 2017-12-24 10:08 ` Arbel Moshe
  2018-02-14 12:06 ` [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Paolo Bonzini
  5 siblings, 0 replies; 7+ messages in thread
From: Arbel Moshe @ 2017-12-24 10:08 UTC (permalink / raw)
  To: pbonzini, rkrcmar, kvm
  Cc: idan.brown, liran.alon, Arbel Moshe, Konrad Rzeszutek Wilk

Add VMware backdoors unit test.

VMware backdoors, is a PV interface VMware ESX and Workstation expose
to their running VMs, in order to better operate in a virtualized
environment.

There are 2 main backdoor mechanisms: I/O ports & Pseduo-PMCs.

VMware backdoor I/O ports: VMware expose a special I/O port which
sends/gives ParaVirtualize info. The I/O port is accessible from
User Mode, even if the TSS I/O permission bitmap states otherwise.

VMware backdoor Pseduo-PMCs: VMware exposes 3 Pseduo-PMCs to its
running VMS, that lets the VMs collect information regarding host time.
For more info, see:
www.vmware.com/files/pdf/techpaper/Timekeeping-In-VirtualMachines.pdf

This unit test tests the functionality of these backdoors. They are
tested both from User Mode and Kernel Mode, as they will be accessible
running on ESX.

Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 x86/Makefile.common    |   1 +
 x86/unittests.cfg      |   4 ++
 x86/vmware_backdoors.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 196 insertions(+)
 create mode 100644 x86/vmware_backdoors.c

diff --git a/x86/Makefile.common b/x86/Makefile.common
index cbd5847..f544636 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -56,6 +56,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \
                $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \
                $(TEST_DIR)/hyperv_connections.flat \
+               $(TEST_DIR)/vmware_backdoors.flat\
 
 ifdef API
 tests-api = api/api-sample api/dirty-log api/dirty-log-perf
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 91d1c75..5410177 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -150,6 +150,10 @@ file = pmu.flat
 extra_params = -cpu host
 check = /proc/sys/kernel/nmi_watchdog=0
 
+[vmware_backdoors]
+file = vmware_backdoors.flat
+extra_params = -machine vmport=on
+
 [port80]
 file = port80.flat
 
diff --git a/x86/vmware_backdoors.c b/x86/vmware_backdoors.c
new file mode 100644
index 0000000..f718f16
--- /dev/null
+++ b/x86/vmware_backdoors.c
@@ -0,0 +1,191 @@
+
+#include "x86/msr.h"
+#include "x86/processor.h"
+#include "x86/apic-defs.h"
+#include "x86/apic.h"
+#include "x86/desc.h"
+#include "x86/isr.h"
+#include "alloc.h"
+#include "setjmp.h"
+#include "usermode.h"
+#include "fault_test.h"
+
+#include "libcflat.h"
+#include <stdint.h>
+
+#define VMWARE_BACKDOOR_PMC_HOST_TSC           0x10000
+#define VMWARE_BACKDOOR_PMC_REAL_TIME          0x10001
+#define VMWARE_BACKDOOR_PMC_APPARENT_TIME      0x10002
+
+#define VMWARE_BACKDOOR_PORT	0x5658
+#define VMWARE_MAGIC		0x564D5868
+
+#define VMPORT_CMD_GETVERSION	0x0a
+#define VMPORT_CMD_ILLEGAL	0xfff
+
+#define VMPORT_DEFAULT_RETVAL	0xdeadbeef
+
+#define RANDOM_IO_PORT		0x1234
+
+struct backdoor_port_result {
+	uint64_t rax;
+	uint64_t rbx;
+	uint64_t rcx;
+	uint64_t rdx;
+};
+
+static bool vmware_backdoor_port_callback(struct fault_test_arg *arg)
+{
+	struct backdoor_port_result *res =
+		(struct backdoor_port_result *) arg->retval;
+
+	switch (arg->arg[2]) {
+	case VMPORT_CMD_GETVERSION:
+		return (res->rbx == VMWARE_MAGIC);
+	case VMPORT_CMD_ILLEGAL:
+		return (res->rbx == VMPORT_DEFAULT_RETVAL);
+	}
+	return false;
+}
+
+static uint64_t vmware_backdoor_port(uint64_t vmport, uint64_t vmport_magic,
+		uint64_t command)
+{
+	struct backdoor_port_result *res =
+		(struct backdoor_port_result *)
+		malloc(sizeof(struct backdoor_port_result));
+
+	res->rax = VMPORT_DEFAULT_RETVAL;
+	res->rbx = VMPORT_DEFAULT_RETVAL;
+	res->rcx = VMPORT_DEFAULT_RETVAL;
+	res->rdx = VMPORT_DEFAULT_RETVAL;
+
+	asm volatile(
+		"mov %[rax], %%rax\n\t"
+		"mov %[rdx], %%rdx\n\t"
+		"mov %[rcx], %%rcx\n\t"
+		"inl %%dx, %%eax\n\t"
+		:
+		"+a"(res->rax),
+		"+b"(res->rbx),
+		"+c"(res->rcx),
+		"+d"(res->rdx)
+		:
+		[rax]"m"(vmport_magic),
+		[rdx]"m"(vmport),
+		[rcx]"m"(command)
+		);
+
+	return (uint64_t) res;
+}
+
+#define FAULT		true
+#define NO_FAULT	false
+#define USER_MODE	true
+#define KERNEL_MODE	false
+
+#define RDPMC_ARG(n, m, sf) {.usermode = m, \
+	.func =  (test_fault_func) rdpmc, .fault_vector = GP_VECTOR, \
+	.should_fault = sf, .arg = {n, 0, 0, 0}, .callback = NULL}
+
+#define RDPMC_TEST(name, a, m, sf) FAULT_TEST("rdpmc_test: "name, \
+		RDPMC_ARG(a, m, sf))
+
+#define PORT_ARG(a, b, c, m, sf) {.usermode = m, \
+	.func =  (test_fault_func) vmware_backdoor_port, \
+	.fault_vector = GP_VECTOR, .should_fault = sf, .arg = {a, b, c, 0}, \
+	.callback = vmware_backdoor_port_callback}
+
+#define PORT_TEST(name, a, b, c, m, sf) FAULT_TEST("port_test: "name, \
+		PORT_ARG(a, b, c, m, sf))
+
+
+struct fault_test vmware_backdoor_tests[] = {
+	RDPMC_TEST("HOST_TSC kernel", VMWARE_BACKDOOR_PMC_HOST_TSC,
+			KERNEL_MODE, NO_FAULT),
+	RDPMC_TEST("REAL_TIME kernel", VMWARE_BACKDOOR_PMC_REAL_TIME,
+			KERNEL_MODE, NO_FAULT),
+	RDPMC_TEST("APPARENT_TIME kernel", VMWARE_BACKDOOR_PMC_APPARENT_TIME,
+			KERNEL_MODE, NO_FAULT),
+	RDPMC_TEST("HOST_TSC user", VMWARE_BACKDOOR_PMC_HOST_TSC,
+			USER_MODE, NO_FAULT),
+	RDPMC_TEST("REAL_TIME user", VMWARE_BACKDOOR_PMC_REAL_TIME,
+			USER_MODE, NO_FAULT),
+	RDPMC_TEST("APPARENT_TIME user", VMWARE_BACKDOOR_PMC_APPARENT_TIME,
+			USER_MODE, NO_FAULT),
+	RDPMC_TEST("RANDOM PMC user", 0xfff, USER_MODE, FAULT),
+
+	PORT_TEST("CMD_GETVERSION user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC,
+			VMPORT_CMD_GETVERSION, USER_MODE, NO_FAULT),
+	PORT_TEST("CMD_GETVERSION kernel", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC,
+			VMPORT_CMD_GETVERSION, KERNEL_MODE, NO_FAULT),
+	PORT_TEST("CMD_ILLEGAL user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC,
+			VMPORT_CMD_ILLEGAL, USER_MODE, NO_FAULT),
+	PORT_TEST("RANDOM port user", RANDOM_IO_PORT, VMWARE_MAGIC, 0xfff,
+			USER_MODE, FAULT),
+	{ NULL },
+};
+
+/*
+ * Set TSS IO Perm to throw GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT
+ * from User Mode
+ */
+static void set_tss_ioperm(void)
+{
+	struct descriptor_table_ptr gdt;
+	struct segment_desc64 *gdt_table;
+	struct segment_desc64 *tss_entry;
+	u16 tr = 0;
+	tss64_t *tss;
+	unsigned char *ioperm_bitmap;
+	uint64_t tss_base;
+
+	sgdt(&gdt);
+	tr = str();
+	gdt_table = (struct segment_desc64 *) gdt.base;
+	tss_entry = &gdt_table[tr / sizeof(struct segment_desc64)];
+	tss_base = ((uint64_t) tss_entry->base1 |
+			((uint64_t) tss_entry->base2 << 16) |
+			((uint64_t) tss_entry->base3 << 24) |
+			((uint64_t) tss_entry->base4 << 32));
+	tss = (tss64_t *)tss_base;
+	tss->iomap_base = sizeof(*tss);
+	ioperm_bitmap = ((unsigned char *)tss+tss->iomap_base);
+
+	/* We want GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT */
+	ioperm_bitmap[RANDOM_IO_PORT / 8] |=
+		1 << (RANDOM_IO_PORT % 8);
+	ioperm_bitmap[VMWARE_BACKDOOR_PORT / 8] |=
+		1 << (VMWARE_BACKDOOR_PORT % 8);
+	*(uint64_t *)tss_entry &= ~DESC_BUSY;
+
+	/* Update TSS */
+	ltr(tr);
+}
+
+static void check_vmware_backdoors(void)
+{
+	int i;
+
+	/* Disable Permissions for IO PORTS */
+	set_tss_ioperm();
+	/* Disable Permission to run rdpmc from user mode */
+	write_cr4(read_cr4() & ~X86_CR4_PCE);
+
+	report_prefix_push("vmware_backdoors");
+
+	for (i = 0; vmware_backdoor_tests[i].name != NULL; i++)
+		test_run(&vmware_backdoor_tests[i]);
+
+	report_prefix_pop();
+}
+
+int main(int ac, char **av)
+{
+	setup_vm();
+	setup_idt();
+
+	check_vmware_backdoors();
+
+	return report_summary();
+}
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor
  2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
                   ` (4 preceding siblings ...)
  2017-12-24 10:08 ` [PATCH 5/5] x86: Add VMware backdoor unit test Arbel Moshe
@ 2018-02-14 12:06 ` Paolo Bonzini
  5 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2018-02-14 12:06 UTC (permalink / raw)
  To: Arbel Moshe, rkrcmar, kvm; +Cc: idan.brown, liran.alon

On 24/12/2017 11:07, Arbel Moshe wrote:
> Hi,
> This series adds a set of unit tests to series:
> "KVM: x86: Add support for VMware backdoor I/O ports & Pseduo-PMCs"
> 
> The series is split into the following patches:
> 1. Add an x86 utility to run a function in User Mode.
> 2. Add a test utility to run a function in User Mode / Kernel Mode, catch an
> exception, and run a callback to test function return value.
> 3. Add CR4 PCE bit definition.
> 4. Add x86_64 segment descriptor struct.
> 5. Add VMware backdoor tests:
> Test VMware port and VMware RDPMC backdoors, both in user mode and kernel
> mode.

Looks good, thanks.  I'll shortly review the kernel parts too.

Paolo

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-02-14 12:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-24 10:07 [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Arbel Moshe
2017-12-24 10:07 ` [PATCH 1/5] x86: Add utility to run function in User Mode Arbel Moshe
2017-12-24 10:07 ` [PATCH 2/5] x86: Add Test Utility to run in User Mode and catch exceptions Arbel Moshe
2017-12-24 10:07 ` [PATCH 3/5] x86: Add Definition for PCE bit in CR4 Arbel Moshe
2017-12-24 10:08 ` [PATCH 4/5] x86: Add definition for 64 bit Segment descriptor Arbel Moshe
2017-12-24 10:08 ` [PATCH 5/5] x86: Add VMware backdoor unit test Arbel Moshe
2018-02-14 12:06 ` [kvm-unit-test PATCH 0/5]: x86: Add tests for VMware backdoor Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.