[PATCH] kvm-unit-tests: add a fetch instruction test case

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



BUG error infomation:

KVM internal error. Suberror: 1
emulation failure
RAX=0000000000463fe8 RBX=ffffffffffffd000 RCX=000000000000000c RDX=0000000000464006
RSI=0000000000000001 RDI=0000000000463000 RBP=0000000000452ce0 RSP=0000000000452c78
R8 =0000000000000000 R9 =0000000000410d7f R10=0000000000000000 R11=0000000000000000
R12=ffffffffffffe000 R13=1111111111111111 R14=3333333333333333 R15=00000000a06d39e8
RIP=ffffffffffffd000 RFL=00010002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 0000000000000000 ffffffff 00a09b00 DPL=0 CS64 [-RA]
SS =0010 0000000000000000 ffffffff 00c09300 DPL=0 DS   [-WA]

new test case emulates the situation.If patch "kvm/x86: propagate
fetch fault into guest" has merged, the test case can gracefully
handle #PF in guest and continue execute.
---
 lib/vmalloc.c  | 32 ++++++++++++++++++++++++++++++++
 lib/vmalloc.h  |  3 +++
 lib/x86/vm.c   |  5 +++++
 x86/emulator.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/lib/vmalloc.c b/lib/vmalloc.c
index b583786..1318163 100644
--- a/lib/vmalloc.c
+++ b/lib/vmalloc.c
@@ -54,6 +54,38 @@ void *vmap(phys_addr_t phys, size_t size)
 	return mem;
 }
 
+void unvmap(phys_addr_t phys,void * mem, size_t size)
+{
+	unsigned pages;
+	void * p = mem;
+	size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	pages = size / PAGE_SIZE;
+
+	phys &= ~(unsigned long long)(PAGE_SIZE - 1);
+	while (pages--) {
+		uninstall_page(page_root, phys, p);
+		phys += PAGE_SIZE;
+		p += PAGE_SIZE;
+	}
+	return;
+}
+
+void *revmap(phys_addr_t phys, void * mem, size_t size)
+{
+	void *p = mem;
+	unsigned pages;
+
+	size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	pages = size / PAGE_SIZE;
+
+	phys &= ~(unsigned long long)(PAGE_SIZE - 1);
+	while (pages--) {
+		install_page(page_root, phys, p);
+		phys += PAGE_SIZE;
+		p += PAGE_SIZE;
+	}
+    return mem;
+}
 static void *vm_memalign(size_t alignment, size_t size)
 {
 	void *mem, *p;
diff --git a/lib/vmalloc.h b/lib/vmalloc.h
index 3658b80..9eca9ec 100644
--- a/lib/vmalloc.h
+++ b/lib/vmalloc.h
@@ -11,7 +11,10 @@ extern void setup_vm(void);
 extern void *setup_mmu(phys_addr_t top);
 extern phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *virt);
 extern pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt);
+extern pteval_t *uninstall_page(pgd_t *pgtable, phys_addr_t phys, void *virt);
 
 void *vmap(phys_addr_t phys, size_t size);
+void *revmap(phys_addr_t phys, void * mem, size_t size);
+void unvmap(phys_addr_t phys,void * mem, size_t size);
 
 #endif
diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 73d9be4..6472da5 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -100,6 +100,11 @@ pteval_t *install_page(pgd_t *cr3, phys_addr_t phys, void *virt)
     return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0);
 }
 
+pteval_t *uninstall_page(pgd_t *cr3, phys_addr_t phys, void *virt)
+{
+	return install_pte(cr3, 1, virt, phys | PT_WRITABLE_MASK | PT_USER_MASK, 0);
+}
+
 void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt)
 {
 	phys_addr_t max = (u64)len + (u64)phys;
diff --git a/x86/emulator.c b/x86/emulator.c
index c856db4..9accb08 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -16,6 +16,8 @@ static int exceptions;
 #define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
 #define KVM_FEP_LENGTH 5
 static int fep_available = 1;
+static void *insn_page;
+static void *insn_ram;
 
 struct regs {
 	u64 rax, rbx, rcx, rdx;
@@ -33,6 +35,31 @@ struct insn_desc {
 
 static char st1[] = "abcdefghijklmnop";
 
+void do_pf_tss(void)
+{
+        printf("PF running\n");
+        revmap(virt_to_phys(insn_page), insn_ram, 4096);
+        invlpg(insn_ram);
+}
+
+extern void pf_tss(void);
+
+asm ("pf_tss: \n\t"
+#ifdef __x86_64__
+        // no task on x86_64, save/restore caller-save regs
+        "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n"
+        "push %r8; push %r9; push %r10; push %r11\n"
+#endif
+        "call do_pf_tss \n\t"
+#ifdef __x86_64__
+        "pop %r11; pop %r10; pop %r9; pop %r8\n"
+        "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n"
+#endif
+        "add $"S", %"R "sp\n\t" // discard error code
+        "iret"W" \n\t"
+        "jmp pf_tss\n\t"
+    );
+
 static void test_stringio(void)
 {
 	unsigned char r = 0;
@@ -714,6 +741,22 @@ static void test_rip_relative(unsigned *mem, char *insn_ram)
     report("movb $imm, 0(%%rip)", *mem == 0x10000);
 }
 
+static void test_fetch_insn(unsigned *mem, unsigned long phys, char *insn_ram)
+{
+    /* movb $1, mem+2(%rip) */
+    insn_ram[0] = 0xc6;
+    insn_ram[1] = 0x05;
+    *(unsigned *)&insn_ram[2] = 2 + (char *)mem - (insn_ram + 7);
+    insn_ram[6] = 0x01;
+    /* ret */
+    insn_ram[7] = 0xc3;
+    unvmap(phys, insn_ram, 4096);
+
+    *mem = 0;
+    asm("callq *%1" : "+m"(*mem) : "r"(insn_ram));
+    report("fetch insn", *mem == 0x10000);
+}
+
 static void test_shld_shrd(u32 *mem)
 {
     *mem = 0x12345678;
@@ -1018,12 +1061,11 @@ static void record_no_fep(struct ex_regs *regs)
 int main(void)
 {
 	void *mem;
-	void *insn_page;
-	void *insn_ram;
 	unsigned long t1, t2;
 
 	setup_vm();
 	setup_idt();
+	setup_alt_stack();
 	handle_exception(UD_VECTOR, record_no_fep);
 	asm(KVM_FEP "nop");
 	handle_exception(UD_VECTOR, 0);
@@ -1068,6 +1110,10 @@ int main(void)
 	test_sse(mem);
 	test_mmx(mem);
 	test_rip_relative(mem, insn_ram);
+	/* fetch insn test need handle #PF in guest */
+	set_intr_alt_stack(14, pf_tss);
+	test_fetch_insn(mem, virt_to_phys(insn_page), insn_ram);
+
 	test_shld_shrd(mem);
 	//test_lgdt_lidt(mem);
 	test_sreg(mem);
-- 
1.8.3.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux