kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
@ 2013-06-19 15:00 Arthur Chunqi Li
  2013-06-19 15:00 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
                   ` (2 more replies)
  0 siblings, 3 replies; 54+ messages in thread
From: Arthur Chunqi Li @ 2013-06-19 15:00 UTC (permalink / raw)
  To: kvm; +Cc: gleb, pbonzini, jan.kiszka, Arthur Chunqi Li

Add a function trap_emulator to run an instruction in emulator.
Set inregs first (%rax is invalid because it is used as return
address), put instruction codec in alt_insn and call func with
alt_insn_length. Get results in outregs.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/emulator.c |  110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)
 mode change 100644 => 100755 x86/emulator.c

diff --git a/x86/emulator.c b/x86/emulator.c
old mode 100644
new mode 100755
index 96576e5..48d45c8
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -11,6 +11,15 @@ int fails, tests;
 
 static int exceptions;
 
+struct regs {
+	u64 rax, rbx, rcx, rdx;
+	u64 rsi, rdi, rsp, rbp;
+	u64 r8, r9, r10, r11;
+	u64 r12, r13, r14, r15;
+	u64 rip, rflags;
+};
+struct regs inregs, outregs, save;
+
 void report(const char *name, int result)
 {
 	++tests;
@@ -685,6 +694,107 @@ static void test_shld_shrd(u32 *mem)
     report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29)));
 }
 
+#define INSN_SAVE 			\
+	"ret\n\t"				\
+	"pushf\n\t"			\
+	"push 136+save \n\t"		\
+	"popf \n\t"			\
+	"xchg %rax, 0+save \n\t"		\
+	"xchg %rbx, 8+save \n\t"		\
+	"xchg %rcx, 16+save \n\t"		\
+	"xchg %rdx, 24+save \n\t"		\
+	"xchg %rsi, 32+save \n\t"		\
+	"xchg %rdi, 40+save \n\t"		\
+	"xchg %rsp, 48+save \n\t"		\
+	"xchg %rbp, 56+save \n\t"		\
+	"xchg %r8, 64+save \n\t"		\
+	"xchg %r9, 72+save \n\t"		\
+	"xchg %r10, 80+save \n\t"		\
+	"xchg %r11, 88+save \n\t"		\
+	"xchg %r12, 96+save \n\t"		\
+	"xchg %r13, 104+save \n\t"		\
+	"xchg %r14, 112+save \n\t"		\
+	"xchg %r15, 120+save \n\t"		\
+
+#define INSN_RESTORE			\
+	"xchg %rax, 0+save \n\t"		\
+	"xchg %rbx, 8+save \n\t"		\
+	"xchg %rcx, 16+save \n\t"		\
+	"xchg %rdx, 24+save \n\t"		\
+	"xchg %rsi, 32+save \n\t"		\
+	"xchg %rdi, 40+save \n\t"		\
+	"xchg %rsp, 48+save \n\t"		\
+	"xchg %rbp, 56+save \n\t"		\
+	"xchg %r8, 64+save \n\t"		\
+	"xchg %r9, 72+save \n\t"		\
+	"xchg %r10, 80+save \n\t"		\
+	"xchg %r11, 88+save \n\t"		\
+	"xchg %r12, 96+save \n\t"		\
+	"xchg %r13, 104+save \n\t"		\
+	"xchg %r14, 112+save \n\t"		\
+	"xchg %r15, 120+save \n\t"		\
+	"pushf \n\t"			\
+	"pop 136+save \n\t"		\
+	"popf \n\t"			\
+	"ret \n\t"				\
+
+#define INSN_TRAP			\
+	"in  (%dx),%al\n\t"			\
+	". = . + 31\n\t"			\
+
+asm(
+	".align 4096\n\t"
+	"insn_page:\n\t"
+	INSN_SAVE
+	"test_insn:\n\t"
+	INSN_TRAP
+	"test_insn_end:\n\t"
+	INSN_RESTORE
+	"insn_page_end:\n\t"
+	".align 4096\n\t"
+
+	"alt_insn_page:\n\t"
+	INSN_SAVE
+	"alt_test_insn:\n\t"
+	INSN_TRAP
+	"alt_test_insn_end:\n\t"
+	INSN_RESTORE
+	"alt_insn_page_end:\n\t"
+	".align 4096\n\t"
+);
+
+static void trap_emulator(uint64_t *mem, uint8_t* alt_insn, int alt_insn_length)
+{
+	ulong *cr3 = (ulong *)read_cr3();
+	void *insn_ram;
+	int i;
+	extern u8 insn_page[], test_insn[], test_insn_end[];
+	extern u8 alt_insn_page[], alt_test_insn[];
+
+	insn_ram = vmap(virt_to_phys(insn_page), 4096);
+	for (i=1; i<test_insn_end - test_insn; i++)
+		alt_test_insn[i] = test_insn[i] = 0x90; // nop
+	for (i=0; i<alt_insn_length; i++)
+		alt_test_insn[i] = alt_insn[i];
+	for(;i<test_insn_end - test_insn; i++)
+		alt_test_insn[i] = 0x90; // nop
+	save = inregs;
+
+	// Load the code TLB with insn_page, but point the page tables at
+	// alt_insn_page (and keep the data TLB clear, for AMD decode assist).
+	// This will make the CPU trap on the insn_page instruction but the
+	// hypervisor will see alt_insn_page.
+	install_page(cr3, virt_to_phys(insn_page), insn_ram);
+	invlpg(insn_ram);
+	// Load code TLB
+	asm volatile("call *%0" : : "r"(insn_ram));
+	install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
+	// Trap, let hypervisor emulate at alt_insn_page
+	asm volatile("call *%0": : "r"(insn_ram+1));
+
+	outregs = save;
+}
+
 static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
 {
     ++exceptions;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 54+ messages in thread
* [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
@ 2013-06-20 10:45 Arthur Chunqi Li
  2013-06-20 10:47 ` Jan Kiszka
  2013-06-20 12:32 ` Gleb Natapov
  0 siblings, 2 replies; 54+ messages in thread
From: Arthur Chunqi Li @ 2013-06-20 10:45 UTC (permalink / raw)
  To: kvm; +Cc: gleb, pbonzini, jan.kiszka, Arthur Chunqi Li

Add a function trap_emulator to run an instruction in emulator.
Set inregs first (%rax is invalid because it is used as return
address), put instruction codec in alt_insn and call func with
alt_insn_length. Get results in outregs.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 lib/libcflat.h |    1 +
 lib/string.c   |   12 +++++++++
 x86/emulator.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 0875bd9..fadc33d 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -50,6 +50,7 @@ extern int vsnprintf(char *buf, int size, const char *fmt, va_list va);
 extern void puts(const char *s);
 
 extern void *memset(void *s, int c, size_t n);
+extern void *memcpy(void *dest, const void *src, size_t n);
 
 extern long atol(const char *ptr);
 #define ARRAY_SIZE(_a)  (sizeof(_a)/sizeof((_a)[0]))
diff --git a/lib/string.c b/lib/string.c
index 9dc94a1..e798f86 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -42,6 +42,18 @@ void *memset(void *s, int c, size_t n)
     return s;
 }
 
+void *memcpy(void *dest, const void *src, size_t n)
+{
+    size_t i;
+    char *a = dest;
+    char *b = src;
+
+    for (i = 0; i < n; ++i)
+        a[i] = b[i];
+
+    return dest;
+}
+
 long atol(const char *ptr)
 {
     long acc = 0;
diff --git a/x86/emulator.c b/x86/emulator.c
index 96576e5..b3626fa 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -11,6 +11,15 @@ int fails, tests;
 
 static int exceptions;
 
+struct regs {
+	u64 rax, rbx, rcx, rdx;
+	u64 rsi, rdi, rsp, rbp;
+	u64 r8, r9, r10, r11;
+	u64 r12, r13, r14, r15;
+	u64 rip, rflags;
+};
+struct regs inregs, outregs, save;
+
 void report(const char *name, int result)
 {
 	++tests;
@@ -685,6 +694,75 @@ static void test_shld_shrd(u32 *mem)
     report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29)));
 }
 
+#define INSN_XCHG_ALL			\
+	"xchg %rax, 0+save \n\t"		\
+	"xchg %rbx, 8+save \n\t"		\
+	"xchg %rcx, 16+save \n\t"		\
+	"xchg %rdx, 24+save \n\t"		\
+	"xchg %rsi, 32+save \n\t"		\
+	"xchg %rdi, 40+save \n\t"		\
+	"xchg %rsp, 48+save \n\t"		\
+	"xchg %rbp, 56+save \n\t"		\
+	"xchg %r8, 64+save \n\t"		\
+	"xchg %r9, 72+save \n\t"		\
+	"xchg %r10, 80+save \n\t"		\
+	"xchg %r11, 88+save \n\t"		\
+	"xchg %r12, 96+save \n\t"		\
+	"xchg %r13, 104+save \n\t"		\
+	"xchg %r14, 112+save \n\t"		\
+	"xchg %r15, 120+save \n\t"		\
+
+asm(
+	".align 4096\n\t"
+	"insn_page:\n\t"
+	"ret\n\t"
+	"pushf\n\t"
+	"push 136+save \n\t"
+	"popf \n\t"
+	INSN_XCHG_ALL
+	"test_insn:\n\t"
+	"in  (%dx),%al\n\t"
+	".skip 31, 0x90\n\t"
+	"test_insn_end:\n\t"
+	INSN_XCHG_ALL
+	"pushf \n\t"
+	"pop 136+save \n\t"
+	"popf \n\t"
+	"ret \n\t"
+	"insn_page_end:\n\t"
+	".align 4096\n\t"
+
+	"alt_insn_page:\n\t"
+	". = . + 4096\n\t"
+	".align 4096\n\t"
+);
+
+static void trap_emulator(uint64_t *mem, uint8_t* alt_insn, int alt_insn_length)
+{
+	ulong *cr3 = (ulong *)read_cr3();
+	void *insn_ram;
+	extern u8 insn_page[], test_insn[], alt_insn_page[];
+
+	insn_ram = vmap(virt_to_phys(insn_page), 4096);
+	memcpy(alt_insn_page, test_insn, 4096);
+	memcpy(alt_insn_page + (test_insn - insn_page), alt_insn, alt_insn_length);
+	save = inregs;
+
+	/* Load the code TLB with insn_page, but point the page tables at
+	   alt_insn_page (and keep the data TLB clear, for AMD decode assist).
+	   This will make the CPU trap on the insn_page instruction but the
+	   hypervisor will see alt_insn_page. */
+	install_page(cr3, virt_to_phys(insn_page), insn_ram);
+	invlpg(insn_ram);
+	/* Load code TLB */
+	asm volatile("call *%0" : : "r"(insn_ram));
+	install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
+	/* Trap, let hypervisor emulate at alt_insn_page */
+	asm volatile("call *%0": : "r"(insn_ram+1));
+
+	outregs = save;
+}
+
 static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
 {
     ++exceptions;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 54+ messages in thread
* [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
@ 2013-06-13 15:16 Arthur Chunqi Li
  0 siblings, 0 replies; 54+ messages in thread
From: Arthur Chunqi Li @ 2013-06-13 15:16 UTC (permalink / raw)
  To: kvm; +Cc: gleb, pbonzini, jan.kiszka, Arthur Chunqi Li

Add a function trap_emulator to run an instruction in emulator.
Set inregs first (%rax is invalid because it is used as return
address), put instruction codec in alt_insn and call func with
alt_insn_length. Get results in outregs.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/emulator.c |  132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)

diff --git a/x86/emulator.c b/x86/emulator.c
index 96576e5..4981bfb 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -11,6 +11,16 @@ int fails, tests;
 
 static int exceptions;
 
+struct regs {
+	u64 rax, rbx, rcx, rdx;
+	u64 rsi, rdi, rsp, rbp;
+	u64 r8, r9, r10, r11;
+	u64 r12, r13, r14, r15;
+	u64 rip, rflags;
+};
+static struct regs inregs, outregs;
+extern struct regs save;
+
 void report(const char *name, int result)
 {
 	++tests;
@@ -685,6 +695,128 @@ static void test_shld_shrd(u32 *mem)
     report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29)));
 }
 
+extern u8 insn_start[], insn_end[];
+extern u8 insn_emulate_start[], insn_emulate_end[];
+
+static void mk_insn_page(uint8_t *insn_page, uint8_t *alt_insn_page,
+				uint8_t *alt_insn, int alt_insn_length)
+{
+	int i, emul_offset;
+	for (i=1; i<insn_emulate_end - insn_emulate_start; i++)
+		insn_emulate_start[i] = 0x90; // nop
+	for (i=0; i<insn_end - insn_start; i++)
+		insn_page[i] = insn_start[i];
+	emul_offset = insn_emulate_start - insn_start;
+	for (i=0; i<alt_insn_length; i++)
+		alt_insn_page[i+emul_offset] = alt_insn[i];
+
+	asm volatile(
+		".pushsection .text.insn, \"ax\" \n\t"
+		"insn_start:\n\t"
+		"ret\n\t"
+
+		"push %%rax; push %%rbx\n\t"
+		"push %%rcx; push %%rdx\n\t"
+		"push %%rsi; push %%rdi\n\t"
+		"push %%rbp\n\t"
+		"push %%r8; push %%r9\n\t"
+		"push %%r10; push %%r11\n\t"
+		"push %%r12; push %%r13\n\t"
+		"push %%r14; push %%r15\n\t"
+		"pushf\n\t"
+
+		"push 136+%[save] \n\t"
+		"popf \n\t"
+		"mov 0+%[save], %%rax \n\t"
+		"mov 8+%[save], %%rbx \n\t"
+		"mov 16+%[save], %%rcx \n\t"
+		"mov 24+%[save], %%rdx \n\t"
+		"mov 32+%[save], %%rsi \n\t"
+		"mov 40+%[save], %%rdi \n\t"
+		"mov 56+%[save], %%rbp \n\t"
+		"mov 64+%[save], %%r8 \n\t"
+		"mov 72+%[save], %%r9 \n\t"
+		"mov 80+%[save], %%r10  \n\t"
+		"mov 88+%[save], %%r11 \n\t"
+		"mov 96+%[save], %%r12 \n\t"
+		"mov 104+%[save], %%r13 \n\t"
+		"mov 112+%[save], %%r14 \n\t"
+		"mov 120+%[save], %%r15 \n\t"
+
+		"insn_emulate_start:\n\t"
+		"in  (%%dx),%%al\n\t"
+		". = . + 31\n\t"
+		"insn_emulate_end:\n\t"
+
+		"pushf \n\t"
+		"pop 136+%[save] \n\t"
+		"mov %%rax, 0+%[save] \n\t"
+		"mov %%rbx, 8+%[save] \n\t"
+		"mov %%rcx, 16+%[save] \n\t"
+		"mov %%rdx, 24+%[save] \n\t"
+		"mov %%rsi, 32+%[save] \n\t"
+		"mov %%rdi, 40+%[save] \n\t"
+		"mov %%rbp, 56+%[save] \n\t"
+		"mov %%r8, 64+%[save]\n\t"
+		"mov %%r9, 72+%[save]\n\t"
+		"mov %%r10, 80+%[save]\n\t"
+		"mov %%r11, 88+%[save]\n\t"
+		"mov %%r12, 96+%[save]\n\t"
+		"mov %%r13, 104+%[save]\n\t"
+		"mov %%r14, 112+%[save]\n\t"
+		"mov %%r15, 120+%[save]\n\t"
+
+		"popf\n\t"
+		"pop %%r15; pop %%r14 \n\t"
+		"pop %%r13; pop %%r12 \n\t"
+		"pop %%r11; pop %%r10 \n\t"
+		"pop %%r9; pop %%r8 \n\t"
+		"pop %%rbp \n\t"
+		"pop %%rdi; pop %%rsi \n\t"
+		"pop %%rdx; pop %%rcx \n\t"
+		"pop %%rbx; pop %%rax \n\t"
+
+		"ret\n\t"
+		
+		"save:\n\t"
+		". = . + 256\n\t"
+		"insn_end:\n\t"
+		".popsection\n\t"
+		: [save]"=m"(save)
+		: : "memory", "cc"
+		);
+}
+
+static void trap_emulator(uint64_t *mem, uint8_t *insn_page,
+			     uint8_t *alt_insn_page, void *insn_ram,
+			     uint8_t* alt_insn, int alt_insn_length, int reserve_stack)
+{
+	ulong *cr3 = (ulong *)read_cr3();
+	extern u8 insn_start[];
+	int save_offset = (u8 *)(&save) - insn_start;
+	
+	memset(insn_page, 0x90, 4096);
+	memset(alt_insn_page, 0x90, 4096);
+	
+	save = inregs;
+	mk_insn_page(insn_page, alt_insn_page,
+		alt_insn, alt_insn_length);
+	
+	// Load the code TLB with insn_page, but point the page tables at
+	// alt_insn_page (and keep the data TLB clear, for AMD decode assist).
+	// This will make the CPU trap on the insn_page instruction but the
+	// hypervisor will see alt_insn_page.
+	install_page(cr3, virt_to_phys(insn_page), insn_ram);
+	invlpg(insn_ram);
+	// Load code TLB
+	asm volatile("call *%0" : : "r"(insn_ram));
+	install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
+	// Trap, let hypervisor emulate at alt_insn_page
+	asm volatile("call *%0": : "r"(insn_ram+1));
+
+	outregs = *((struct regs *)(&alt_insn_page[save_offset]));
+}
+
 static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
 {
     ++exceptions;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 54+ messages in thread
* [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
@ 2013-06-10 13:38 Arthur Chunqi Li
  2013-06-10 17:36 ` Gleb Natapov
  0 siblings, 1 reply; 54+ messages in thread
