Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


significant refactoring of RTM emulation code
[palacios.git] / palacios / src / palacios / vmm_quix86.c
index fd64626..befc9d1 100644 (file)
@@ -7,8 +7,8 @@
  * and the University of New Mexico.  You can find out more at
  * http://www.v3vee.org
  *
- * Copyright (c) 2011, Jack Lange <jarusl@cs.northwestern.edu>
- * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * Copyright (c) 2012,  Alexander Kudryavtsev <alexk@ispras.ru>
+ * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org>
  * All rights reserved.
  *
  * Author: Alexander Kudryavtsev <alexk@ispras.ru>
 
 #include <quix86/quix86.h>
 
+#ifdef V3_CONFIG_TM_FUNC
+#include <extensions/trans_mem.h>
+#endif
+
+#ifdef V3_CONFIG_DEBUG_TM_FUNC
+#define PrintTMDebug(...) V3_Print(__VA_ARGS__)
+#else
+#define PrintTMDebug(...)
+#endif
+
 #ifndef V3_CONFIG_DEBUG_DECODER
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
@@ -45,73 +55,10 @@ int v3_deinit_decoder(struct guest_info * core) {
     return 0;
 }
 
-static int get_opcode(qx86_insn *inst);
+static int get_opcode(qx86_insn *inst, struct guest_info *core);
 static int qx86_register_to_v3_reg(struct guest_info * info, int qx86_reg,
                  addr_t * v3_reg, uint_t * reg_len);
 
