X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=misc%2Fdecoder_test%2Fvmm_decoder.h;fp=misc%2Fdecoder_test%2Fvmm_decoder.h;h=0c7dcf43617ea31f073e240c3511cd6f54c26794;hp=0000000000000000000000000000000000000000;hb=ddc16b0737cf58f7aa90a69c6652cdf4090aec51;hpb=626595465a2c6987606a6bc697df65130ad8c2d3 diff --git a/misc/decoder_test/vmm_decoder.h b/misc/decoder_test/vmm_decoder.h new file mode 100644 index 0000000..0c7dcf4 --- /dev/null +++ b/misc/decoder_test/vmm_decoder.h @@ -0,0 +1,304 @@ +#ifndef __VMM_EMULATE_H +#define __VMM_EMULATE_H + +#ifdef __V3VEE__ + +#include "test.h" +#include "vm_guest.h" + + +typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} operand_type_t; + +struct x86_operand { + addr_t operand; + uint_t size; + operand_type_t type; +}; + +struct x86_prefixes { + uint_t lock : 1; // 0xF0 + uint_t repne : 1; // 0xF2 + uint_t repnz : 1; // 0xF2 + uint_t rep : 1; // 0xF3 + uint_t repe : 1; // 0xF3 + uint_t repz : 1; // 0xF3 + uint_t cs_override : 1; // 0x2E + uint_t ss_override : 1; // 0x36 + uint_t ds_override : 1; // 0x3E + uint_t es_override : 1; // 0x26 + uint_t fs_override : 1; // 0x64 + uint_t gs_override : 1; // 0x65 + uint_t br_not_taken : 1; // 0x2E + uint_t br_takend : 1; // 0x3E + uint_t op_size : 1; // 0x66 + uint_t addr_size : 1; // 0x67 +}; + + +struct x86_instr { + struct x86_prefixes prefixes; + uint_t instr_length; + addr_t opcode; // a pointer to the V3_OPCODE_[*] arrays defined below + uint_t num_operands; + struct x86_operand src_operand; + struct x86_operand dst_operand; + struct x86_operand third_operand; + void * decoder_data; +}; + + + /************************/ + /* EXTERNAL DECODER API */ +/************************/ +/* + This is an External API definition that must be implemented by a decoder +*/ + + +/* + * Initializes a decoder + */ +int init_decoder(); + +/* + * Decodes an instruction + * All addresses in arguments are in the host address space + * instr_ptr is the host address of the instruction + * IMPORTANT: make sure the instr_ptr is in contiguous host memory + * ie. Copy it to a buffer before the call + */ +int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * instr); + +/* + * Encodes an instruction + * All addresses in arguments are in the host address space + * The instruction is encoded from the struct, and copied into a 15 byte host buffer + * referenced by instr_buf + * any unused bytes at the end of instr_buf will be filled with nops + * IMPORTANT: instr_buf must be allocated and 15 bytes long + */ +int v3_encode(struct guest_info * info, struct x86_instr * instr, char * instr_buf); + + + + + + + + + +/* + * 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 +#define PREFIX_REPNE 0xF2 +#define PREFIX_REPNZ 0xF2 +#define PREFIX_REP 0xF3 +#define PREFIX_REPE 0xF3 +#define PREFIX_REPZ 0xF3 +#define PREFIX_CS_OVERRIDE 0x2E +#define PREFIX_SS_OVERRIDE 0x36 +#define PREFIX_DS_OVERRIDE 0x3E +#define PREFIX_ES_OVERRIDE 0x26 +#define PREFIX_FS_OVERRIDE 0x64 +#define PREFIX_GS_OVERRIDE 0x65 +#define PREFIX_BR_NOT_TAKEN 0x2E +#define PREFIX_BR_TAKEN 0x3E +#define PREFIX_OP_SIZE 0x66 +#define PREFIX_ADDR_SIZE 0x67 + +int opcode_cmp(const uchar_t * op1, const uchar_t * op2); + + +static inline int is_prefix_byte(char byte) { + switch (byte) { + case 0xF0: // lock + case 0xF2: // REPNE/REPNZ + case 0xF3: // REP or REPE/REPZ + case 0x2E: // CS override or Branch hint not taken (with Jcc instrs) + case 0x36: // SS override + case 0x3E: // DS override or Branch hint taken (with Jcc instrs) + case 0x26: // ES override + case 0x64: // FS override + case 0x65: // GS override + //case 0x2E: // branch not taken hint + // case 0x3E: // branch taken hint + case 0x66: // operand size override + case 0x67: // address size override + return 1; + break; + default: + return 0; + break; + } +} + + +static inline v3_reg_t get_gpr_mask(struct guest_info * info) { + switch (info->cpu_mode) { + case REAL: + return 0xffff; + break; + case PROTECTED: + return 0xffffffff; + default: + V3_ASSERT(0); + return 0; + } +} + + +static inline addr_t get_addr_linear(struct guest_info * info, addr_t addr, struct v3_segment * seg) { + switch (info->cpu_mode) { + case REAL: + // It appears that the segment values are computed and cached in the vmcb structure + // We Need to check this for Intel + /* return addr + (seg->selector << 4); + break;*/ + + case PROTECTED: + return addr + seg->base; + break; + default: + V3_ASSERT(0); + return 0; + } +} + + +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; +} + + + + + +#endif // !__V3VEE__ + + +#endif