From: Arthur Chunqi Li @ 2013-06-10 13:38 UTC (permalink / raw)
  To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li

Add a function trap_emulator to run an instruction in emulator.
Set inregs first (%rax is invalid because it is used as return
address), put instruction codec in alt_insn and call func with
alt_insn_length. Get results in outregs.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/emulator.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)

diff --git a/x86/emulator.c b/x86/emulator.c
index 96576e5..a1bd92e 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -11,6 +11,13 @@ int fails, tests;
 
 static int exceptions;
 
+struct regs {
+	u64 rax, rbx, rcx, rdx;
+	u64 rsi, rdi, rsp, rbp;
+	u64 rip, rflags;
+};
+static struct regs inregs, outregs;
+
 void report(const char *name, int result)
 {
 	++tests;
@@ -685,6 +692,105 @@ static void test_shld_shrd(u32 *mem)
     report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29)));
 }
 
+static void trap_emulator(uint64_t *mem, uint8_t *insn_page,
+			     uint8_t *alt_insn_page, void *insn_ram,
+			     uint8_t* alt_insn, int alt_insn_length, int reserve_stack)
+{
+	ulong *cr3 = (ulong *)read_cr3();
+	int i;
+	static struct regs save;
+
+	// Pad with RET instructions
+	memset(insn_page, 0x90, 4096);
+	memset(alt_insn_page, 0x90, 4096);
+
+	asm volatile(
+		"movw $1, %0\n\t"
+		: : "m"(mem)
+		: "memory"
+		);
+	// Place a trapping instruction in the page to trigger a VMEXIT
+	insn_page[0] = 0xc3; // ret
+	if (!reserve_stack)
+	{
+		insn_page[1] = 0x49; // xchg   %rsp,%r9
+		insn_page[2] = 0x87;
+		insn_page[3] = 0xe1;
+		insn_page[4] = 0x49; // xchg   %rbp,%r10
+		insn_page[5] = 0x87;
+		insn_page[6] = 0xea;
+	}
+	//in  (%dx),%al, may change in the future
+	insn_page[7] = 0xec;
+
+	// Place the instruction we want the hypervisor to see in the alternate page
+	for (i=7; i<alt_insn_length+7; i++)
+		alt_insn_page[i] = alt_insn[i-7];
+
+	if (!reserve_stack)
+	{
+		insn_page[i+0] = 0x49; // xchg   %rsp,%r9
+		insn_page[i+1] = 0x87;
+		insn_page[i+2] = 0xe1;
+		insn_page[i+3] = 0x49; // xchg   %rbp,%r10
+		insn_page[i+4] = 0x87;
+		insn_page[i+5] = 0xea;
+	}
+	else
+	{
+		insn_page[i+0] = 0x49; // mov   %rsp,%r9
+		insn_page[i+1] = 0x89;
+		insn_page[i+2] = 0xe1;
+		insn_page[i+3] = 0x49; // mov   %rbp,%r10
+		insn_page[i+4] = 0x89;
+		insn_page[i+5] = 0xea;
+	}
+	insn_page[i+6] = 0xc3; // ret
+
+	save = inregs;
+	
+	// Load the code TLB with insn_page, but point the page tables at
+	// alt_insn_page (and keep the data TLB clear, for AMD decode assist).
+	// This will make the CPU trap on the insn_page instruction but the
+	// hypervisor will see alt_insn_page.
+	install_page(cr3, virt_to_phys(insn_page), insn_ram);
+	invlpg(insn_ram);
+	// Load code TLB
+	asm volatile("call *%0" : : "r"(insn_ram));
+	install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
+	// Trap, let hypervisor emulate at alt_insn_page
+	asm volatile(
+		"push 72+%[save]; popf\n\t"
+		"mov %2, %%r8\n\t"
+		"xchg %%rax, 0+%[save] \n\t"
+		"xchg %%rbx, 8+%[save] \n\t"
+		"xchg %%rcx, 16+%[save] \n\t"
+		"xchg %%rdx, 24+%[save] \n\t"
+		"xchg %%rsi, 32+%[save] \n\t"
+		"xchg %%rdi, 40+%[save] \n\t"
+		"xchg %%r9, 48+%[save]\n\t"
+		"xchg %%r10, 56+%[save]\n\t"
+
+		"call *%1\n\t"
+
+		"xchg %%rax, 0+%[save] \n\t"
+		"xchg %%rbx, 8+%[save] \n\t"
+		"xchg %%rcx, 16+%[save] \n\t"
+		"xchg %%rdx, 24+%[save] \n\t"
+		"xchg %%rsi, 32+%[save] \n\t"
+		"xchg %%rdi, 40+%[save] \n\t"
+		"xchg %%r9, 48+%[save] \n\t"
+		"xchg %%r10, 56+%[save] \n\t"
+		/* Save RFLAGS in outregs*/
+		"pushf \n\t"
+		"pop 72+%[save] \n\t"
+		: [save]"+m"(save)
+		: "r"(insn_ram+1), "r"(mem)
+		: "memory", "cc", "r8", "r9", "r10"
+		);
+	outregs = save;
+}
+
 static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
 {
     ++exceptions;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 54+ messages in thread
* [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
@ 2013-06-07  2:31 Arthur Chunqi Li
  2013-06-09 11:07 ` Gleb Natapov
  0 siblings, 1 reply; 54+ messages in thread
From: Arthur Chunqi Li @ 2013-06-07  2:31 UTC (permalink / raw)
  To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li

Add a function trap_emulator to run an instruction in emulator.
Set inregs first (%rax, %rsp, %rbp, %rflags have special usage and
cannot set in inregs), put instruction codec in alt_insn and call
func with alt_insn_length. Get results in outregs.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/emulator.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)
 mode change 100644 => 100755 x86/emulator.c

diff --git a/x86/emulator.c b/x86/emulator.c
old mode 100644
new mode 100755
index 96576e5..770e8f7
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -11,6 +11,13 @@ int fails, tests;
 
 static int exceptions;
 
+struct regs {
+	u64 rax, rbx, rcx, rdx;
+	u64 rsi, rdi, rsp, rbp;
+	u64 rip, rflags;
+};
+static struct regs inregs, outregs;
+
 void report(const char *name, int result)
 {
 	++tests;
@@ -685,6 +692,66 @@ static void test_shld_shrd(u32 *mem)
     report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29)));
 }
 
+static void trap_emulator(uint64_t *mem, uint8_t *insn_page,
+			     uint8_t *alt_insn_page, void *insn_ram,
+			     uint8_t *alt_insn, int alt_insn_length)
+{
+	ulong *cr3 = (ulong *)read_cr3();
+	int i;
+	static struct regs save;
+
+	// Pad with RET instructions
+	memset(insn_page, 0xc3, 4096);
+	memset(alt_insn_page, 0xc3, 4096);
+
+	// Place a trapping instruction in the page to trigger a VMEXIT
+	insn_page[0] = 0x89; // mov %eax, (%rax)
+	insn_page[1] = 0x00;
+	insn_page[2] = 0x90; // nop
+	insn_page[3] = 0xc3; // ret
+
+	// Place the instruction we want the hypervisor to see in the alternate page
+	for (i=0; i<alt_insn_length; i++)
+		alt_insn_page[i] = alt_insn[i];
+	save = inregs;
+	
+	// Load the code TLB with insn_page, but point the page tables at
+	// alt_insn_page (and keep the data TLB clear, for AMD decode assist).
+	// This will make the CPU trap on the insn_page instruction but the
+	// hypervisor will see alt_insn_page.
+	install_page(cr3, virt_to_phys(insn_page), insn_ram);
+	invlpg(insn_ram);
+	// Load code TLB
+	asm volatile("call *%0" : : "r"(insn_ram + 3));
+	install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
+	// Trap, let hypervisor emulate at alt_insn_page
+	asm volatile(
+		"xchg %%rbx, 8+%[save] \n\t"
+		"xchg %%rcx, 16+%[save] \n\t"
+		"xchg %%rdx, 24+%[save] \n\t"
+		"xchg %%rsi, 32+%[save] \n\t"
+		"xchg %%rdi, 40+%[save] \n\t"
+
+		"call *%1\n\t"
+
+		"mov %%rax, 0+%[save] \n\t"
+		"xchg %%rbx, 8+%[save] \n\t"
+		"xchg %%rcx, 16+%[save] \n\t"
+		"xchg %%rdx, 24+%[save] \n\t"
+		"xchg %%rsi, 32+%[save] \n\t"
+		"xchg %%rdi, 40+%[save] \n\t"
+		"mov %%rsp, 48+%[save] \n\t"
+		"mov %%rbp, 56+%[save] \n\t"
+		/* Save RFLAGS in outregs*/
+		"pushf \n\t"
+		"popq 72+%[save] \n\t"
+		: [save]"+m"(save)
+		: "r"(insn_ram), "a"(mem)
+		: "memory", "cc"
+		);
+	outregs = save;
+}
+
 static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
 {
     ++exceptions;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 54+ messages in thread
* [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
@ 2013-06-06 15:24 Arthur Chunqi Li
  2013-06-07  2:14 ` 李春奇 <Arthur Chunqi Li>
  2013-06-12 20:50 ` Paolo Bonzini
  0 siblings, 2 replies; 54+ messages in thread
From: Arthur Chunqi Li @ 2013-06-06 15:24 UTC (permalink / raw)
  To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li

Add a function trap_emulator to run an instruction in emulator.
Set inregs first (%rax is invalid because it is used as return
address), put instruction codec in alt_insn and call func with
alt_insn_length. Get results in outregs.

Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
 x86/emulator.c |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/x86/emulator.c b/x86/emulator.c
index 96576e5..8ab9904 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -11,6 +11,14 @@ int fails, tests;
 
 static int exceptions;
 
+struct regs {
+	u64 rax, rbx, rcx, rdx;
+	u64 rsi, rdi, rsp, rbp;
+	u64 rip, rflags;
+};
+
+static struct regs inregs, outregs;
+
 void report(const char *name, int result)
 {
 	++tests;
@@ -685,6 +693,79 @@ static void test_shld_shrd(u32 *mem)
     report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29)));
 }
 
+static void trap_emulator(uint64_t *mem, uint8_t *insn_page,
+			     uint8_t *alt_insn_page, void *insn_ram,
+			     uint8_t *alt_insn, int alt_insn_length)
+{
+	ulong *cr3 = (ulong *)read_cr3();
+	int i;
+
+	// Pad with RET instructions
+	memset(insn_page, 0xc3, 4096);
+	memset(alt_insn_page, 0xc3, 4096);
+
+	// Place a trapping instruction in the page to trigger a VMEXIT
+	insn_page[0] = 0x89; // mov %eax, (%rax)
+	insn_page[1] = 0x00;
+	insn_page[2] = 0x90; // nop
+	insn_page[3] = 0xc3; // ret
+
+	// Place the instruction we want the hypervisor to see in the alternate page
+	for (i=0; i<alt_insn_length; i++)
+		alt_insn_page[i] = alt_insn[i];
+
+	// Save general registers
+	asm volatile(
+		"push %rax\n\r"
+		"push %rbx\n\r"
+		"push %rcx\n\r"
+		"push %rdx\n\r"
+		"push %rsi\n\r"
+		"push %rdi\n\r"
+		);
+	// Load the code TLB with insn_page, but point the page tables at
+	// alt_insn_page (and keep the data TLB clear, for AMD decode assist).
+	// This will make the CPU trap on the insn_page instruction but the
+	// hypervisor will see alt_insn_page.
+	install_page(cr3, virt_to_phys(insn_page), insn_ram);
+	invlpg(insn_ram);
+	// Load code TLB
+	asm volatile("call *%0" : : "r"(insn_ram + 3));
+	install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
+	// Trap, let hypervisor emulate at alt_insn_page
+	asm volatile(
+		"call *%1\n\r"
+
+		"mov %%rax, 0+%[outregs] \n\t"
+		"mov %%rbx, 8+%[outregs] \n\t"
+		"mov %%rcx, 16+%[outregs] \n\t"
+		"mov %%rdx, 24+%[outregs] \n\t"
+		"mov %%rsi, 32+%[outregs] \n\t"
+		"mov %%rdi, 40+%[outregs] \n\t"
+		"mov %%rsp,48+ %[outregs] \n\t"
+		"mov %%rbp, 56+%[outregs] \n\t"
+
+		/* Save RFLAGS in outregs*/
+		"pushf \n\t"
+		"popq 72+%[outregs] \n\t"
+		: [outregs]"+m"(outregs)
+		: "r"(insn_ram),
+			"a"(mem), "b"(inregs.rbx),
+			"c"(inregs.rcx), "d"(inregs.rdx),
+			"S"(inregs.rsi), "D"(inregs.rdi)
+		: "memory", "cc"
+		);
+	// Restore general registers
+	asm volatile(
+		"pop %rax\n\r"
+		"pop %rbx\n\r"
+		"pop %rcx\n\r"
+		"pop %rdx\n\r"
+		"pop %rsi\n\r"
+		"pop %rdi\n\r"
+		);
+}
+
 static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
 {
     ++exceptions;
-- 
1.7.9.5


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

end of thread, other threads:[~2013-06-20 12:32 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-19 15:00 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
2013-06-19 15:00 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-20  8:25   ` Paolo Bonzini
2013-06-19 15:07 ` [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator 李春奇 <Arthur Chunqi Li>
2013-06-19 16:03   ` Gleb Natapov
2013-06-19 17:48     ` Gmail
2013-06-20  5:42       ` Gleb Natapov
2013-06-20  8:29     ` Paolo Bonzini
2013-06-20  8:31       ` Gleb Natapov
2013-06-20  8:48 ` Gleb Natapov
2013-06-20  8:58   ` Gmail
  -- strict thread matches above, loose matches on Subject: below --
2013-06-20 10:45 Arthur Chunqi Li
2013-06-20 10:47 ` Jan Kiszka
2013-06-20 12:32 ` Gleb Natapov
2013-06-13 15:16 Arthur Chunqi Li
2013-06-10 13:38 Arthur Chunqi Li
2013-06-10 17:36 ` Gleb Natapov
2013-06-07  2:31 Arthur Chunqi Li
2013-06-09 11:07 ` Gleb Natapov
2013-06-09 12:44   ` 李春奇 <Arthur Chunqi Li>
2013-06-09 12:49     ` Gleb Natapov
2013-06-09 12:56       ` 李春奇 <Arthur Chunqi Li>
2013-06-09 12:58         ` Gleb Natapov
2013-06-09 13:22       ` 李春奇 <Arthur Chunqi Li>
2013-06-09 14:09         ` Gleb Natapov
2013-06-09 15:23           ` 李春奇 <Arthur Chunqi Li>
2013-06-09 16:00             ` Gleb Natapov
2013-06-09 17:09               ` 李春奇 <Arthur Chunqi Li>
2013-06-09 17:13                 ` Gleb Natapov
2013-06-09 17:28                   ` 李春奇 <Arthur Chunqi Li>
2013-06-09 17:39                     ` Gleb Natapov
2013-06-06 15:24 Arthur Chunqi Li
2013-06-07  2:14 ` 李春奇 <Arthur Chunqi Li>
2013-06-12 20:50 ` Paolo Bonzini
2013-06-13  4:50   ` 李春奇 <Arthur Chunqi Li>
2013-06-13  9:30     ` 李春奇 <Arthur Chunqi Li>
2013-06-13 13:12       ` Paolo Bonzini
2013-06-18 12:45       ` Gleb Natapov
2013-06-18 13:40         ` 李春奇 <Arthur Chunqi Li>
2013-06-18 14:28         ` 李春奇 <Arthur Chunqi Li>
2013-06-18 15:47           ` Gleb Natapov
2013-06-18 15:56             ` 李春奇 <Arthur Chunqi Li>
2013-06-18 16:09               ` Gleb Natapov
2013-06-18 16:14                 ` 李春奇 <Arthur Chunqi Li>
2013-06-18 16:44                   ` Gleb Natapov
2013-06-19  1:26                     ` 李春奇 <Arthur Chunqi Li>
2013-06-19  9:31                       ` Gleb Natapov
2013-06-19 12:18                         ` 李春奇 <Arthur Chunqi Li>
2013-06-19 12:26                           ` Gleb Natapov
2013-06-19 12:30                             ` 李春奇 <Arthur Chunqi Li>
2013-06-19 12:32                               ` Gleb Natapov
2013-06-19 14:01                                 ` 李春奇 <Arthur Chunqi Li>
2013-06-19 14:13                                   ` Gleb Natapov
2013-06-19 14:20                                     ` 李春奇 <Arthur Chunqi Li>

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).