+/* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
+/* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
+
#ifndef __VMM_EMULATE_H
#define __VMM_EMULATE_H
-#include <palacios/vm_guest.h>
-
-
-/*
- * This is where we do the hideous X86 instruction parsing among other things
- * We can parse out the instruction prefixes, as well as decode the operands
- */
-typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND} operand_type_t;
+#ifdef __V3VEE__
+#include <palacios/vm_guest.h>
+#include <palacios/vmm.h>
+typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} operand_type_t;
struct x86_operand {
addr_t operand;
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 dst_operand;
+ struct x86_operand src_operand;
+ struct x86_operand third_operand;
+ void * decoder_data;
+};
+
+
+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 */
+/************************/
+/*
+ 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);
-/* This parses an instruction
+/*
+ * 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);
+
+
+/*
+ * Gets the operand size for a memory operation
+ *
*/
-int v3_parse_instr(struct guest_info * info, // input
- char * instr_ptr, // input
- uint_t * instr_length, // output
- struct x86_operand * src_operand, // output
- struct x86_operand * dst_operand, // output
- struct x86_operand * extra_operand); // output
-
+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 strip_rep_prefix(uchar_t * instr, int length);
+
/*
-#define MAKE_INSTR(nm, ...) static const uchar_t OPCODE_##nm[] = { __VA_ARGS__ }
+#define MAKE_INSTR(nm, ...) static const uchar_t V3_OPCODE_##nm[] = { __VA_ARGS__ }
/*
* Here's how it works:
MAKE_INSTR(SMSW, 3, 0x0f, 0x01, 0x00);
-static const uchar_t PREFIX_LOCK = 0xF0;
-static const uchar_t PREFIX_REPNE = 0xF2;
-static const uchar_t PREFIX_REPNZ = 0xF2;
-static const uchar_t PREFIX_REP = 0xF3;
-static const uchar_t PREFIX_REPE = 0xF3;
-static const uchar_t PREFIX_REPZ = 0xF3;
-static const uchar_t PREFIX_CS_OVERRIDE = 0x2E;
-static const uchar_t PREFIX_SS_OVERRIDE = 0x36;
-static const uchar_t PREFIX_DS_OVERRIDE = 0x3E;
-static const uchar_t PREFIX_ES_OVERRIDE = 0x26;
-static const uchar_t PREFIX_FS_OVERRIDE = 0x64;
-static const uchar_t PREFIX_GS_OVERRIDE = 0x65;
-static const uchar_t PREFIX_BR_NOT_TAKEN = 0x2E;
-static const uchar_t PREFIX_BR_TAKEN = 0x3E;
-static const uchar_t PREFIX_OP_SIZE = 0x66;
-static const uchar_t PREFIX_ADDR_SIZE = 0x67;
+#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) {
return 0xffff;
break;
case PROTECTED:
- case PROTECTED_PG:
return 0xffffffff;
default:
V3_ASSERT(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:
- return addr + (seg->selector << 4);
- break;
+ // 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:
- case PROTECTED_PG:
return addr + seg->base;
break;
default:
operand_type_t addr_type = INVALID_OPERAND;
char * instr_cursor = modrm_instr;
- PrintDebug("ModRM mod=%d\n", modrm->mod);
+ // 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);
+ //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
*first_operand = decode_register(gprs, modrm->rm, reg_size);
mod_mode = REG;
addr_type = REG_OPERAND;
- PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
+ // PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
*first_operand = decode_register(gprs, modrm->rm, reg_size);
+#endif // !__V3VEE__
+
#endif