On Mon, Jun 10, 2013 at 09:38:32PM +0800, Arthur Chunqi Li wrote: > Add a function trap_emulator to run an instruction in emulator. > Set inregs first (%rax is invalid because it is used as return > address), put instruction codec in alt_insn and call func with > alt_insn_length. Get results in outregs. > That's far from what I meant :( As I said before inregs/outregs should contain r[0-7] too so you cannot use then as tmp vars to save %rbp/%rsp. My ideas is that the code to save/restore register (all the xchg instructions) should be part of the code in insn_page/alt_insn_page. Instead of call in the middle just put trapping instruction there on insn_page (in (%dx),%al is a good one) padded with nops to the max instruction length. alt_insn_page will have an instruction we want to test at the same offset. This way you can call insn_page freely since stack register during entry and return are unchanged, all the register are saved and restored by the code on insn_page itself.
> Signed-off-by: Arthur Chunqi Li <yzt...@gmail.com> > --- > x86/emulator.c | 106 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 106 insertions(+) > > diff --git a/x86/emulator.c b/x86/emulator.c > index 96576e5..a1bd92e 100644 > --- a/x86/emulator.c > +++ b/x86/emulator.c > @@ -11,6 +11,13 @@ int fails, tests; > > static int exceptions; > > +struct regs { > + u64 rax, rbx, rcx, rdx; > + u64 rsi, rdi, rsp, rbp; > + u64 rip, rflags; > +}; > +static struct regs inregs, outregs; > + > void report(const char *name, int result) > { > ++tests; > @@ -685,6 +692,105 @@ static void test_shld_shrd(u32 *mem) > report("shrd (cl)", *mem == ((0x12345678 >> 3) | (5u << 29))); > } > > +static void trap_emulator(uint64_t *mem, uint8_t *insn_page, > + uint8_t *alt_insn_page, void *insn_ram, > + uint8_t* alt_insn, int alt_insn_length, int > reserve_stack) > +{ > + ulong *cr3 = (ulong *)read_cr3(); > + int i; > + static struct regs save; > + > + // Pad with RET instructions > + memset(insn_page, 0x90, 4096); > + memset(alt_insn_page, 0x90, 4096); > + > + asm volatile( > + "movw $1, %0\n\t" > + : : "m"(mem) > + : "memory" > + ); > + // Place a trapping instruction in the page to trigger a VMEXIT > + insn_page[0] = 0xc3; // ret > + if (!reserve_stack) > + { > + insn_page[1] = 0x49; // xchg %rsp,%r9 > + insn_page[2] = 0x87; > + insn_page[3] = 0xe1; > + insn_page[4] = 0x49; // xchg %rbp,%r10 > + insn_page[5] = 0x87; > + insn_page[6] = 0xea; > + } > + //in (%dx),%al, may change in the future > + insn_page[7] = 0xec; > + > + // Place the instruction we want the hypervisor to see in the alternate > page > + for (i=7; i<alt_insn_length+7; i++) > + alt_insn_page[i] = alt_insn[i-7]; > + > + if (!reserve_stack) > + { > + insn_page[i+0] = 0x49; // xchg %rsp,%r9 > + insn_page[i+1] = 0x87; > + insn_page[i+2] = 0xe1; > + insn_page[i+3] = 0x49; // xchg %rbp,%r10 > + insn_page[i+4] = 0x87; > + insn_page[i+5] = 0xea; > + } > + else > + { > + insn_page[i+0] = 0x49; // mov %rsp,%r9 > + insn_page[i+1] = 0x89; > + insn_page[i+2] = 0xe1; > + insn_page[i+3] = 0x49; // mov %rbp,%r10 > + insn_page[i+4] = 0x89; > + insn_page[i+5] = 0xea; > + } > + insn_page[i+6] = 0xc3; // ret > + > + save = inregs; > + > + // Load the code TLB with insn_page, but point the page tables at > + // alt_insn_page (and keep the data TLB clear, for AMD decode assist). > + // This will make the CPU trap on the insn_page instruction but the > + // hypervisor will see alt_insn_page. > + install_page(cr3, virt_to_phys(insn_page), insn_ram); > + invlpg(insn_ram); > + // Load code TLB > + asm volatile("call *%0" : : "r"(insn_ram)); > + install_page(cr3, virt_to_phys(alt_insn_page), insn_ram); > + // Trap, let hypervisor emulate at alt_insn_page > + asm volatile( > + "push 72+%[save]; popf\n\t" > + "mov %2, %%r8\n\t" > + "xchg %%rax, 0+%[save] \n\t" > + "xchg %%rbx, 8+%[save] \n\t" > + "xchg %%rcx, 16+%[save] \n\t" > + "xchg %%rdx, 24+%[save] \n\t" > + "xchg %%rsi, 32+%[save] \n\t" > + "xchg %%rdi, 40+%[save] \n\t" > + "xchg %%r9, 48+%[save]\n\t" > + "xchg %%r10, 56+%[save]\n\t" > + > + "call *%1\n\t" > + > + "xchg %%rax, 0+%[save] \n\t" > + "xchg %%rbx, 8+%[save] \n\t" > + "xchg %%rcx, 16+%[save] \n\t" > + "xchg %%rdx, 24+%[save] \n\t" > + "xchg %%rsi, 32+%[save] \n\t" > + "xchg %%rdi, 40+%[save] \n\t" > + "xchg %%r9, 48+%[save] \n\t" > + "xchg %%r10, 56+%[save] \n\t" > + /* Save RFLAGS in outregs*/ > + "pushf \n\t" > + "pop 72+%[save] \n\t" > + : [save]"+m"(save) > + : "r"(insn_ram+1), "r"(mem) > + : "memory", "cc", "r8", "r9", "r10" > + ); > + outregs = save; > +} > + > static void advance_rip_by_3_and_note_exception(struct ex_regs *regs) > { > ++exceptions; > -- > 1.7.9.5 -- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html