* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-06 15:24 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
@ 2013-06-06 15:24 ` Arthur Chunqi Li
2013-06-12 20:51 ` Paolo Bonzini
0 siblings, 1 reply; 25+ messages in thread
From: Arthur Chunqi Li @ 2013-06-06 15:24 UTC (permalink / raw)
To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 66 ++++++++++++--------------------------------------------
1 file changed, 14 insertions(+), 52 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index 8ab9904..fa8993f 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -776,72 +776,34 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
+ uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
-
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
+
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 3);
// exit MMX mode
asm volatile("fnclex; emms");
- report("movq mmx generates #MF", exceptions == 1);
+ report("movq mmx generates #MF2", exceptions == 1);
handle_exception(MF_VECTOR, 0);
}
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ // mov $0xc3c3c3c3c3c3c3c3, %rcx
+ uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
+ inregs = (struct regs){ .rcx = 0 };
+
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 10);
+ report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ 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-07 2:31 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-09 11:07 ` [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Gleb Natapov
0 siblings, 2 replies; 25+ 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] 25+ messages in thread
* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-07 2:31 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
@ 2013-06-07 2:31 ` Arthur Chunqi Li
2013-06-09 11:07 ` [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Gleb Natapov
1 sibling, 0 replies; 25+ messages in thread
From: Arthur Chunqi Li @ 2013-06-07 2:31 UTC (permalink / raw)
To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 66 ++++++++++++--------------------------------------------
1 file changed, 14 insertions(+), 52 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index 770e8f7..f8a204e 100755
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -762,72 +762,34 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
+ uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
-
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
+
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 3);
// exit MMX mode
asm volatile("fnclex; emms");
- report("movq mmx generates #MF", exceptions == 1);
+ report("movq mmx generates #MF2", exceptions == 1);
handle_exception(MF_VECTOR, 0);
}
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ // mov $0xc3c3c3c3c3c3c3c3, %rcx
+ uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
+ inregs = (struct regs){ .rcx = 0 };
+
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 10);
+ report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-07 2:31 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
2013-06-07 2:31 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
@ 2013-06-09 11:07 ` Gleb Natapov
2013-06-09 12:44 ` 李春奇 <Arthur Chunqi Li>
1 sibling, 1 reply; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 11:07 UTC (permalink / raw)
To: Arthur Chunqi Li; +Cc: kvm, pbonzini
On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> 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.
>
Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
%rax because trapping instruction uses it? Use one that does not use
register at all: MOV r/m32, imm32
%rsp and %rbp because of ret on instruction page? Use the same trick
realmode.c test uses: have the code that sets/saves registers in
insn_page/alt_insn_page itself and copy the instruction you want to test
into the page itself instead of doing call.
Not sure what is so special about %rflags.
> 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
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 11:07 ` [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Gleb Natapov
@ 2013-06-09 12:44 ` 李春奇 <Arthur Chunqi Li>
2013-06-09 12:49 ` Gleb Natapov
0 siblings, 1 reply; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-09 12:44 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm, Paolo Bonzini
On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
>> 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.
>>
> Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
>
> %rax because trapping instruction uses it? Use one that does not use
> register at all: MOV r/m32, imm32
I don't know why set %rax before call alt_insn_page can cause error. I
use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
correctly.
>
> %rsp and %rbp because of ret on instruction page? Use the same trick
> realmode.c test uses: have the code that sets/saves registers in
> insn_page/alt_insn_page itself and copy the instruction you want to test
> into the page itself instead of doing call.
I don't know how instructions between calling insn_page and
alt_insn_page are executed (function install_page and some other
instructions before call *%1". If these insns are executed after
insn_page is called, changes before the trapping instruction may
affect the executing of these instructions.
>
> Not sure what is so special about %rflags.
>
>> 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
>
> --
> Gleb.
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
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 13:22 ` 李春奇 <Arthur Chunqi Li>
0 siblings, 2 replies; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 12:49 UTC (permalink / raw)
To: 李春奇 <Arthur Chunqi Li>; +Cc: kvm, Paolo Bonzini
On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> >> 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.
> >>
> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
> >
> > %rax because trapping instruction uses it? Use one that does not use
> > register at all: MOV r/m32, imm32
> I don't know why set %rax before call alt_insn_page can cause error. I
> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
> correctly.
We better find this out :)
> >
> > %rsp and %rbp because of ret on instruction page? Use the same trick
> > realmode.c test uses: have the code that sets/saves registers in
> > insn_page/alt_insn_page itself and copy the instruction you want to test
> > into the page itself instead of doing call.
> I don't know how instructions between calling insn_page and
> alt_insn_page are executed (function install_page and some other
> instructions before call *%1". If these insns are executed after
> insn_page is called, changes before the trapping instruction may
> affect the executing of these instructions.
>
Not sure what do you mean here.
> >
> > Not sure what is so special about %rflags.
> >
> >> 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
> >
> > --
> > Gleb.
>
>
>
> --
> Arthur Chunqi Li
> Department of Computer Science
> School of EECS
> Peking University
> Beijing, China
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
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>
1 sibling, 1 reply; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-09 12:56 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm, Paolo Bonzini
On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
>> >> 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.
>> >>
>> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
>> >
>> > %rax because trapping instruction uses it? Use one that does not use
>> > register at all: MOV r/m32, imm32
>> I don't know why set %rax before call alt_insn_page can cause error. I
>> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
>> correctly.
> We better find this out :)
I will try to trace it.
>
>> >
>> > %rsp and %rbp because of ret on instruction page? Use the same trick
>> > realmode.c test uses: have the code that sets/saves registers in
>> > insn_page/alt_insn_page itself and copy the instruction you want to test
>> > into the page itself instead of doing call.
>> I don't know how instructions between calling insn_page and
>> alt_insn_page are executed (function install_page and some other
>> instructions before call *%1". If these insns are executed after
>> insn_page is called, changes before the trapping instruction may
>> affect the executing of these instructions.
>>
> Not sure what do you mean here.
Simply, I mean what is the executing sequence in that piece of codes.
Why instruction in alt_insn_page will be emulated?
>
>> >
>> > Not sure what is so special about %rflags.
>> >
>> >> 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
>> >
>> > --
>> > Gleb.
>>
>>
>>
>> --
>> Arthur Chunqi Li
>> Department of Computer Science
>> School of EECS
>> Peking University
>> Beijing, China
>
> --
> Gleb.
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 12:56 ` 李春奇 <Arthur Chunqi Li>
@ 2013-06-09 12:58 ` Gleb Natapov
0 siblings, 0 replies; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 12:58 UTC (permalink / raw)
To: 李春奇 <Arthur Chunqi Li>; +Cc: kvm, Paolo Bonzini
On Sun, Jun 09, 2013 at 08:56:04PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> >> >> 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.
> >> >>
> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
> >> >
> >> > %rax because trapping instruction uses it? Use one that does not use
> >> > register at all: MOV r/m32, imm32
> >> I don't know why set %rax before call alt_insn_page can cause error. I
> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
> >> correctly.
> > We better find this out :)
> I will try to trace it.
> >
> >> >
> >> > %rsp and %rbp because of ret on instruction page? Use the same trick
> >> > realmode.c test uses: have the code that sets/saves registers in
> >> > insn_page/alt_insn_page itself and copy the instruction you want to test
> >> > into the page itself instead of doing call.
> >> I don't know how instructions between calling insn_page and
> >> alt_insn_page are executed (function install_page and some other
> >> instructions before call *%1". If these insns are executed after
> >> insn_page is called, changes before the trapping instruction may
> >> affect the executing of these instructions.
> >>
> > Not sure what do you mean here.
> Simply, I mean what is the executing sequence in that piece of codes.
> Why instruction in alt_insn_page will be emulated?
>
For the same reason it is emulated now. The trick is to have trapping
instruction and instruction we want to emulate at the same offset on
insn_page and alt_insn_page. Now the offset is 0, but it does not have
to be.
> >> >
> >> > Not sure what is so special about %rflags.
> >> >
> >> >> 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
> >> >
> >> > --
> >> > Gleb.
> >>
> >>
> >>
> >> --
> >> Arthur Chunqi Li
> >> Department of Computer Science
> >> School of EECS
> >> Peking University
> >> Beijing, China
> >
> > --
> > Gleb.
>
>
>
> --
> Arthur Chunqi Li
> Department of Computer Science
> School of EECS
> Peking University
> Beijing, China
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 12:49 ` Gleb Natapov
2013-06-09 12:56 ` 李春奇 <Arthur Chunqi Li>
@ 2013-06-09 13:22 ` 李春奇 <Arthur Chunqi Li>
2013-06-09 14:09 ` Gleb Natapov
1 sibling, 1 reply; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-09 13:22 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm, Paolo Bonzini
On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
>> >> 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.
>> >>
>> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
>> >
>> > %rax because trapping instruction uses it? Use one that does not use
>> > register at all: MOV r/m32, imm32
>> I don't know why set %rax before call alt_insn_page can cause error. I
>> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
>> correctly.
> We better find this out :)
I found that before calling alt_insn_page, address of "mem" is saved
to %rax, why?
>
>> >
>> > %rsp and %rbp because of ret on instruction page? Use the same trick
>> > realmode.c test uses: have the code that sets/saves registers in
>> > insn_page/alt_insn_page itself and copy the instruction you want to test
>> > into the page itself instead of doing call.
>> I don't know how instructions between calling insn_page and
>> alt_insn_page are executed (function install_page and some other
>> instructions before call *%1". If these insns are executed after
>> insn_page is called, changes before the trapping instruction may
>> affect the executing of these instructions.
>>
> Not sure what do you mean here.
>
>> >
>> > Not sure what is so special about %rflags.
>> >
>> >> 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
>> >
>> > --
>> > Gleb.
>>
>>
>>
>> --
>> Arthur Chunqi Li
>> Department of Computer Science
>> School of EECS
>> Peking University
>> Beijing, China
>
> --
> Gleb.
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 13:22 ` 李春奇 <Arthur Chunqi Li>
@ 2013-06-09 14:09 ` Gleb Natapov
2013-06-09 15:23 ` 李春奇 <Arthur Chunqi Li>
0 siblings, 1 reply; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 14:09 UTC (permalink / raw)
To: 李春奇 <Arthur Chunqi Li>; +Cc: kvm, Paolo Bonzini
On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> >> >> 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.
> >> >>
> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
> >> >
> >> > %rax because trapping instruction uses it? Use one that does not use
> >> > register at all: MOV r/m32, imm32
> >> I don't know why set %rax before call alt_insn_page can cause error. I
> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
> >> correctly.
> > We better find this out :)
> I found that before calling alt_insn_page, address of "mem" is saved
> to %rax, why?
Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
MMOI address mem is loaded into %rax before jumping into it.
> >
> >> >
> >> > %rsp and %rbp because of ret on instruction page? Use the same trick
> >> > realmode.c test uses: have the code that sets/saves registers in
> >> > insn_page/alt_insn_page itself and copy the instruction you want to test
> >> > into the page itself instead of doing call.
> >> I don't know how instructions between calling insn_page and
> >> alt_insn_page are executed (function install_page and some other
> >> instructions before call *%1". If these insns are executed after
> >> insn_page is called, changes before the trapping instruction may
> >> affect the executing of these instructions.
> >>
> > Not sure what do you mean here.
> >
> >> >
> >> > Not sure what is so special about %rflags.
> >> >
> >> >> 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
> >> >
> >> > --
> >> > Gleb.
> >>
> >>
> >>
> >> --
> >> Arthur Chunqi Li
> >> Department of Computer Science
> >> School of EECS
> >> Peking University
> >> Beijing, China
> >
> > --
> > Gleb.
>
>
>
> --
> Arthur Chunqi Li
> Department of Computer Science
> School of EECS
> Peking University
> Beijing, China
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 14:09 ` Gleb Natapov
@ 2013-06-09 15:23 ` 李春奇 <Arthur Chunqi Li>
2013-06-09 16:00 ` Gleb Natapov
0 siblings, 1 reply; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-09 15:23 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm, Paolo Bonzini
On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov <gleb@redhat.com> wrote:
> On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
>> >> >> 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.
>> >> >>
>> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
>> >> >
>> >> > %rax because trapping instruction uses it? Use one that does not use
>> >> > register at all: MOV r/m32, imm32
>> >> I don't know why set %rax before call alt_insn_page can cause error. I
>> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
>> >> correctly.
>> > We better find this out :)
>> I found that before calling alt_insn_page, address of "mem" is saved
>> to %rax, why?
> Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
> MMOI address mem is loaded into %rax before jumping into it.
I think this is why changing %rax will cause error. If we use mov
%eax, (%rax) to trigger vmexit, and %rax is changed before calling
alt_insn_page, codes in alt_insn_page will not be executed and return
directly.
I changed the codes which trigger vmexit to "mov %eax, (%r8)" and set
"mem" to %r8 before calling alt_insn_page, it runs OK.
Besides, I also don't know if changed %rflags may cause some
unpredictable actions, so now we just treat it with no error :)
>
>> >
>> >> >
>> >> > %rsp and %rbp because of ret on instruction page? Use the same trick
>> >> > realmode.c test uses: have the code that sets/saves registers in
>> >> > insn_page/alt_insn_page itself and copy the instruction you want to test
>> >> > into the page itself instead of doing call.
>> >> I don't know how instructions between calling insn_page and
>> >> alt_insn_page are executed (function install_page and some other
>> >> instructions before call *%1". If these insns are executed after
>> >> insn_page is called, changes before the trapping instruction may
>> >> affect the executing of these instructions.
>> >>
>> > Not sure what do you mean here.
>> >
>> >> >
>> >> > Not sure what is so special about %rflags.
>> >> >
>> >> >> 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
>> >> >
>> >> > --
>> >> > Gleb.
>> >>
>> >>
>> >>
>> >> --
>> >> Arthur Chunqi Li
>> >> Department of Computer Science
>> >> School of EECS
>> >> Peking University
>> >> Beijing, China
>> >
>> > --
>> > Gleb.
>>
>>
>>
>> --
>> Arthur Chunqi Li
>> Department of Computer Science
>> School of EECS
>> Peking University
>> Beijing, China
>
> --
> Gleb.
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 15:23 ` 李春奇 <Arthur Chunqi Li>
@ 2013-06-09 16:00 ` Gleb Natapov
2013-06-09 17:09 ` 李春奇 <Arthur Chunqi Li>
0 siblings, 1 reply; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 16:00 UTC (permalink / raw)
To: 李春奇 <Arthur Chunqi Li>; +Cc: kvm, Paolo Bonzini
On Sun, Jun 09, 2013 at 11:23:26PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> >> >> >> 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.
> >> >> >>
> >> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
> >> >> >
> >> >> > %rax because trapping instruction uses it? Use one that does not use
> >> >> > register at all: MOV r/m32, imm32
> >> >> I don't know why set %rax before call alt_insn_page can cause error. I
> >> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
> >> >> correctly.
> >> > We better find this out :)
> >> I found that before calling alt_insn_page, address of "mem" is saved
> >> to %rax, why?
> > Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
> > MMOI address mem is loaded into %rax before jumping into it.
> I think this is why changing %rax will cause error. If we use mov
> %eax, (%rax) to trigger vmexit, and %rax is changed before calling
> alt_insn_page, codes in alt_insn_page will not be executed and return
> directly.
> I changed the codes which trigger vmexit to "mov %eax, (%r8)" and set
> "mem" to %r8 before calling alt_insn_page, it runs OK.
>
Just use an instruction that does not use registers at all. mov $1, addr
where addr is immediate and encoded from mem parameter.
> Besides, I also don't know if changed %rflags may cause some
> unpredictable actions, so now we just treat it with no error :)
If test sets rflags to a value that causes crashes this is a test bug,
no need to prevent this from happening.
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 16:00 ` Gleb Natapov
@ 2013-06-09 17:09 ` 李春奇 <Arthur Chunqi Li>
2013-06-09 17:13 ` Gleb Natapov
0 siblings, 1 reply; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-09 17:09 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm, Paolo Bonzini
I have finished the infrastructure but after changing test_mmx_movq_mf
test case, it return error:
unhandled excecption 6
Return value from qemu: 15
If I don't change %rsp and %rbp, it runs OK.
So I wonder if this test case is strictly reply on %rsp and %rbp?
On Mon, Jun 10, 2013 at 12:00 AM, Gleb Natapov <gleb@redhat.com> wrote:
> On Sun, Jun 09, 2013 at 11:23:26PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> > On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> >> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> >> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> >> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> >> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
>> >> >> >> 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.
>> >> >> >>
>> >> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
>> >> >> >
>> >> >> > %rax because trapping instruction uses it? Use one that does not use
>> >> >> > register at all: MOV r/m32, imm32
>> >> >> I don't know why set %rax before call alt_insn_page can cause error. I
>> >> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
>> >> >> correctly.
>> >> > We better find this out :)
>> >> I found that before calling alt_insn_page, address of "mem" is saved
>> >> to %rax, why?
>> > Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
>> > MMOI address mem is loaded into %rax before jumping into it.
>> I think this is why changing %rax will cause error. If we use mov
>> %eax, (%rax) to trigger vmexit, and %rax is changed before calling
>> alt_insn_page, codes in alt_insn_page will not be executed and return
>> directly.
>> I changed the codes which trigger vmexit to "mov %eax, (%r8)" and set
>> "mem" to %r8 before calling alt_insn_page, it runs OK.
>>
> Just use an instruction that does not use registers at all. mov $1, addr
> where addr is immediate and encoded from mem parameter.
>
>> Besides, I also don't know if changed %rflags may cause some
>> unpredictable actions, so now we just treat it with no error :)
> If test sets rflags to a value that causes crashes this is a test bug,
> no need to prevent this from happening.
>
> --
> Gleb.
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 17:09 ` 李春奇 <Arthur Chunqi Li>
@ 2013-06-09 17:13 ` Gleb Natapov
2013-06-09 17:28 ` 李春奇 <Arthur Chunqi Li>
0 siblings, 1 reply; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 17:13 UTC (permalink / raw)
To: 李春奇 <Arthur Chunqi Li>; +Cc: kvm, Paolo Bonzini
On Mon, Jun 10, 2013 at 01:09:15AM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> I have finished the infrastructure but after changing test_mmx_movq_mf
> test case, it return error:
> unhandled excecption 6
> Return value from qemu: 15
>
> If I don't change %rsp and %rbp, it runs OK.
> So I wonder if this test case is strictly reply on %rsp and %rbp?
>
I can't help without seeing the code.
> On Mon, Jun 10, 2013 at 12:00 AM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Sun, Jun 09, 2013 at 11:23:26PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> > On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> >> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> >> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> >> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> >> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> >> >> >> >> 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.
> >> >> >> >>
> >> >> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
> >> >> >> >
> >> >> >> > %rax because trapping instruction uses it? Use one that does not use
> >> >> >> > register at all: MOV r/m32, imm32
> >> >> >> I don't know why set %rax before call alt_insn_page can cause error. I
> >> >> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
> >> >> >> correctly.
> >> >> > We better find this out :)
> >> >> I found that before calling alt_insn_page, address of "mem" is saved
> >> >> to %rax, why?
> >> > Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
> >> > MMOI address mem is loaded into %rax before jumping into it.
> >> I think this is why changing %rax will cause error. If we use mov
> >> %eax, (%rax) to trigger vmexit, and %rax is changed before calling
> >> alt_insn_page, codes in alt_insn_page will not be executed and return
> >> directly.
> >> I changed the codes which trigger vmexit to "mov %eax, (%r8)" and set
> >> "mem" to %r8 before calling alt_insn_page, it runs OK.
> >>
> > Just use an instruction that does not use registers at all. mov $1, addr
> > where addr is immediate and encoded from mem parameter.
> >
> >> Besides, I also don't know if changed %rflags may cause some
> >> unpredictable actions, so now we just treat it with no error :)
> > If test sets rflags to a value that causes crashes this is a test bug,
> > no need to prevent this from happening.
> >
> > --
> > Gleb.
>
>
>
> --
> Arthur Chunqi Li
> Department of Computer Science
> School of EECS
> Peking University
> Beijing, China
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 17:13 ` Gleb Natapov
@ 2013-06-09 17:28 ` 李春奇 <Arthur Chunqi Li>
2013-06-09 17:39 ` Gleb Natapov
0 siblings, 1 reply; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-09 17:28 UTC (permalink / raw)
To: Gleb Natapov; +Cc: kvm, Paolo Bonzini
I have trouble to send the address of inregs into alt_insn_page, so I
use r9 and r10 to carry %rsp and %rbp into it. And r8 is used to
trigger vmexit.
I paste the relevant functions as follows:
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, 0x90, 4096);
memset(alt_insn_page, 0x90, 4096);
// Place a trapping instruction in the page to trigger a VMEXIT
insn_page[0] = 0x49; //xchg %rsp, %r9
insn_page[1] = 0x87;
insn_page[2] = 0xe1;
insn_page[3] = 0x49; //xchg %rbp, %r10
insn_page[4] = 0x87;
insn_page[5] = 0xea;
insn_page[6] = 0x41; // mov %eax, (%r8)
insn_page[7] = 0x89;
insn_page[8] = 0x00; // 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+6] = alt_insn[i];
i+=6;
insn_page[i++] = 0x49; //xchg %rsp, %r9
insn_page[i++] = 0x87;
insn_page[i++] = 0xe1;
insn_page[i++] = 0x49; //xchg %rbp, %r10
insn_page[i++] = 0x87;
insn_page[i++] = 0xea;
insn_page[i++] = 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(
"mov %2, %%r8\n\r"
"push 72+%[save]; 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 %%r9, 48+%[save] \n\t" // %rsp in %r9
"xchg %%r10, 56+%[save] \n\t" // %rbp in %r10
"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" // %rsp in %r9
"xchg %%r10, 56+%[save] \n\t" // %rbp in %r10
/* Save RFLAGS in outregs*/
"pushf \n\t"
"pop 72+%[save] \n\t"
: [save]"=m"(save)
: "r"(insn_ram), "r"(mem)
: "memory", "cc", "r9", "r10", "r8"
);
outregs = save;
}
static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
uint16_t fcw = 0; // all exceptions unmasked
uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
write_cr0(read_cr0() & ~6); // TS, EM
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
asm volatile("fldz; fldz; fdivp"); // generate exception
inregs = (struct regs){ .rsp=0, .rbp=0 };
trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
alt_insn, 3);
// exit MMX mode
asm volatile("fnclex; emms");
report("movq mmx generates #MF2", exceptions == 1);
handle_exception(MF_VECTOR, 0);
}
On Mon, Jun 10, 2013 at 1:13 AM, Gleb Natapov <gleb@redhat.com> wrote:
> On Mon, Jun 10, 2013 at 01:09:15AM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> I have finished the infrastructure but after changing test_mmx_movq_mf
>> test case, it return error:
>> unhandled excecption 6
>> Return value from qemu: 15
>>
>> If I don't change %rsp and %rbp, it runs OK.
>> So I wonder if this test case is strictly reply on %rsp and %rbp?
>>
> I can't help without seeing the code.
>
>> On Mon, Jun 10, 2013 at 12:00 AM, Gleb Natapov <gleb@redhat.com> wrote:
>> > On Sun, Jun 09, 2013 at 11:23:26PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> >> On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> >> > On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> >> >> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> >> >> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
>> >> >> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
>> >> >> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
>> >> >> >> >> 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.
>> >> >> >> >>
>> >> >> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
>> >> >> >> >
>> >> >> >> > %rax because trapping instruction uses it? Use one that does not use
>> >> >> >> > register at all: MOV r/m32, imm32
>> >> >> >> I don't know why set %rax before call alt_insn_page can cause error. I
>> >> >> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
>> >> >> >> correctly.
>> >> >> > We better find this out :)
>> >> >> I found that before calling alt_insn_page, address of "mem" is saved
>> >> >> to %rax, why?
>> >> > Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
>> >> > MMOI address mem is loaded into %rax before jumping into it.
>> >> I think this is why changing %rax will cause error. If we use mov
>> >> %eax, (%rax) to trigger vmexit, and %rax is changed before calling
>> >> alt_insn_page, codes in alt_insn_page will not be executed and return
>> >> directly.
>> >> I changed the codes which trigger vmexit to "mov %eax, (%r8)" and set
>> >> "mem" to %r8 before calling alt_insn_page, it runs OK.
>> >>
>> > Just use an instruction that does not use registers at all. mov $1, addr
>> > where addr is immediate and encoded from mem parameter.
>> >
>> >> Besides, I also don't know if changed %rflags may cause some
>> >> unpredictable actions, so now we just treat it with no error :)
>> > If test sets rflags to a value that causes crashes this is a test bug,
>> > no need to prevent this from happening.
>> >
>> > --
>> > Gleb.
>>
>>
>>
>> --
>> Arthur Chunqi Li
>> Department of Computer Science
>> School of EECS
>> Peking University
>> Beijing, China
>
> --
> Gleb.
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator
2013-06-09 17:28 ` 李春奇 <Arthur Chunqi Li>
@ 2013-06-09 17:39 ` Gleb Natapov
0 siblings, 0 replies; 25+ messages in thread
From: Gleb Natapov @ 2013-06-09 17:39 UTC (permalink / raw)
To: 李春奇 <Arthur Chunqi Li>; +Cc: kvm, Paolo Bonzini
On Mon, Jun 10, 2013 at 01:28:48AM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> I have trouble to send the address of inregs into alt_insn_page, so I
> use r9 and r10 to carry %rsp and %rbp into it. And r8 is used to
> trigger vmexit.
>
If you going to use call you will need stack. I said how not to use it
and how not to use register for trapping instruction since you cannot
use r[0-7] registers because we will obviously want them to be part of
inregs/outreg.
> I paste the relevant functions as follows:
>
>
> 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, 0x90, 4096);
> memset(alt_insn_page, 0x90, 4096);
>
> // Place a trapping instruction in the page to trigger a VMEXIT
> insn_page[0] = 0x49; //xchg %rsp, %r9
> insn_page[1] = 0x87;
> insn_page[2] = 0xe1;
> insn_page[3] = 0x49; //xchg %rbp, %r10
> insn_page[4] = 0x87;
> insn_page[5] = 0xea;
> insn_page[6] = 0x41; // mov %eax, (%r8)
> insn_page[7] = 0x89;
> insn_page[8] = 0x00; // 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+6] = alt_insn[i];
> i+=6;
> insn_page[i++] = 0x49; //xchg %rsp, %r9
> insn_page[i++] = 0x87;
> insn_page[i++] = 0xe1;
> insn_page[i++] = 0x49; //xchg %rbp, %r10
> insn_page[i++] = 0x87;
> insn_page[i++] = 0xea;
> insn_page[i++] = 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(
> "mov %2, %%r8\n\r"
> "push 72+%[save]; 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 %%r9, 48+%[save] \n\t" // %rsp in %r9
> "xchg %%r10, 56+%[save] \n\t" // %rbp in %r10
>
> "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" // %rsp in %r9
> "xchg %%r10, 56+%[save] \n\t" // %rbp in %r10
> /* Save RFLAGS in outregs*/
> "pushf \n\t"
> "pop 72+%[save] \n\t"
> : [save]"=m"(save)
> : "r"(insn_ram), "r"(mem)
> : "memory", "cc", "r9", "r10", "r8"
> );
> outregs = save;
> }
>
>
> static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> uint16_t fcw = 0; // all exceptions unmasked
> uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
>
> write_cr0(read_cr0() & ~6); // TS, EM
> exceptions = 0;
> handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
> asm volatile("fninit; fldcw %0" : : "m"(fcw));
> asm volatile("fldz; fldz; fdivp"); // generate exception
>
> inregs = (struct regs){ .rsp=0, .rbp=0 };
> trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
> alt_insn, 3);
> // exit MMX mode
> asm volatile("fnclex; emms");
> report("movq mmx generates #MF2", exceptions == 1);
> handle_exception(MF_VECTOR, 0);
> }
>
> On Mon, Jun 10, 2013 at 1:13 AM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Mon, Jun 10, 2013 at 01:09:15AM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> I have finished the infrastructure but after changing test_mmx_movq_mf
> >> test case, it return error:
> >> unhandled excecption 6
> >> Return value from qemu: 15
> >>
> >> If I don't change %rsp and %rbp, it runs OK.
> >> So I wonder if this test case is strictly reply on %rsp and %rbp?
> >>
> > I can't help without seeing the code.
> >
> >> On Mon, Jun 10, 2013 at 12:00 AM, Gleb Natapov <gleb@redhat.com> wrote:
> >> > On Sun, Jun 09, 2013 at 11:23:26PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> >> On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> >> > On Sun, Jun 09, 2013 at 09:22:27PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> >> >> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> >> >> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, 李春奇 <Arthur Chunqi Li> wrote:
> >> >> >> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov <gleb@redhat.com> wrote:
> >> >> >> >> > On Fri, Jun 07, 2013 at 10:31:38AM +0800, Arthur Chunqi Li wrote:
> >> >> >> >> >> 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.
> >> >> >> >> >>
> >> >> >> >> > Why %rax, %rsp, %rbp, %rflags cannot be set in inregs?
> >> >> >> >> >
> >> >> >> >> > %rax because trapping instruction uses it? Use one that does not use
> >> >> >> >> > register at all: MOV r/m32, imm32
> >> >> >> >> I don't know why set %rax before call alt_insn_page can cause error. I
> >> >> >> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rcx is not set
> >> >> >> >> correctly.
> >> >> >> > We better find this out :)
> >> >> >> I found that before calling alt_insn_page, address of "mem" is saved
> >> >> >> to %rax, why?
> >> >> > Because instruction that we use to trigger vmexit is mov %eax, (%rax) so
> >> >> > MMOI address mem is loaded into %rax before jumping into it.
> >> >> I think this is why changing %rax will cause error. If we use mov
> >> >> %eax, (%rax) to trigger vmexit, and %rax is changed before calling
> >> >> alt_insn_page, codes in alt_insn_page will not be executed and return
> >> >> directly.
> >> >> I changed the codes which trigger vmexit to "mov %eax, (%r8)" and set
> >> >> "mem" to %r8 before calling alt_insn_page, it runs OK.
> >> >>
> >> > Just use an instruction that does not use registers at all. mov $1, addr
> >> > where addr is immediate and encoded from mem parameter.
> >> >
> >> >> Besides, I also don't know if changed %rflags may cause some
> >> >> unpredictable actions, so now we just treat it with no error :)
> >> > If test sets rflags to a value that causes crashes this is a test bug,
> >> > no need to prevent this from happening.
> >> >
> >> > --
> >> > Gleb.
> >>
> >>
> >>
> >> --
> >> Arthur Chunqi Li
> >> Department of Computer Science
> >> School of EECS
> >> Peking University
> >> Beijing, China
> >
> > --
> > Gleb.
>
>
>
> --
> Arthur Chunqi Li
> Department of Computer Science
> School of EECS
> Peking University
> Beijing, China
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-10 13:38 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
@ 2013-06-10 13:38 ` Arthur Chunqi Li
0 siblings, 0 replies; 25+ messages in thread
From: Arthur Chunqi Li @ 2013-06-10 13:38 UTC (permalink / raw)
To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 65 ++++++++++++--------------------------------------------
1 file changed, 13 insertions(+), 52 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index a1bd92e..4ad6f5e 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -801,72 +801,33 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
+ uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
-
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
+
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 3, 1);
// exit MMX mode
asm volatile("fnclex; emms");
- report("movq mmx generates #MF", exceptions == 1);
+ report("movq mmx generates #MF2", exceptions == 1);
handle_exception(MF_VECTOR, 0);
}
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ // mov $0xc3c3c3c3c3c3c3c3, %rcx
+ uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
+ inregs = (struct regs){ .rcx = 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 10, 1);
+ report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
@ 2013-06-10 13:45 Arthur Chunqi Li
2013-06-10 13:46 ` 李春奇 <Arthur Chunqi Li>
0 siblings, 1 reply; 25+ messages in thread
From: Arthur Chunqi Li @ 2013-06-10 13:45 UTC (permalink / raw)
To: kvm; +Cc: gleb, pbonzini, Arthur Chunqi Li
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 63 +++++++++++---------------------------------------------
1 file changed, 12 insertions(+), 51 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index a1bd92e..c73c766 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -801,36 +801,17 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
+ uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
-
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
+
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 3, 1);
// exit MMX mode
asm volatile("fnclex; emms");
report("movq mmx generates #MF", exceptions == 1);
@@ -840,33 +821,13 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ // mov $0xc3c3c3c3c3c3c3c3, %rcx
+ uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
+ inregs = (struct regs){ .rcx = 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 10, 1);
+ report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-10 13:45 Arthur Chunqi Li
@ 2013-06-10 13:46 ` 李春奇 <Arthur Chunqi Li>
0 siblings, 0 replies; 25+ messages in thread
From: 李春奇 <Arthur Chunqi Li> @ 2013-06-10 13:46 UTC (permalink / raw)
To: kvm; +Cc: Gleb Natapov, Paolo Bonzini, Arthur Chunqi Li
Sorry, there are some small mistakes in the first path, recommit it.
Arthur
On Mon, Jun 10, 2013 at 9:45 PM, Arthur Chunqi Li <yzt356@gmail.com> wrote:
> Change two functions (test_mmx_movq_mf and test_movabs) using
> unified trap_emulator.
>
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
> x86/emulator.c | 63 +++++++++++---------------------------------------------
> 1 file changed, 12 insertions(+), 51 deletions(-)
>
> diff --git a/x86/emulator.c b/x86/emulator.c
> index a1bd92e..c73c766 100644
> --- a/x86/emulator.c
> +++ b/x86/emulator.c
> @@ -801,36 +801,17 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> uint16_t fcw = 0; // all exceptions unmasked
> - ulong *cr3 = (ulong *)read_cr3();
> + uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
>
> write_cr0(read_cr0() & ~6); // TS, EM
> - // 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
> - alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
> - alt_insn_page[1] = 0x7f;
> - alt_insn_page[2] = 0x00;
> - alt_insn_page[3] = 0xc3; // ret
> -
> exceptions = 0;
> handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
> -
> - // 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);
> asm volatile("fninit; fldcw %0" : : "m"(fcw));
> asm volatile("fldz; fldz; fdivp"); // generate exception
> - 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 *%0" : : "r"(insn_ram), "a"(mem));
> +
> + inregs = (struct regs){ 0 };
> + trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
> + alt_insn, 3, 1);
> // exit MMX mode
> asm volatile("fnclex; emms");
> report("movq mmx generates #MF", exceptions == 1);
> @@ -840,33 +821,13 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
> static void test_movabs(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> - uint64_t val = 0;
> - ulong *cr3 = (ulong *)read_cr3();
> -
> - // 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;
> - // Place the instruction we want the hypervisor to see in the alternate
> - // page. A buggy hypervisor will fetch a 32-bit immediate and return
> - // 0xffffffffc3c3c3c3.
> - alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
> - alt_insn_page[1] = 0xb9;
> -
> - // 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);
> - // Load code TLB
> - invlpg(insn_ram);
> - asm volatile("call *%0" : : "r"(insn_ram + 3));
> - // Trap, let hypervisor emulate at alt_insn_page
> - install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
> - asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
> - report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
> + // mov $0xc3c3c3c3c3c3c3c3, %rcx
> + uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
> + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
> + inregs = (struct regs){ .rcx = 0 };
> + trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
> + alt_insn, 10, 1);
> + report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
> }
>
> static void test_crosspage_mmio(volatile uint8_t *mem)
> --
> 1.7.9.5
>
--
Arthur Chunqi Li
Department of Computer Science
School of EECS
Peking University
Beijing, China
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-06 15:24 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
@ 2013-06-12 20:51 ` Paolo Bonzini
0 siblings, 0 replies; 25+ messages in thread
From: Paolo Bonzini @ 2013-06-12 20:51 UTC (permalink / raw)
To: Arthur Chunqi Li; +Cc: kvm, gleb
Il 06/06/2013 11:24, Arthur Chunqi Li ha scritto:
> Change two functions (test_mmx_movq_mf and test_movabs) using
> unified trap_emulator.
>
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
> x86/emulator.c | 66 ++++++++++++--------------------------------------------
> 1 file changed, 14 insertions(+), 52 deletions(-)
>
> diff --git a/x86/emulator.c b/x86/emulator.c
> index 8ab9904..fa8993f 100644
> --- a/x86/emulator.c
> +++ b/x86/emulator.c
> @@ -776,72 +776,34 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> uint16_t fcw = 0; // all exceptions unmasked
> - ulong *cr3 = (ulong *)read_cr3();
> + uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
>
> write_cr0(read_cr0() & ~6); // TS, EM
> - // 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
> - alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
> - alt_insn_page[1] = 0x7f;
> - alt_insn_page[2] = 0x00;
> - alt_insn_page[3] = 0xc3; // ret
> -
> exceptions = 0;
> handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
> -
> - // 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);
> asm volatile("fninit; fldcw %0" : : "m"(fcw));
> asm volatile("fldz; fldz; fdivp"); // generate exception
> - 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 *%0" : : "r"(insn_ram), "a"(mem));
> +
> + inregs = (struct regs){ 0 };
> + trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
> + alt_insn, 3);
> // exit MMX mode
> asm volatile("fnclex; emms");
> - report("movq mmx generates #MF", exceptions == 1);
> + report("movq mmx generates #MF2", exceptions == 1);
Extra hunk that is not needed? Otherwise it looks good.
Thanks,
Paolo
> handle_exception(MF_VECTOR, 0);
> }
>
> static void test_movabs(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> - uint64_t val = 0;
> - ulong *cr3 = (ulong *)read_cr3();
> -
> - // 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;
> - // Place the instruction we want the hypervisor to see in the alternate
> - // page. A buggy hypervisor will fetch a 32-bit immediate and return
> - // 0xffffffffc3c3c3c3.
> - alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
> - alt_insn_page[1] = 0xb9;
> -
> - // 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);
> - // Load code TLB
> - invlpg(insn_ram);
> - asm volatile("call *%0" : : "r"(insn_ram + 3));
> - // Trap, let hypervisor emulate at alt_insn_page
> - install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
> - asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
> - report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
> + // mov $0xc3c3c3c3c3c3c3c3, %rcx
> + uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
> + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
> + inregs = (struct regs){ .rcx = 0 };
> +
> + trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
> + alt_insn, 10);
> + report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
> }
>
> static void test_crosspage_mmio(volatile uint8_t *mem)
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-13 15:16 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
@ 2013-06-13 15:16 ` Arthur Chunqi Li
0 siblings, 0 replies; 25+ 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
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 85 +++++++++++++++-----------------------------------------
1 file changed, 23 insertions(+), 62 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index 4981bfb..7698f56 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -826,73 +826,34 @@ static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
-
- write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
-
- exceptions = 0;
- handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
- asm volatile("fninit; fldcw %0" : : "m"(fcw));
- asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
- // exit MMX mode
- asm volatile("fnclex; emms");
- report("movq mmx generates #MF", exceptions == 1);
- handle_exception(MF_VECTOR, 0);
+ uint16_t fcw = 0; // all exceptions unmasked
+ uint8_t alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
+
+ write_cr0(read_cr0() & ~6); // TS, EM
+ exceptions = 0;
+ handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
+ asm volatile("fninit; fldcw %0" : : "m"(fcw));
+ asm volatile("fldz; fldz; fdivp"); // generate exception
+
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 3, 1);
+ // exit MMX mode
+ asm volatile("fnclex; emms");
+ report("movq mmx generates #MF", exceptions == 1);
+ handle_exception(MF_VECTOR, 0);
}
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ // mov $0xc3c3c3c3c3c3c3c3, %rcx
+ uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
+ inregs = (struct regs){ .rbx = 0x5678, .rcx = 0x1234 };
+ trap_emulator(mem, insn_page, alt_insn_page, insn_ram,
+ alt_insn, 10, 1);
+ report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
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 ` Arthur Chunqi Li
2013-06-20 8:25 ` Paolo Bonzini
0 siblings, 1 reply; 25+ 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
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 62 ++++++++++----------------------------------------------
1 file changed, 11 insertions(+), 51 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index 48d45c8..701c578 100755
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -805,36 +805,17 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
+ u8 alt_insn[] = {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax)
+ void *stack = alloc_page();
write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
-
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
+
+ inregs = (struct regs){ .rsp=(u64)stack+1024 };
+ trap_emulator(mem, alt_insn, 3);
// exit MMX mode
asm volatile("fnclex; emms");
report("movq mmx generates #MF", exceptions == 1);
@@ -844,33 +825,12 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ // mov $0xc3c3c3c3c3c3c3c3, %rcx
+ uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, alt_insn, 10);
+ report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
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
0 siblings, 0 replies; 25+ messages in thread
From: Paolo Bonzini @ 2013-06-20 8:25 UTC (permalink / raw)
To: Arthur Chunqi Li; +Cc: kvm, gleb, jan.kiszka
Il 19/06/2013 17:00, Arthur Chunqi Li ha scritto:
> static void test_movabs(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> - uint64_t val = 0;
> - ulong *cr3 = (ulong *)read_cr3();
> -
> - // 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;
> - // Place the instruction we want the hypervisor to see in the alternate
> - // page. A buggy hypervisor will fetch a 32-bit immediate and return
> - // 0xffffffffc3c3c3c3.
> - alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
> - alt_insn_page[1] = 0xb9;
> -
> - // 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);
> - // Load code TLB
> - invlpg(insn_ram);
> - asm volatile("call *%0" : : "r"(insn_ram + 3));
> - // Trap, let hypervisor emulate at alt_insn_page
> - install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
> - asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
> - report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
> + // mov $0xc3c3c3c3c3c3c3c3, %rcx
> + uint8_t alt_insn[] = {0x48, 0xb9, 0xc3, 0xc3, 0xc3,
> + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3};
> + inregs = (struct regs){ 0 };
> + trap_emulator(mem, alt_insn, 10);
> + report("64-bit mov imm2", outregs.rcx == 0xc3c3c3c3c3c3c3c3);
> }
0xc3 is ret and it may mess up the test case if the buggy hypervisor
sees it as
mov $0xc3c3c3c3, %rcx (sign extended, no such instruction exists)
ret
ret
ret
ret
I suggest changing it to 0x90 as part of this patch.
Paolo
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-20 10:45 Arthur Chunqi Li
@ 2013-06-20 10:45 ` Arthur Chunqi Li
2013-06-20 12:33 ` Gleb Natapov
0 siblings, 1 reply; 25+ 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
Change two functions (test_mmx_movq_mf and test_movabs) using
unified trap_emulator.
Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
---
x86/emulator.c | 70 ++++++++++++--------------------------------------------
1 file changed, 15 insertions(+), 55 deletions(-)
diff --git a/x86/emulator.c b/x86/emulator.c
index b3626fa..16d63e0 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -772,38 +772,19 @@ static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint16_t fcw = 0; // all exceptions unmasked
- ulong *cr3 = (ulong *)read_cr3();
-
- write_cr0(read_cr0() & ~6); // TS, EM
- // 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
- alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
- alt_insn_page[1] = 0x7f;
- alt_insn_page[2] = 0x00;
- alt_insn_page[3] = 0xc3; // ret
+ uint16_t fcw = 0; /* all exceptions unmasked */
+ u8 alt_insn[] = {0x0f, 0x7f, 0x00}; /* movq %mm0, (%rax) */
+ void *stack = alloc_page();
+ write_cr0(read_cr0() & ~6); /* TS, EM */
exceptions = 0;
handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
-
- // 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);
asm volatile("fninit; fldcw %0" : : "m"(fcw));
- asm volatile("fldz; fldz; fdivp"); // generate exception
- 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 *%0" : : "r"(insn_ram), "a"(mem));
- // exit MMX mode
+ asm volatile("fldz; fldz; fdivp"); /* generate exception */
+
+ inregs = (struct regs){ .rsp=(u64)stack+1024 };
+ trap_emulator(mem, alt_insn, 3);
+ /* exit MMX mode */
asm volatile("fnclex; emms");
report("movq mmx generates #MF", exceptions == 1);
handle_exception(MF_VECTOR, 0);
@@ -812,33 +793,12 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
static void test_movabs(uint64_t *mem, uint8_t *insn_page,
uint8_t *alt_insn_page, void *insn_ram)
{
- uint64_t val = 0;
- ulong *cr3 = (ulong *)read_cr3();
-
- // 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;
- // Place the instruction we want the hypervisor to see in the alternate
- // page. A buggy hypervisor will fetch a 32-bit immediate and return
- // 0xffffffffc3c3c3c3.
- alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
- alt_insn_page[1] = 0xb9;
-
- // 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);
- // Load code TLB
- invlpg(insn_ram);
- asm volatile("call *%0" : : "r"(insn_ram + 3));
- // Trap, let hypervisor emulate at alt_insn_page
- install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
- asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
- report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
+ /* mov $0x9090909090909090, %rcx */
+ uint8_t alt_insn[] = {0x48, 0xb9, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90};
+ inregs = (struct regs){ 0 };
+ trap_emulator(mem, alt_insn, 10);
+ report("64-bit mov imm2", outregs.rcx == 0x9090909090909090);
}
static void test_crosspage_mmio(volatile uint8_t *mem)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator
2013-06-20 10:45 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
@ 2013-06-20 12:33 ` Gleb Natapov
0 siblings, 0 replies; 25+ messages in thread
From: Gleb Natapov @ 2013-06-20 12:33 UTC (permalink / raw)
To: Arthur Chunqi Li; +Cc: kvm, pbonzini, jan.kiszka
On Thu, Jun 20, 2013 at 06:45:22PM +0800, Arthur Chunqi Li wrote:
> Change two functions (test_mmx_movq_mf and test_movabs) using
> unified trap_emulator.
>
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
> x86/emulator.c | 70 ++++++++++++--------------------------------------------
> 1 file changed, 15 insertions(+), 55 deletions(-)
>
> diff --git a/x86/emulator.c b/x86/emulator.c
> index b3626fa..16d63e0 100644
> --- a/x86/emulator.c
> +++ b/x86/emulator.c
> @@ -772,38 +772,19 @@ static void advance_rip_by_3_and_note_exception(struct ex_regs *regs)
> static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> - uint16_t fcw = 0; // all exceptions unmasked
> - ulong *cr3 = (ulong *)read_cr3();
> -
> - write_cr0(read_cr0() & ~6); // TS, EM
> - // 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
> - alt_insn_page[0] = 0x0f; // movq %mm0, (%rax)
> - alt_insn_page[1] = 0x7f;
> - alt_insn_page[2] = 0x00;
> - alt_insn_page[3] = 0xc3; // ret
> + uint16_t fcw = 0; /* all exceptions unmasked */
> + u8 alt_insn[] = {0x0f, 0x7f, 0x00}; /* movq %mm0, (%rax) */
Lets introduce something akin to MK_INSN in x86/realmode.c.
> + void *stack = alloc_page();
>
> + write_cr0(read_cr0() & ~6); /* TS, EM */
> exceptions = 0;
> handle_exception(MF_VECTOR, advance_rip_by_3_and_note_exception);
> -
> - // 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);
> asm volatile("fninit; fldcw %0" : : "m"(fcw));
> - asm volatile("fldz; fldz; fdivp"); // generate exception
> - 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 *%0" : : "r"(insn_ram), "a"(mem));
> - // exit MMX mode
> + asm volatile("fldz; fldz; fdivp"); /* generate exception */
> +
> + inregs = (struct regs){ .rsp=(u64)stack+1024 };
> + trap_emulator(mem, alt_insn, 3);
> + /* exit MMX mode */
> asm volatile("fnclex; emms");
> report("movq mmx generates #MF", exceptions == 1);
> handle_exception(MF_VECTOR, 0);
> @@ -812,33 +793,12 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
> static void test_movabs(uint64_t *mem, uint8_t *insn_page,
> uint8_t *alt_insn_page, void *insn_ram)
> {
> - uint64_t val = 0;
> - ulong *cr3 = (ulong *)read_cr3();
> -
> - // 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;
> - // Place the instruction we want the hypervisor to see in the alternate
> - // page. A buggy hypervisor will fetch a 32-bit immediate and return
> - // 0xffffffffc3c3c3c3.
> - alt_insn_page[0] = 0x48; // mov $0xc3c3c3c3c3c3c3c3, %rcx
> - alt_insn_page[1] = 0xb9;
> -
> - // 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);
> - // Load code TLB
> - invlpg(insn_ram);
> - asm volatile("call *%0" : : "r"(insn_ram + 3));
> - // Trap, let hypervisor emulate at alt_insn_page
> - install_page(cr3, virt_to_phys(alt_insn_page), insn_ram);
> - asm volatile("call *%1" : "=c"(val) : "r"(insn_ram), "a"(mem), "c"(0));
> - report("64-bit mov imm", val == 0xc3c3c3c3c3c3c3c3);
> + /* mov $0x9090909090909090, %rcx */
> + uint8_t alt_insn[] = {0x48, 0xb9, 0x90, 0x90, 0x90,
> + 0x90, 0x90, 0x90, 0x90, 0x90};
> + inregs = (struct regs){ 0 };
> + trap_emulator(mem, alt_insn, 10);
> + report("64-bit mov imm2", outregs.rcx == 0x9090909090909090);
> }
>
> static void test_crosspage_mmio(volatile uint8_t *mem)
> --
> 1.7.9.5
--
Gleb.
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2013-06-20 12:33 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-07 2:31 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
2013-06-07 2:31 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-09 11:07 ` [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator 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
-- strict thread matches above, loose matches on Subject: below --
2013-06-20 10:45 Arthur Chunqi Li
2013-06-20 10:45 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-20 12:33 ` Gleb Natapov
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-13 15:16 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
2013-06-13 15:16 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-10 13:45 Arthur Chunqi Li
2013-06-10 13:46 ` 李春奇 <Arthur Chunqi Li>
2013-06-10 13:38 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
2013-06-10 13:38 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-06 15:24 [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Arthur Chunqi Li
2013-06-06 15:24 ` [PATCH 2/2] kvm-unit-tests: Change two cases to use trap_emulator Arthur Chunqi Li
2013-06-12 20:51 ` Paolo Bonzini
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).