From: Jack Lange Date: Fri, 4 Mar 2011 22:05:14 +0000 (-0600) Subject: initial checking of internal decoder X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=b3e5aa263c35961c74e0b7ed96b8510e8c6d7d0d;p=palacios.git initial checking of internal decoder --- diff --git a/Kconfig b/Kconfig index 06f962b..6c11bac 100644 --- a/Kconfig +++ b/Kconfig @@ -63,6 +63,22 @@ config DEBUG_INFO help Compiles the Palacios library with debugging symbols +choice + prompt "X86 decoder" + default XED + +config XED + bool "XED decoder library" + help + This uses the XED decoder library from pintools + +config V3_DECODER + bool "Internal Palacios decoder" + help + This selects the internal V3Vee x86 decoder + + +endchoice menu "Supported host OS features" diff --git a/palacios/include/palacios/vmm_decoder.h b/palacios/include/palacios/vmm_decoder.h index 3f71036..81cf0b0 100644 --- a/palacios/include/palacios/vmm_decoder.h +++ b/palacios/include/palacios/vmm_decoder.h @@ -79,15 +79,6 @@ struct x86_instr { }; -struct basic_instr_info { - uint_t instr_length; - uint_t op_size; - uint_t str_op : 1; - uint_t has_rep : 1; -}; - - - /************************/ /* EXTERNAL DECODER API */ /************************/ @@ -122,86 +113,12 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins int v3_encode(struct guest_info * info, struct x86_instr * instr, char * instr_buf); -/* - * Gets the operand size for a memory operation - * - */ -int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic_instr_info * instr_info); - - /* Removes a rep prefix in place */ void v3_strip_rep_prefix(uchar_t * instr, int length); void v3_get_prefixes(uchar_t * instr, struct x86_prefixes * prefixes); -/* - * JRL: Some of this was taken from the Xen sources... - */ - -#define PACKED __attribute__((packed)) - -#define MODRM_MOD(x) ((x >> 6) & 0x3) -#define MODRM_REG(x) ((x >> 3) & 0x7) -#define MODRM_RM(x) (x & 0x7) - -struct modrm_byte { - uint_t rm : 3 PACKED; - uint_t reg : 3 PACKED; - uint_t mod : 2 PACKED; -}; - - -#define SIB_BASE(x) ((x >> 6) & 0x3) -#define SIB_INDEX(x) ((x >> 3) & 0x7) -#define SIB_SCALE(x) (x & 0x7) - -struct sib_byte { - uint_t base : 3 PACKED; - uint_t index : 3 PACKED; - uint_t scale : 2 PACKED; -}; - - - -#define MAKE_INSTR(nm, ...) static const uchar_t V3_OPCODE_##nm[] = { __VA_ARGS__ } - -/* - * Here's how it works: - * First byte: Length. - * Following bytes: Opcode bytes. - * Special case: Last byte, if zero, doesn't need to match. - */ -MAKE_INSTR(INVD, 2, 0x0f, 0x08); -MAKE_INSTR(CPUID, 2, 0x0f, 0xa2); -MAKE_INSTR(RDMSR, 2, 0x0f, 0x32); -MAKE_INSTR(WRMSR, 2, 0x0f, 0x30); -MAKE_INSTR(RDTSC, 2, 0x0f, 0x31); -MAKE_INSTR(RDTSCP, 3, 0x0f, 0x01, 0xf9); -MAKE_INSTR(CLI, 1, 0xfa); -MAKE_INSTR(STI, 1, 0xfb); -MAKE_INSTR(RDPMC, 2, 0x0f, 0x33); -MAKE_INSTR(CLGI, 3, 0x0f, 0x01, 0xdd); -MAKE_INSTR(STGI, 3, 0x0f, 0x01, 0xdc); -MAKE_INSTR(VMRUN, 3, 0x0f, 0x01, 0xd8); -MAKE_INSTR(VMLOAD, 3, 0x0f, 0x01, 0xda); -MAKE_INSTR(VMSAVE, 3, 0x0f, 0x01, 0xdb); -MAKE_INSTR(VMCALL, 3, 0x0f, 0x01, 0xd9); -MAKE_INSTR(PAUSE, 2, 0xf3, 0x90); -MAKE_INSTR(SKINIT, 3, 0x0f, 0x01, 0xde); -MAKE_INSTR(MOV2CR, 3, 0x0f, 0x22, 0x00); -MAKE_INSTR(MOVCR2, 3, 0x0f, 0x20, 0x00); -MAKE_INSTR(MOV2DR, 3, 0x0f, 0x23, 0x00); -MAKE_INSTR(MOVDR2, 3, 0x0f, 0x21, 0x00); -MAKE_INSTR(PUSHF, 1, 0x9c); -MAKE_INSTR(POPF, 1, 0x9d); -MAKE_INSTR(RSM, 2, 0x0f, 0xaa); -MAKE_INSTR(INVLPG, 3, 0x0f, 0x01, 0x00); -MAKE_INSTR(INVLPGA,3, 0x0f, 0x01, 0xdf); -MAKE_INSTR(HLT, 1, 0xf4); -MAKE_INSTR(CLTS, 2, 0x0f, 0x06); -MAKE_INSTR(LMSW, 3, 0x0f, 0x01, 0x00); -MAKE_INSTR(SMSW, 3, 0x0f, 0x01, 0x00); #define PREFIX_LOCK 0xF0 @@ -221,7 +138,7 @@ MAKE_INSTR(SMSW, 3, 0x0f, 0x01, 0x00); #define PREFIX_OP_SIZE 0x66 #define PREFIX_ADDR_SIZE 0x67 -int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2); + static inline int is_prefix_byte(uchar_t byte) { @@ -267,6 +184,7 @@ static inline v3_reg_t get_gpr_mask(struct guest_info * info) { } + static inline addr_t get_addr_linear(struct guest_info * info, addr_t addr, struct v3_segment * seg) { switch (info->cpu_mode) { case REAL: @@ -294,328 +212,6 @@ static inline addr_t get_addr_linear(struct guest_info * info, addr_t addr, stru } -typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t; -typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t; - - - - - - -struct v3_gprs; - -static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_size_t reg_size) { - addr_t reg_addr; - - switch (reg_code) { - case 0: - reg_addr = (addr_t)&(gprs->rax); - break; - case 1: - reg_addr = (addr_t)&(gprs->rcx); - break; - case 2: - reg_addr = (addr_t)&(gprs->rdx); - break; - case 3: - reg_addr = (addr_t)&(gprs->rbx); - break; - case 4: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rax) + 1; - } else { - reg_addr = (addr_t)&(gprs->rsp); - } - break; - case 5: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rcx) + 1; - } else { - reg_addr = (addr_t)&(gprs->rbp); - } - break; - case 6: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rdx) + 1; - } else { - reg_addr = (addr_t)&(gprs->rsi); - } - break; - case 7: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rbx) + 1; - } else { - reg_addr = (addr_t)&(gprs->rdi); - } - break; - default: - reg_addr = 0; - break; - } - - return reg_addr; -} - - - -static inline v3_operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output - char * modrm_instr, // input - int * offset, // output - addr_t * first_operand, // output - addr_t * second_operand, // output - reg_size_t reg_size) { // input - - struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; - addr_t base_addr = 0; - modrm_mode_t mod_mode = 0; - v3_operand_type_t addr_type = INVALID_OPERAND; - char * instr_cursor = modrm_instr; - - // PrintDebug("ModRM mod=%d\n", modrm->mod); - - instr_cursor += 1; - - if (modrm->mod == 3) { - mod_mode = REG; - addr_type = REG_OPERAND; - //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); - - *first_operand = decode_register(gprs, modrm->rm, reg_size); - - } else { - - addr_type = MEM_OPERAND; - - if (modrm->mod == 0) { - mod_mode = DISP0; - } else if (modrm->mod == 1) { - mod_mode = DISP8; - } else if (modrm->mod == 2) { - mod_mode = DISP16; - } - - switch (modrm->rm) { - case 0: - base_addr = gprs->rbx + gprs->rsi; - break; - case 1: - base_addr = gprs->rbx + gprs->rdi; - break; - case 2: - base_addr = gprs->rbp + gprs->rsi; - break; - case 3: - base_addr = gprs->rbp + gprs->rdi; - break; - case 4: - base_addr = gprs->rsi; - break; - case 5: - base_addr = gprs->rdi; - break; - case 6: - if (modrm->mod == 0) { - base_addr = 0; - mod_mode = DISP16; - } else { - base_addr = gprs->rbp; - } - break; - case 7: - base_addr = gprs->rbx; - break; - } - - - - if (mod_mode == DISP8) { - base_addr += (uchar_t)*(instr_cursor); - instr_cursor += 1; - } else if (mod_mode == DISP16) { - base_addr += (ushort_t)*(instr_cursor); - instr_cursor += 2; - } - - *first_operand = base_addr; - } - - *offset += (instr_cursor - modrm_instr); - *second_operand = decode_register(gprs, modrm->reg, reg_size); - - return addr_type; -} - - - -static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output - uchar_t * modrm_instr, // input - int * offset, // output - addr_t * first_operand, // output - addr_t * second_operand, // output - reg_size_t reg_size) { // input - - uchar_t * instr_cursor = modrm_instr; - struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; - addr_t base_addr = 0; - modrm_mode_t mod_mode = 0; - uint_t has_sib_byte = 0; - v3_operand_type_t addr_type = INVALID_OPERAND; - - - - instr_cursor += 1; - - if (modrm->mod == 3) { - mod_mode = REG; - addr_type = REG_OPERAND; - - // PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); - - *first_operand = decode_register(gprs, modrm->rm, reg_size); - - } else { - - addr_type = MEM_OPERAND; - - if (modrm->mod == 0) { - mod_mode = DISP0; - } else if (modrm->mod == 1) { - mod_mode = DISP8; - } else if (modrm->mod == 2) { - mod_mode = DISP32; - } - - switch (modrm->rm) { - case 0: - base_addr = gprs->rax; - break; - case 1: - base_addr = gprs->rcx; - break; - case 2: - base_addr = gprs->rdx; - break; - case 3: - base_addr = gprs->rbx; - break; - case 4: - has_sib_byte = 1; - break; - case 5: - if (modrm->mod == 0) { - base_addr = 0; - mod_mode = DISP32; - } else { - base_addr = gprs->rbp; - } - break; - case 6: - base_addr = gprs->rsi; - break; - case 7: - base_addr = gprs->rdi; - break; - } - - if (has_sib_byte) { - instr_cursor += 1; - struct sib_byte * sib = (struct sib_byte *)(instr_cursor); - int scale = 1; - - instr_cursor += 1; - - - if (sib->scale == 1) { - scale = 2; - } else if (sib->scale == 2) { - scale = 4; - } else if (sib->scale == 3) { - scale = 8; - } - - - switch (sib->index) { - case 0: - base_addr = gprs->rax; - break; - case 1: - base_addr = gprs->rcx; - break; - case 2: - base_addr = gprs->rdx; - break; - case 3: - base_addr = gprs->rbx; - break; - case 4: - base_addr = 0; - break; - case 5: - base_addr = gprs->rbp; - break; - case 6: - base_addr = gprs->rsi; - break; - case 7: - base_addr = gprs->rdi; - break; - } - - base_addr *= scale; - - - switch (sib->base) { - case 0: - base_addr += gprs->rax; - break; - case 1: - base_addr += gprs->rcx; - break; - case 2: - base_addr += gprs->rdx; - break; - case 3: - base_addr += gprs->rbx; - break; - case 4: - base_addr += gprs->rsp; - break; - case 5: - if (modrm->mod != 0) { - base_addr += gprs->rbp; - } - break; - case 6: - base_addr += gprs->rsi; - break; - case 7: - base_addr += gprs->rdi; - break; - } - - } - - - if (mod_mode == DISP8) { - base_addr += (uchar_t)*(instr_cursor); - instr_cursor += 1; - } else if (mod_mode == DISP32) { - base_addr += (uint_t)*(instr_cursor); - instr_cursor += 4; - } - - - *first_operand = base_addr; - } - - *offset += (instr_cursor - modrm_instr); - - *second_operand = decode_register(gprs, modrm->reg, reg_size); - - return addr_type; -} - - #endif // !__V3VEE__ diff --git a/palacios/include/palacios/vmm_ss_emulator.h b/palacios/include/palacios/vmm_ss_emulator.h deleted file mode 100644 index 173cddd..0000000 --- a/palacios/include/palacios/vmm_ss_emulator.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the Palacios Virtual Machine Monitor developed - * by the V3VEE Project with funding from the United States National - * Science Foundation and the Department of Energy. - * - * The V3VEE Project is a joint project between Northwestern University - * and the University of New Mexico. You can find out more at - * http://www.v3vee.org - * - * Copyright (c) 2008, Jack Lange - * Copyright (c) 2008, The V3VEE Project - * All rights reserved. - * - * Author: Jack Lange - * - * This is free software. You are permitted to use, - * redistribute, and modify it as specified in the file "V3VEE_LICENSE". - */ - -#ifndef __VMM_EMULATOR_H__ -#define __VMM_EMULATOR_H__ - -#ifdef __V3VEE__ - -#include -#include -#include - - - - - - - - -struct emulation_state { - - uint_t running : 1; - uint_t instr_length; - - uint_t tf_enabled : 1; -}; - - -int v3_init_emulator(struct guest_info * info); - - -int v3_emulation_exit_handler(struct guest_info * info); - -int v3_emulate_memory_write(struct guest_info * info, addr_t fault_gva, - int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), - addr_t write_addr, void * private_data); -int v3_emulate_memory_read(struct guest_info * info, addr_t fault_gva, - int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), - addr_t read_addr, void * private_data); - - -#endif // !__V3VEE__ - -#endif diff --git a/palacios/lib/i386/Makefile b/palacios/lib/i386/Makefile index 788a68c..439cd66 100644 --- a/palacios/lib/i386/Makefile +++ b/palacios/lib/i386/Makefile @@ -1,2 +1,2 @@ -obj-y := libxed.a \ - v3-xed-compat.o +obj-$(CONFIG_XED) := libxed.a \ + v3-xed-compat.o diff --git a/palacios/lib/x86_64/Makefile b/palacios/lib/x86_64/Makefile index 1ece18e..c77a270 100644 --- a/palacios/lib/x86_64/Makefile +++ b/palacios/lib/x86_64/Makefile @@ -1,2 +1,2 @@ -obj-y := libxed32e.a \ - v3-xed-compat.o +obj-$(CONFIG_XED) := libxed32e.a \ + v3-xed-compat.o diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index 8e44ae5..756b020 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -28,7 +28,6 @@ obj-y := \ vmm_string.o \ vmm_time.o \ vmm_util.o \ - vmm_xed.o \ vmm_binaries.o \ vmm_cpuid.o \ vmm_xml.o \ @@ -39,6 +38,10 @@ obj-y := \ vmm_mtrr.o \ + +obj-$(CONFIG_XED) += vmm_xed.o +obj-$(CONFIG_V3_DECODER) += vmm_v3dec.o + obj-$(CONFIG_SVM) += svm.o \ svm_io.o \ svm_lowlevel.o \ diff --git a/palacios/src/palacios/vmm.c b/palacios/src/palacios/vmm.c index c890fda..7b38e2d 100644 --- a/palacios/src/palacios/vmm.c +++ b/palacios/src/palacios/vmm.c @@ -266,7 +266,8 @@ int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) { if (vm->num_cores > avail_cores) { - PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", vm->num_cores, avail_cores, MAX_CORES); + PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n", + vm->num_cores, avail_cores, MAX_CORES); return -1; } diff --git a/palacios/src/palacios/vmm_decoder.c b/palacios/src/palacios/vmm_decoder.c index 4b88e67..1d9e178 100644 --- a/palacios/src/palacios/vmm_decoder.c +++ b/palacios/src/palacios/vmm_decoder.c @@ -21,13 +21,7 @@ #include -int v3_opcode_cmp(const uchar_t * op1, const uchar_t * op2) { - if (op1[0] != op2[0]) { - return op1[0] - op2[0];; - } else { - return memcmp(op1 + 1, op2 + 1, op1[0]); - } -} + void v3_get_prefixes(uchar_t * instr, struct x86_prefixes * prefixes) { diff --git a/palacios/src/palacios/vmm_ss_emulator.c b/palacios/src/palacios/vmm_ss_emulator.c deleted file mode 100644 index de50876..0000000 --- a/palacios/src/palacios/vmm_ss_emulator.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * This file is part of the Palacios Virtual Machine Monitor developed - * by the V3VEE Project with funding from the United States National - * Science Foundation and the Department of Energy. - * - * The V3VEE Project is a joint project between Northwestern University - * and the University of New Mexico. You can find out more at - * http://www.v3vee.org - * - * Copyright (c) 2008, Jack Lange - * Copyright (c) 2008, The V3VEE Project - * All rights reserved. - * - * Author: Jack Lange - * - * This is free software. You are permitted to use, - * redistribute, and modify it as specified in the file "V3VEE_LICENSE". - */ - -#include -#include -#include -#include -#include -#include -#include - - -#ifndef CONFIG_DEBUG_EMULATOR -#undef PrintDebug -#define PrintDebug(fmt, args...) -#endif - - -int v3_init_emulator(struct guest_info * info) { - - - emulator->tf_enabled = 0; - - return 0; -} - - - - - - - - - - -static int set_stepping(struct guest_info * info) { - vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); - ctrl_area->exceptions.db = 1; - - info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf; - - ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1; - - return 0; -} - - -static int unset_stepping(struct guest_info * info) { - vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); - ctrl_area->exceptions.db = 0; - - ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled; - - if (info->emulator.tf_enabled) { - // Inject breakpoint exception into guest - } - - return 0; - -} - - -int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva, - int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), - addr_t read_gpa, void * private_data) { - struct basic_instr_info instr_info; - uchar_t instr[15]; - int ret; - addr_t data_addr_offset = PAGE_OFFSET(read_gva); - - PrintDebug("Emulating Read\n"); - - if (info->mem_mode == PHYSICAL_MEM) { - ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); - } else { - ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); - } - - if (ret == -1) { - PrintError("Could not read guest memory\n"); - return -1; - } - -#ifdef CONFIG_DEBUG_EMULATOR - PrintDebug("Instr (15 bytes) at %p:\n", (void *)(addr_t)instr); - PrintTraceMemDump(instr, 15); -#endif - - - if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) { - PrintError("Could not do a basic memory instruction decode\n"); - V3_Free(data_page); - return -1; - } - - // Read the data directly onto the emulated page - ret = read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data); - if ((ret == -1) || ((uint_t)ret != instr_info.op_size)) { - PrintError("Read error in emulator\n"); - return -1; - } - - - - // setup_code_page(info, instr, &instr_info); - set_stepping(info); - - info->emulator.running = 1; - info->run_state = VM_EMULATING; - info->emulator.instr_length = instr_info.instr_length; - - return 0; -} - - - -int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva, - int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), - addr_t write_gpa, void * private_data) { - - struct basic_instr_info instr_info; - uchar_t instr[15]; - int ret; - addr_t data_addr_offset = PAGE_OFFSET(write_gva); - int i; - - PrintDebug("Emulating Write for instruction at 0x%p\n", (void *)(addr_t)(info->rip)); - - if (info->mem_mode == PHYSICAL_MEM) { - ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); - } else { - ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); - } - - - - if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) { - PrintError("Could not do a basic memory instruction decode\n"); - V3_Free(write_op); - V3_Free(data_page); - return -1; - } - - if (instr_info.has_rep==1) { - PrintDebug("Emulated instruction has rep\n"); - } - - - if (info->emulator.running == 0) { - // setup_code_page(info, instr, &instr_info); - set_stepping(info); - info->emulator.running = 1; - info->run_state = VM_EMULATING; - info->emulator.instr_length = instr_info.instr_length; - } - - return 0; -} - - -// end emulation -int v3_emulation_exit_handler(struct guest_info * info) { - - unset_stepping(info); - - - PrintDebug("returning from emulation\n"); - - return 0; -} diff --git a/palacios/src/palacios/vmm_v3dec.c b/palacios/src/palacios/vmm_v3dec.c new file mode 100644 index 0000000..78cb8b6 --- /dev/null +++ b/palacios/src/palacios/vmm_v3dec.c @@ -0,0 +1,819 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#include + + +/* .... Giant fucking switch tables */ + + + +#define MODRM_MOD(x) (((x) >> 6) & 0x3) +#define MODRM_REG(x) (((x) >> 3) & 0x7) +#define MODRM_RM(x) ((x) & 0x7) + +struct modrm_byte { + uint_t rm : 3; + uint_t reg : 3; + uint_t mod : 2; +} __attribute__((packed)); + + +#define SIB_BASE(x) (((x) >> 6) & 0x3) +#define SIB_INDEX(x) (((x) >> 3) & 0x7) +#define SIB_SCALE(x) ((x) & 0x7) + +struct sib_byte { + uint_t base : 3; + uint_t index : 3; + uint_t scale : 2; +} __attribute__((packed)); + + + + +typedef enum { + INVALID_INSTR, + LMSW, + SMSW, + CLTS, + INVLPG, + + MOV_CR2, + MOV_2CR, + MOV_DR2, + MOV_2DR, + MOV_SR2, + MOV_2SR, + + MOV_2GPR_8, + MOV_2GPR, + MOV_GPR2_8, + MOV_GPR2, + MOV_MEM2AL_8, + MOV_MEM2AX, + MOV_AL2MEM_8, + MOV_AX2MEM, + MOV_IMM2_8, + MOV_IMM2, + + MOVS_8, + MOVS, + MOVSX_8, + MOVSX, + MOVZX_8, + MOVZX, + + HLT, + PUSHF, + POPF, + + ADC_2MEM_8, + ADC_2MEM, + ADC_MEM2_8, + ADC_MEM2, + ADC_IMM2_8, + ADC_IMM2, + ADC_IMM2SX_8, + ADD_IMM2_8, + ADD_IMM2, + ADD_IMM2SX_8, + ADD_2MEM_8, + ADD_2MEM, + ADD_MEM2_8, + ADD_MEM2, + AND_MEM2_8, + AND_MEM2, + AND_2MEM_8, + AND_2MEM, + AND_IMM2_8, + AND_IMM2, + AND_IMM2SX_8, + OR_2MEM_8, + OR_2MEM, + OR_MEM2_8, + OR_MEM2, + OR_IMM2_8, + OR_IMM2, + OR_IMM2SX_8, + SUB_2MEM_8, + SUB_2MEM, + SUB_MEM2_8, + SUB_MEM2, + SUB_IMM2_8, + SUB_IMM2, + SUB_IMM2SX_8, + XOR_2MEM_8, + XOR_2MEM, + XOR_MEM2_8, + XOR_MEM2, + XOR_IMM2_8, + XOR_IMM2, + XOR_IMM2SX_8, + + INC_8, + INC, + DEC_8, + DEC, + NEG_8, + NEG, + NOT_8, + NOT, + XCHG_8, + XCHG, + + SETB, + SETBE, + SETL, + SETLE, + SETNB, + SETNBE, + SETNL, + SETNLE, + SETNO, + SETNP, + SETNS, + SETNZ, + SETP, + SETS, + SETZ, + SETO, + + STOS_8, + STOS +} op_form_t; + +static op_form_t op_code_to_form(uint8_t * instr); + + + +typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t; +typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t; + + +struct v3_gprs; + +static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_size_t reg_size) { + addr_t reg_addr; + + switch (reg_code) { + case 0: + reg_addr = (addr_t)&(gprs->rax); + break; + case 1: + reg_addr = (addr_t)&(gprs->rcx); + break; + case 2: + reg_addr = (addr_t)&(gprs->rdx); + break; + case 3: + reg_addr = (addr_t)&(gprs->rbx); + break; + case 4: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rax) + 1; + } else { + reg_addr = (addr_t)&(gprs->rsp); + } + break; + case 5: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rcx) + 1; + } else { + reg_addr = (addr_t)&(gprs->rbp); + } + break; + case 6: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rdx) + 1; + } else { + reg_addr = (addr_t)&(gprs->rsi); + } + break; + case 7: + if (reg_size == REG8) { + reg_addr = (addr_t)&(gprs->rbx) + 1; + } else { + reg_addr = (addr_t)&(gprs->rdi); + } + break; + default: + reg_addr = 0; + break; + } + + return reg_addr; +} + + + +static inline v3_operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output + char * modrm_instr, // input + int * offset, // output + addr_t * first_operand, // output + addr_t * second_operand, // output + reg_size_t reg_size) { // input + + struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; + addr_t base_addr = 0; + modrm_mode_t mod_mode = 0; + v3_operand_type_t addr_type = INVALID_OPERAND; + char * instr_cursor = modrm_instr; + + // PrintDebug("ModRM mod=%d\n", modrm->mod); + + instr_cursor += 1; + + if (modrm->mod == 3) { + mod_mode = REG; + addr_type = REG_OPERAND; + //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); + + *first_operand = decode_register(gprs, modrm->rm, reg_size); + + } else { + + addr_type = MEM_OPERAND; + + if (modrm->mod == 0) { + mod_mode = DISP0; + } else if (modrm->mod == 1) { + mod_mode = DISP8; + } else if (modrm->mod == 2) { + mod_mode = DISP16; + } + + switch (modrm->rm) { + case 0: + base_addr = gprs->rbx + gprs->rsi; + break; + case 1: + base_addr = gprs->rbx + gprs->rdi; + break; + case 2: + base_addr = gprs->rbp + gprs->rsi; + break; + case 3: + base_addr = gprs->rbp + gprs->rdi; + break; + case 4: + base_addr = gprs->rsi; + break; + case 5: + base_addr = gprs->rdi; + break; + case 6: + if (modrm->mod == 0) { + base_addr = 0; + mod_mode = DISP16; + } else { + base_addr = gprs->rbp; + } + break; + case 7: + base_addr = gprs->rbx; + break; + } + + + + if (mod_mode == DISP8) { + base_addr += (uchar_t)*(instr_cursor); + instr_cursor += 1; + } else if (mod_mode == DISP16) { + base_addr += (ushort_t)*(instr_cursor); + instr_cursor += 2; + } + + *first_operand = base_addr; + } + + *offset += (instr_cursor - modrm_instr); + *second_operand = decode_register(gprs, modrm->reg, reg_size); + + return addr_type; +} + + + +static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output + uchar_t * modrm_instr, // input + int * offset, // output + addr_t * first_operand, // output + addr_t * second_operand, // output + reg_size_t reg_size) { // input + + uchar_t * instr_cursor = modrm_instr; + struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; + addr_t base_addr = 0; + modrm_mode_t mod_mode = 0; + uint_t has_sib_byte = 0; + v3_operand_type_t addr_type = INVALID_OPERAND; + + + + instr_cursor += 1; + + if (modrm->mod == 3) { + mod_mode = REG; + addr_type = REG_OPERAND; + + // PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); + + *first_operand = decode_register(gprs, modrm->rm, reg_size); + + } else { + + addr_type = MEM_OPERAND; + + if (modrm->mod == 0) { + mod_mode = DISP0; + } else if (modrm->mod == 1) { + mod_mode = DISP8; + } else if (modrm->mod == 2) { + mod_mode = DISP32; + } + + switch (modrm->rm) { + case 0: + base_addr = gprs->rax; + break; + case 1: + base_addr = gprs->rcx; + break; + case 2: + base_addr = gprs->rdx; + break; + case 3: + base_addr = gprs->rbx; + break; + case 4: + has_sib_byte = 1; + break; + case 5: + if (modrm->mod == 0) { + base_addr = 0; + mod_mode = DISP32; + } else { + base_addr = gprs->rbp; + } + break; + case 6: + base_addr = gprs->rsi; + break; + case 7: + base_addr = gprs->rdi; + break; + } + + if (has_sib_byte) { + instr_cursor += 1; + struct sib_byte * sib = (struct sib_byte *)(instr_cursor); + int scale = 1; + + instr_cursor += 1; + + + if (sib->scale == 1) { + scale = 2; + } else if (sib->scale == 2) { + scale = 4; + } else if (sib->scale == 3) { + scale = 8; + } + + + switch (sib->index) { + case 0: + base_addr = gprs->rax; + break; + case 1: + base_addr = gprs->rcx; + break; + case 2: + base_addr = gprs->rdx; + break; + case 3: + base_addr = gprs->rbx; + break; + case 4: + base_addr = 0; + break; + case 5: + base_addr = gprs->rbp; + break; + case 6: + base_addr = gprs->rsi; + break; + case 7: + base_addr = gprs->rdi; + break; + } + + base_addr *= scale; + + + switch (sib->base) { + case 0: + base_addr += gprs->rax; + break; + case 1: + base_addr += gprs->rcx; + break; + case 2: + base_addr += gprs->rdx; + break; + case 3: + base_addr += gprs->rbx; + break; + case 4: + base_addr += gprs->rsp; + break; + case 5: + if (modrm->mod != 0) { + base_addr += gprs->rbp; + } + break; + case 6: + base_addr += gprs->rsi; + break; + case 7: + base_addr += gprs->rdi; + break; + } + + } + + + if (mod_mode == DISP8) { + base_addr += (uchar_t)*(instr_cursor); + instr_cursor += 1; + } else if (mod_mode == DISP32) { + base_addr += (uint_t)*(instr_cursor); + instr_cursor += 4; + } + + + *first_operand = base_addr; + } + + *offset += (instr_cursor - modrm_instr); + + *second_operand = decode_register(gprs, modrm->reg, reg_size); + + return addr_type; +} + + + +static inline op_form_t op_code_to_form_0f(uint8_t * instr) { + switch (instr[1]) { + case 0x01: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[2]); + + switch (modrm->reg) { + case 4: + return SMSW; + case 6: + return LMSW; + case 7: + return INVLPG; + default: + return INVALID_INSTR; + } + } + + case 0x06: + return CLTS; + case 0x20: + return MOV_CR2; + case 0x21: + return MOV_DR2; + + case 0x22: + return MOV_2CR; + case 0x23: + return MOV_2DR; + + case 0x90: + return SETO; + case 0x91: + return SETNO; + case 0x92: + return SETB; + case 0x93: + return SETNB; + case 0x94: + return SETZ; + case 0x95: + return SETNZ; + case 0x96: + return SETBE; + case 0x97: + return SETNBE; + case 0x98: + return SETS; + case 0x99: + return SETNS; + case 0x9a: + return SETP; + case 0x9b: + return SETNP; + case 0x9c: + return SETL; + case 0x9d: + return SETNL; + case 0x9e: + return SETLE; + case 0x9f: + return SETNLE; + + case 0xb6: + return MOVZX_8; + case 0xb7: + return MOVZX; + + case 0xbe: + return MOVSX_8; + case 0xbf: + return MOVSX; + + + default: + return INVALID_INSTR; + } +} + + +static op_form_t op_code_to_form(uint8_t * instr) { + switch (instr[0]) { + case 0x00: + return ADD_2MEM_8; + case 0x01: + return ADD_2MEM; + case 0x02: + return ADD_MEM2_8; + case 0x03: + return ADD_MEM2; + + case 0x08: + return OR_2MEM_8; + case 0x09: + return OR_2MEM; + case 0x0a: + return OR_MEM2_8; + case 0x0b: + return OR_MEM2; + + + case 0x0f: + return op_code_to_form_0f(instr); + + case 0x10: + return ADC_2MEM_8; + case 0x11: + return ADC_2MEM; + case 0x12: + return ADC_MEM2_8; + case 0x13: + return ADC_MEM2; + + case 0x20: + return AND_2MEM_8; + case 0x21: + return AND_2MEM; + case 0x22: + return AND_MEM2_8; + case 0x23: + return AND_MEM2; + + case 0x28: + return SUB_2MEM_8; + case 0x29: + return SUB_2MEM; + case 0x2a: + return SUB_MEM2_8; + case 0x2b: + return SUB_MEM2; + + + case 0x30: + return XOR_2MEM_8; + case 0x31: + return XOR_2MEM; + case 0x32: + return XOR_MEM2_8; + case 0x33: + return XOR_MEM2; + + case 0x80:{ + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 0: + return ADD_IMM2_8; + case 1: + return OR_IMM2_8; + case 2: + return ADC_IMM2_8; + case 4: + return AND_IMM2_8; + case 5: + return SUB_IMM2_8; + case 6: + return XOR_IMM2_8; + default: + return INVALID_INSTR; + } + } + case 0x81: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 0: + return ADD_IMM2; + case 1: + return OR_IMM2; + case 2: + return ADC_IMM2; + case 4: + return AND_IMM2; + case 5: + return SUB_IMM2; + case 6: + return XOR_IMM2; + default: + return INVALID_INSTR; + } + } + case 0x83: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 0: + return ADD_IMM2SX_8; + case 1: + return OR_IMM2SX_8; + case 2: + return ADC_IMM2SX_8; + case 4: + return AND_IMM2SX_8; + case 5: + return SUB_IMM2SX_8; + case 6: + return XOR_IMM2SX_8; + default: + return INVALID_INSTR; + } + } + + case 0x86: + return XCHG_8; + case 0x87: + return XCHG; + case 0x88: + return MOV_2GPR_8; + case 0x89: + return MOV_2GPR; + case 0x8a: + return MOV_GPR2_8; + case 0x8b: + return MOV_GPR2; + + case 0x8c: + return MOV_SR2; + case 0x8e: + return MOV_2SR; + + + case 0x9c: + return PUSHF; + case 0x9d: + return POPF; + + case 0xa0: + return MOV_MEM2AL_8; + case 0xa1: + return MOV_MEM2AX; + case 0xa2: + return MOV_AL2MEM_8; + case 0xa3: + return MOV_AX2MEM; + + case 0xa4: + return MOVS_8; + case 0xa5: + return MOVS; + + case 0xaa: + return STOS_8; + case 0xab: + return STOS; + + case 0xc6: + return MOV_IMM2_8; + case 0xc7: + return MOV_IMM2; + + case 0xf4: + return HLT; + + + case 0xf6: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 2: + return NOT_8; + case 3: + return NEG_8; + default: + return INVALID_INSTR; + } + } + case 0xf7: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 2: + return NOT; + case 3: + return NEG; + default: + return INVALID_INSTR; + } + } + + + case 0xfe: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 0: + return INC_8; + case 1: + return DEC_8; + default: + return INVALID_INSTR; + } + } + + case 0xff: { + struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + + switch (modrm->reg) { + case 0: + return INC; + case 1: + return DEC; + default: + return INVALID_INSTR; + } + } + + default: + return INVALID_INSTR; + } +} + +int v3_disasm(struct guest_info * info, void *instr_ptr, addr_t * rip, int mark) { + return 0; +} + + + +int v3_init_decoder(struct guest_info * core) { + return 0; +} + + +int v3_deinit_decoder(struct guest_info * core) { + return 0; +} + + +int v3_encode(struct guest_info * info, struct x86_instr * instr, char * instr_buf) { + return 0; +} + +int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * instr) { + op_code_to_form((void *)instr_ptr); + + return 0; +} diff --git a/palacios/src/palacios/vmm_xed.c b/palacios/src/palacios/vmm_xed.c index f140d1a..e23ace0 100644 --- a/palacios/src/palacios/vmm_xed.c +++ b/palacios/src/palacios/vmm_xed.c @@ -187,55 +187,6 @@ int v3_deinit_decoder(struct guest_info * core) { } -int v3_basic_mem_decode(struct guest_info * info, addr_t instr_ptr, struct basic_instr_info * instr_info) { - xed_decoded_inst_t xed_instr; - xed_error_enum_t xed_error; - - - if (set_decoder_mode(info, info->decoder_state) == -1) { - PrintError("Could not set decoder mode\n"); - return -1; - } - - - xed_decoded_inst_zero_set_mode(&xed_instr, info->decoder_state); - - xed_error = xed_decode(&xed_instr, - REINTERPRET_CAST(const xed_uint8_t *, instr_ptr), - XED_MAX_INSTRUCTION_BYTES); - - if (xed_error != XED_ERROR_NONE) { - PrintError("Xed error: %s\n", xed_error_enum_t2str(xed_error)); - return -1; - } - - instr_info->instr_length = xed_decoded_inst_get_length(&xed_instr); - - - if (xed_decoded_inst_number_of_memory_operands(&xed_instr) == 0) { - PrintError("Tried to decode memory operation with no memory operands\n"); - return -1; - } - - instr_info->op_size = xed_decoded_inst_get_memory_operand_length(&xed_instr, 0); - - - xed_category_enum_t cat = xed_decoded_inst_get_category(&xed_instr); - if (cat == XED_CATEGORY_STRINGOP) { - instr_info->str_op = 1; - } else { - instr_info->str_op = 0; - } - - xed_operand_values_t * operands = xed_decoded_inst_operands(&xed_instr); - if (xed_operand_values_has_real_rep(operands)) { - instr_info->has_rep = 1; - } else { - instr_info->has_rep = 0; - } - - return 0; -} static int decode_string_op(struct guest_info * info,