From mboxrd@z Thu Jan 1 00:00:00 1970 From: Gleb Natapov Subject: Re: [PATCH 1/2] kvm-unit-tests: Add a func to run instruction in emulator Date: Sun, 9 Jun 2013 20:39:30 +0300 Message-ID: <20130609173930.GF29022@redhat.com> References: <20130609110738.GO4725@redhat.com> <20130609124953.GU4725@redhat.com> <20130609140953.GG15299@redhat.com> <20130609160049.GB29022@redhat.com> <20130609171300.GE29022@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: kvm , Paolo Bonzini To: =?utf-8?B?5p2O5pil5aWHIDxBcnRodXIgQ2h1bnFpIExpPg==?= Return-path: Received: from mx1.redhat.com ([209.132.183.28]:2444 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751493Ab3FIRjh convert rfc822-to-8bit (ORCPT ); Sun, 9 Jun 2013 13:39:37 -0400 Content-Disposition: inline In-Reply-To: Sender: kvm-owner@vger.kernel.org List-ID: On Mon, Jun 10, 2013 at 01:28:48AM +0800, =E6=9D=8E=E6=98=A5=E5=A5=87 <= 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. >=20 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: >=20 >=20 > 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 =3D (ulong *)read_cr3(); > int i; > static struct regs save; >=20 > // Pad with RET instructions > memset(insn_page, 0x90, 4096); > memset(alt_insn_page, 0x90, 4096); >=20 > // Place a trapping instruction in the page to trigger a VMEXIT > insn_page[0] =3D 0x49; //xchg %rsp, %r9 > insn_page[1] =3D 0x87; > insn_page[2] =3D 0xe1; > insn_page[3] =3D 0x49; //xchg %rbp, %r10 > insn_page[4] =3D 0x87; > insn_page[5] =3D 0xea; > insn_page[6] =3D 0x41; // mov %eax, (%r8) > insn_page[7] =3D 0x89; > insn_page[8] =3D 0x00; // ret >=20 > // Place the instruction we want the hypervisor to see in the alt= ernate page > for (i=3D0; i alt_insn_page[i+6] =3D alt_insn[i]; > i+=3D6; > insn_page[i++] =3D 0x49; //xchg %rsp, %r9 > insn_page[i++] =3D 0x87; > insn_page[i++] =3D 0xe1; > insn_page[i++] =3D 0x49; //xchg %rbp, %r10 > insn_page[i++] =3D 0x87; > insn_page[i++] =3D 0xea; > insn_page[i++] =3D 0xc3; // ret > save =3D 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 ass= ist). > // This will make the CPU trap on the insn_page instruction but t= he > // 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 >=20 > "call *%1\n\t" >=20 > "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]"=3Dm"(save) > : "r"(insn_ram), "r"(mem) > : "memory", "cc", "r9", "r10", "r8" > ); > outregs =3D save; > } >=20 >=20 > static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page, > uint8_t *alt_insn_page, void *insn_ram) > { > uint16_t fcw =3D 0; // all exceptions unmasked > uint8_t alt_insn[] =3D {0x0f, 0x7f, 0x00}; // movq %mm0, (%rax) >=20 > write_cr0(read_cr0() & ~6); // TS, EM > exceptions =3D 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 >=20 > inregs =3D (struct regs){ .rsp=3D0, .rbp=3D0 }; > 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 =3D=3D 1); > handle_exception(MF_VECTOR, 0); > } >=20 > On Mon, Jun 10, 2013 at 1:13 AM, Gleb Natapov wrote= : > > On Mon, Jun 10, 2013 at 01:09:15AM +0800, =E6=9D=8E=E6=98=A5=E5=A5=87= wrote: > >> I have finished the infrastructure but after changing test_mmx_mov= q_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 w= rote: > >> > On Sun, Jun 09, 2013 at 11:23:26PM +0800, =E6=9D=8E=E6=98=A5=E5=A5= =87 wrote: > >> >> On Sun, Jun 9, 2013 at 10:09 PM, Gleb Natapov = wrote: > >> >> > On Sun, Jun 09, 2013 at 09:22:27PM +0800, =E6=9D=8E=E6=98=A5=E5= =A5=87 wrote: > >> >> >> On Sun, Jun 9, 2013 at 8:49 PM, Gleb Natapov wrote: > >> >> >> > On Sun, Jun 09, 2013 at 08:44:32PM +0800, =E6=9D=8E=E6=98=A5= =E5=A5=87 wrote: > >> >> >> >> On Sun, Jun 9, 2013 at 7:07 PM, Gleb Natapov 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 speci= al usage and > >> >> >> >> >> cannot set in inregs), put instruction codec in alt_in= sn 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 c= ause error. I > >> >> >> >> use "xchg %%rax, 0+%[save]" before "call *%1" and the %rc= x 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 m= ov > >> >> %eax, (%rax) to trigger vmexit, and %rax is changed before call= ing > >> >> 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)" a= nd 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 tes= t bug, > >> > no need to prevent this from happening. > >> > > >> > -- > >> > Gleb. > >> > >> > >> > >> -- > >> Arthur Chunqi Li > >> Department of Computer Science > >> School of EECS > >> Peking University > >> Beijing, China > > > > -- > > Gleb. >=20 >=20 >=20 > --=20 > Arthur Chunqi Li > Department of Computer Science > School of EECS > Peking University > Beijing, China -- Gleb.