Author: tychon
Date: Wed Feb  5 02:01:08 2014
New Revision: 261503
URL: http://svnweb.freebsd.org/changeset/base/261503

Log:
  Add support for emulating the byte move and zero extend instructions:
  "mov r/m8, r32" and "mov r/m8, r64".
  
  Approved by:  neel (co-mentor)

Modified:
  head/sys/amd64/vmm/vmm_instruction_emul.c

Modified: head/sys/amd64/vmm/vmm_instruction_emul.c
==============================================================================
--- head/sys/amd64/vmm/vmm_instruction_emul.c   Wed Feb  5 02:00:31 2014        
(r261502)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c   Wed Feb  5 02:01:08 2014        
(r261503)
@@ -58,8 +58,10 @@ enum cpu_mode {
 enum {
        VIE_OP_TYPE_NONE = 0,
        VIE_OP_TYPE_MOV,
+       VIE_OP_TYPE_MOVZX,
        VIE_OP_TYPE_AND,
        VIE_OP_TYPE_OR,
+       VIE_OP_TYPE_TWO_BYTE,
        VIE_OP_TYPE_LAST
 };
 
@@ -67,7 +69,18 @@ enum {
 #define        VIE_OP_F_IMM            (1 << 0)        /* immediate operand 
present */
 #define        VIE_OP_F_IMM8           (1 << 1)        /* 8-bit immediate 
operand */
 
+static const struct vie_op two_byte_opcodes[256] = {
+       [0xB6] = {
+               .op_byte = 0xB6,
+               .op_type = VIE_OP_TYPE_MOVZX,
+       },
+};
+
 static const struct vie_op one_byte_opcodes[256] = {
+       [0x0F] = {
+               .op_byte = 0x0F,
+               .op_type = VIE_OP_TYPE_TWO_BYTE
+       },
        [0x88] = {
                .op_byte = 0x88,
                .op_type = VIE_OP_TYPE_MOV,
@@ -313,6 +326,59 @@ emulate_mov(void *vm, int vcpuid, uint64
        return (error);
 }
 
+/*
+ * The following simplifying assumptions are made during emulation:
+ *
+ * - guest is in 64-bit mode
+ *   - default address size is 64-bits
+ *   - default operand size is 32-bits
+ *
+ * - operand size override is not supported
+ *
+ * - address size override is not supported
+ */
+static int
+emulate_movzx(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
+             mem_region_read_t memread, mem_region_write_t memwrite,
+             void *arg)
+{
+       int error, size;
+       enum vm_reg_name reg;
+       uint64_t val;
+
+       size = 4;
+       error = EINVAL;
+
+       switch (vie->op.op_byte) {
+       case 0xB6:
+               /*
+                * MOV and zero extend byte from mem (ModRM:r/m) to
+                * reg (ModRM:reg).
+                *
+                * 0F B6/r              movzx r/m8, r32
+                * REX.W + 0F B6/r      movzx r/m8, r64
+                */
+
+               /* get the first operand */
+               error = memread(vm, vcpuid, gpa, &val, 1, arg);
+               if (error)
+                       break;
+
+               /* get the second operand */
+               reg = gpr_map[vie->reg];
+
+               if (vie->rex_w)
+                       size = 8;
+
+               /* write the result */
+               error = vie_update_register(vm, vcpuid, reg, val, size);
+               break;
+       default:
+               break;
+       }
+       return (error);
+}
+
 static int
 emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
            mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
@@ -447,6 +513,10 @@ vmm_emulate_instruction(void *vm, int vc
                error = emulate_mov(vm, vcpuid, gpa, vie,
                                    memread, memwrite, memarg);
                break;
+       case VIE_OP_TYPE_MOVZX:
+               error = emulate_movzx(vm, vcpuid, gpa, vie,
+                                     memread, memwrite, memarg);
+               break;
        case VIE_OP_TYPE_AND:
                error = emulate_and(vm, vcpuid, gpa, vie,
                                    memread, memwrite, memarg);
@@ -609,6 +679,23 @@ decode_rex(struct vie *vie)
 }
 
 static int
+decode_two_byte_opcode(struct vie *vie)
+{
+       uint8_t x;
+
+       if (vie_peek(vie, &x))
+               return (-1);
+
+       vie->op = two_byte_opcodes[x];
+
+       if (vie->op.op_type == VIE_OP_TYPE_NONE)
+               return (-1);
+
+       vie_advance(vie);
+       return (0);
+}
+
+static int
 decode_opcode(struct vie *vie)
 {
        uint8_t x;
@@ -622,6 +709,10 @@ decode_opcode(struct vie *vie)
                return (-1);
 
        vie_advance(vie);
+
+       if (vie->op.op_type == VIE_OP_TYPE_TWO_BYTE)
+               return (decode_two_byte_opcode(vie));
+
        return (0);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to