-static int decode_string_op(struct guest_info * info,
-                const qx86_insn * qx86_inst, struct x86_instr * instr)
-{
-    int status = 0;
-    PrintDebug("String operation\n");
-
-    if (instr->prefixes.rep == 1) {
-        uint64_t a_mask = ~(~0ULL <<
-                (QX86_SIZE_OCTETS(qx86_inst->attributes.addressSize) * 8));
-
-        instr->str_op_length = info->vm_regs.rcx & a_mask;
-    } else {
-        instr->str_op_length = 1;
-    }
-
-
-    if (instr->op_type == V3_OP_MOVS) {
-        instr->num_operands = 2;
-
-        if((status = qx86_calculate_linear_address(qx86_inst, 0,
-                (qx86_uint64*)&instr->dst_operand.operand)) != QX86_SUCCESS) {
-            PrintError("Could not get destination memory operand: "
-                    "qx86_calculate_linear_address: %d\n", status);
-            return -1;
-        }
-
-        if((status = qx86_calculate_linear_address(qx86_inst, 1,
-                (qx86_uint64*)&instr->src_operand.operand)) != QX86_SUCCESS) {
-            PrintError("Could not get source memory operand: "
-                    "qx86_calculate_linear_address: %d\n", status);
-            return -1;
-        }
-
-        instr->dst_operand.write = 1;
-        instr->src_operand.read = 1;
-
-    } else if (instr->op_type == V3_OP_STOS) {
-        instr->num_operands = 2;
-
-        if((status = qx86_calculate_linear_address(qx86_inst, 0,
-                (qx86_uint64*)&instr->dst_operand.operand)) != QX86_SUCCESS) {
-            PrintError("Could not get destination memory operand: "
-                    "qx86_calculate_linear_address: %d\n", status);
-            return -1;
-        }
-
-        // STOS reads from rax
-        qx86_register_to_v3_reg(info,
-            qx86_inst->operands[1].u.r.rindex,
-            &(instr->src_operand.operand), &(instr->src_operand.size));
-        instr->src_operand.type = REG_OPERAND;
-
-        instr->src_operand.read = 1;
-        instr->dst_operand.write = 1;
-
-    } else {
-        PrintError("Unhandled String OP\n");
-        return -1;
-    }
-
-    return 0;
-}
-
 static int callback(void *data, int rindex, int subreg, unsigned char *value) {
     void* reg_addr = 0;
     uint_t reg_size;
@@ -122,7 +69,7 @@ static int callback(void *data, int rindex, int subreg, unsigned char *value) {
         (addr_t*)&reg_addr, &reg_size);
 
     if(v3_reg_type == -1) {
-        PrintError("Callback failed to get register index %d\n", rindex);
+        PrintError(info->vm_info, info, "Callback failed to get register index %d\n", rindex);
         return 0;
     }
 
@@ -135,10 +82,10 @@ static int callback(void *data, int rindex, int subreg, unsigned char *value) {
         *(uint32_t*)value = ((struct v3_segment*)reg_addr)->limit;
         break;
     case QX86_SUBREG_FLAGS:
-        PrintError("Callback doesn't know how to give flags.\n");
+        PrintError(info->vm_info, info, "Callback doesn't know how to give flags.\n");
         return 0;
     case QX86_SUBREG_NONE: {
-        switch(qx86_rtab[rindex].size) {
+        switch(qx86_rinfo(rindex)->size) {
         case 1: *(uint8_t* )value = *(uint8_t* )reg_addr; break;
         case 2: *(uint16_t*)value = *(uint16_t*)reg_addr; break;
         case 4: *(uint32_t*)value = *(uint32_t*)reg_addr; break;
@@ -161,8 +108,8 @@ static inline int qx86_op_to_v3_op(struct guest_info *info, qx86_insn *qx86_insn
                 &(v3_op->operand), &(v3_op->size));
 
         if (v3_reg_type == -1) {
-            PrintError("Operand %d is an Unhandled Operand: %s\n", op_num,
-                    qx86_rtab[qx86_op->u.r.rindex].name);
+            PrintError(info->vm_info, info, "Operand %d is an Unhandled Operand: %s\n", op_num,
+                    qx86_rinfo(qx86_op->u.r.rindex)->name);
             v3_op->type = INVALID_OPERAND;
             return -1;
         } else if (v3_reg_type == SEGMENT_REGISTER) {
@@ -172,10 +119,10 @@ static inline int qx86_op_to_v3_op(struct guest_info *info, qx86_insn *qx86_insn
         v3_op->type = REG_OPERAND;
 
     } else if(qx86_op->ot == QX86_OPERAND_TYPE_MEMORY) {
-        PrintDebug("Memory operand (%d)\n", op_num);
+        PrintDebug(info->vm_info, info, "Memory operand (%d)\n", op_num);
         if((status = qx86_calculate_linear_address(qx86_insn, op_num,
                 (qx86_uint64*)&v3_op->operand)) != QX86_SUCCESS) {
-            PrintError("Could not get memory operand %d: "
+            PrintError(info->vm_info, info, "Could not get memory operand %d: "
                     "qx86_calculate_linear_address() returns %d\n", op_num, status);
             return -1;
         }
@@ -186,14 +133,14 @@ static inline int qx86_op_to_v3_op(struct guest_info *info, qx86_insn *qx86_insn
         v3_op->size = qx86_op->u.i.valueSize;
 
         if (v3_op->size > 4) {
-            PrintError("Unhandled 64 bit immediates\n");
+            PrintError(info->vm_info, info, "Unhandled 64 bit immediates\n");
             return -1;
         }
         v3_op->operand = (addr_t)*(uint64_t*)qx86_op->u.i.value;
         v3_op->type = IMM_OPERAND;
 
     } else {
-        PrintError("Unhandled Operand %d Type %d\n", op_num, qx86_op->ot);
+        PrintError(info->vm_info, info, "Unhandled Operand %d Type %d\n", op_num, qx86_op->ot);
         return -1;
     }
 
@@ -214,6 +161,13 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
     memset(instr, 0, sizeof(struct x86_instr));
     memset(&qx86_inst, 0, sizeof(qx86_inst));
 
+#ifdef V3_CONFIG_TM_FUNC
+    if (v3_tm_decode_rtm_instrs(info, instr_ptr, instr) == -1) {
+        return -1;
+    }
+#endif
+
+
     v3_get_prefixes((uchar_t *)instr_ptr, &(instr->prefixes));
 
     switch(v3_get_vm_cpu_mode(info)) {
@@ -224,7 +178,7 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
     case LONG:
         proc_mode = QX86_SIZE_64; break;
     default:
-        PrintError("Unsupported CPU mode: %d\n", info->cpu_mode);
+        PrintError(info->vm_info, info, "Unsupported CPU mode: %d\n", info->cpu_mode);
         return -1;
     }
 
@@ -241,13 +195,13 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
                     (info->rip & ~0xfffULL) + 0x1000, &(info->segments.cs)), &instr_ptr2);
         }
         if (status == -1) {
-            PrintError("Could not translate Instruction Address at second stage "
+            PrintError(info->vm_info, info, "Could not translate Instruction Address at second stage "
                     "translation (%p)\n", (void *)(addr_t)info->rip);
             return -1;
         }
 
         if(((instr_ptr & ~0xfffUL) + 0x1000) != instr_ptr2) {
-            PrintError("Note: physical page non-contiguous\n");
+            PrintError(info->vm_info, info, "Note: physical page non-contiguous\n");
             memcpy(inst_buf, (const void*)instr_ptr, left_in_page);
             memcpy(inst_buf + left_in_page, (const void*)instr_ptr2,
                     QX86_INSN_SIZE_MAX - left_in_page);
@@ -261,21 +215,36 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
     int status = qx86_decode(&qx86_inst, proc_mode,
             (const void*)instr_ptr, QX86_INSN_SIZE_MAX);
     if(status != QX86_SUCCESS) {
-        PrintError("qx86_decode() returned %d\n", status);
+        PrintError(info->vm_info, info, "qx86_decode() returned %d\n", status);
         return -1;
     }
 
     instr->instr_length = qx86_inst.rawSize;
 
-    if ((instr->op_type = get_opcode(&qx86_inst)) == V3_INVALID_OP) {
-        PrintError("Could not get opcode. (mnemonic=%s)\n",
-                qx86_mtab[qx86_inst.mnemonic].name);
+    // 441 - dump memory for quix86 debugging
+    if ((instr->op_type = get_opcode(&qx86_inst,info)) == V3_INVALID_OP) {
+        PrintError(info->vm_info, info, "++==++ QX86 DECODE ++==++, guest RIP: %llx\n", info->rip);
+        v3_dump_mem((void *)instr_ptr, 15);
+        PrintError(info->vm_info, info, "Could not get opcode. (mnemonic=%s)\n",
+                qx86_minfo(qx86_inst.mnemonic)->name);
+        return -1;
+    }
+    if ((instr->op_type = get_opcode(&qx86_inst, info)) == V3_INVALID_OP) {
+        PrintError(info->vm_info, info, "Could not get opcode. (mnemonic=%s)\n",
+                qx86_minfo(qx86_inst.mnemonic)->name);
         return -1;
     }
 
     if(instr->op_type == V3_OP_MOVS || instr->op_type == V3_OP_STOS) {
         instr->is_str_op = 1;
-        return decode_string_op(info, &qx86_inst, instr);
+        if (instr->prefixes.rep == 1) {
+            uint64_t a_mask = (~0ULL >>
+                (64 - QX86_SIZE_OCTETS(qx86_inst.attributes.addressSize) * 8));
+
+            instr->str_op_length = info->vm_regs.rcx & a_mask;
+        } else {
+            instr->str_op_length = 1;
+        }
     } else {
         instr->is_str_op = 0;
         instr->str_op_length = 0;
@@ -306,20 +275,20 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
     char buf[128];
     int buf_sz = 128;
     if(qx86_print_intel(&qx86_inst, &opt, buf, &buf_sz) != QX86_SUCCESS) {
-        PrintDebug("Print failed!\n");
+        PrintDebug(info->vm_info, info, "Print failed!\n");
     } else {
-        PrintDebug("Instruction (%p): %s\n", (void*)info->rip, buf);
+        PrintDebug(info->vm_info, info, "Instruction (%p): %s\n", (void*)info->rip, buf);
     }
-    PrintDebug("Operands: dst %p src %p 3rd %p\n", (void*)instr->dst_operand.operand,
+    PrintDebug(info->vm_info, info, "Operands: dst %p src %p 3rd %p\n", (void*)instr->dst_operand.operand,
             (void*)instr->src_operand.operand, (void*)instr->third_operand.operand);
 #endif
     return 0;
 }
 
-static int get_opcode(qx86_insn *inst) {
+static int get_opcode(qx86_insn *inst, struct guest_info *core) {
     switch (inst->mnemonic) {
 #define IS_CR(op) inst->operands[op].ot == QX86_OPERAND_TYPE_REGISTER && \
-    qx86_rtab[inst->operands[op].u.r.rindex].rclass == QX86_RCLASS_CREG
+    qx86_rinfo(inst->operands[op].u.r.rindex)->rclass == QX86_RCLASS_CREG
 
     /* MOV cases */
     case QX86_MNEMONIC_MOV: {
@@ -330,8 +299,12 @@ static int get_opcode(qx86_insn *inst) {
             return V3_OP_MOV2CR;
         if(IS_CR(1))
             return V3_OP_MOVCR2;
+        // 441 - mov reg reg is also ok
+        if(inst->operands[0].ot == QX86_OPERAND_TYPE_REGISTER
+                || inst->operands[1].ot == QX86_OPERAND_TYPE_REGISTER)
+            return V3_OP_MOV;
 
-        PrintError("Bad operand types for MOV: %d %d\n", inst->operands[0].ot,
+        PrintError(core->vm_info, core, "Bad operand types for MOV: %d %d\n", inst->operands[0].ot,
                 inst->operands[1].ot);
         return V3_INVALID_OP;
     }
@@ -451,6 +424,66 @@ static int get_opcode(qx86_insn *inst) {
     case QX86_MNEMONIC_STOSQ:
         return V3_OP_STOS;
 
+    /* 441-tm: add in CMP, POP, JLE, CALL cases */
+    case QX86_MNEMONIC_CMP:
+        return V3_OP_CMP;
+
+    case QX86_MNEMONIC_POP:
+        return V3_OP_POP;
+
+    case QX86_MNEMONIC_JLE:
+        return V3_OP_JLE;
+
+    case QX86_MNEMONIC_CALL:
+        return V3_OP_CALL;
+
+    case QX86_MNEMONIC_TEST:
+        return V3_OP_TEST;
+
+    case QX86_MNEMONIC_PUSH:
+        return V3_OP_PUSH;
+
+    case QX86_MNEMONIC_JAE:
+        return V3_OP_JAE;
+
+    case QX86_MNEMONIC_JMP:
+        return V3_OP_JMP;
+
+    case QX86_MNEMONIC_JNZ:
+        return V3_OP_JNZ;
+
+    case QX86_MNEMONIC_JZ:
+        return V3_OP_JZ;
+
+    case QX86_MNEMONIC_RET:
+        return V3_OP_RET;
+
+    case QX86_MNEMONIC_IMUL:
+        return V3_OP_IMUL;
+
+    case QX86_MNEMONIC_LEA:
+        return V3_OP_LEA;
+
+    case QX86_MNEMONIC_JL:
+        return V3_OP_JL;
+
+    case QX86_MNEMONIC_CMOVZ:
+        return V3_OP_CMOVZ;
+
+    case QX86_MNEMONIC_MOVSXD:
+        return V3_OP_MOVSXD;
+
+    case QX86_MNEMONIC_JNS:
+        return V3_OP_JNS;
+
+    case QX86_MNEMONIC_CMOVS:
+        return V3_OP_CMOVS;
+
+    case QX86_MNEMONIC_SHL:
+        return V3_OP_SHL;
+
+    case QX86_MNEMONIC_INT:
+        return V3_OP_INT;
 
     default:
         return V3_INVALID_OP;
@@ -459,7 +492,7 @@ static int get_opcode(qx86_insn *inst) {
 
 static int qx86_register_to_v3_reg(struct guest_info * info, int qx86_reg,
                  addr_t * v3_reg, uint_t * reg_len) {
-    PrintDebug("qx86 Register: %s\n", qx86_rtab[qx86_reg].name);
+    PrintDebug(info->vm_info, info, "qx86 Register: %s\n", qx86_rinfo(qx86_reg)->name);
 
     switch (qx86_reg) {
     case QX86_REGISTER_INVALID:
@@ -807,7 +840,7 @@ static int qx86_register_to_v3_reg(struct guest_info * info, int qx86_reg,
         *reg_len = 4;
         return CTRL_REGISTER;
     case QX86_REGISTER_CR8:
-        *v3_reg = (addr_t)&(info->ctrl_regs.cr8);
+        *v3_reg = (addr_t)&(info->ctrl_regs.apic_tpr);
         *reg_len = 4;
         return CTRL_REGISTER;