Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Aug 2014 00:53:57 +0000 (UTC)
From:      Peter Grehan <grehan@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r270689 - head/sys/amd64/vmm
Message-ID:  <201408270053.s7R0rvPI024669@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: grehan
Date: Wed Aug 27 00:53:56 2014
New Revision: 270689
URL: http://svnweb.freebsd.org/changeset/base/270689

Log:
  Implement the 0x2B SUB instruction, and the OR variant of 0x81.
  
  Found with local APIC accesses from bitrig/amd64 bsd.rd, 07/15-snap.
  
  Reviewed by:	neel
  MFC after:	3 days

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 Aug 27 00:50:51 2014	(r270688)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c	Wed Aug 27 00:53:56 2014	(r270689)
@@ -65,6 +65,7 @@ enum {
 	VIE_OP_TYPE_MOVZX,
 	VIE_OP_TYPE_AND,
 	VIE_OP_TYPE_OR,
+	VIE_OP_TYPE_SUB,
 	VIE_OP_TYPE_TWO_BYTE,
 	VIE_OP_TYPE_PUSH,
 	VIE_OP_TYPE_CMP,
@@ -97,6 +98,10 @@ static const struct vie_op one_byte_opco
 		.op_byte = 0x0F,
 		.op_type = VIE_OP_TYPE_TWO_BYTE
 	},
+	[0x2B] = {
+		.op_byte = 0x2B,
+		.op_type = VIE_OP_TYPE_SUB,
+	},
 	[0x3B] = {
 		.op_byte = 0x3B,
 		.op_type = VIE_OP_TYPE_CMP,
@@ -597,18 +602,16 @@ emulate_and(void *vm, int vcpuid, uint64
 		break;
 	case 0x81:
 		/*
-		 * AND mem (ModRM:r/m) with immediate and store the
+		 * AND/OR mem (ModRM:r/m) with immediate and store the
 		 * result in mem.
 		 *
-		 * 81 /4		and r/m16, imm16
-		 * 81 /4		and r/m32, imm32
-		 * REX.W + 81 /4	and r/m64, imm32 sign-extended to 64
+		 * AND: i = 4
+		 * OR:  i = 1
+		 * 81 /i		op r/m16, imm16
+		 * 81 /i		op r/m32, imm32
+		 * REX.W + 81 /i	op r/m64, imm32 sign-extended to 64
 		 *
-		 * Currently, only the AND operation of the 0x81 opcode
-		 * is implemented (ModRM:reg = b100).
 		 */
-		if ((vie->reg & 7) != 4)
-			break;
 
 		/* get the first operand */
                 error = memread(vm, vcpuid, gpa, &val1, size, arg);
@@ -616,11 +619,26 @@ emulate_and(void *vm, int vcpuid, uint64
 			break;
 
                 /*
-		 * perform the operation with the pre-fetched immediate
-		 * operand and write the result
-		 */
-                val1 &= vie->immediate;
-                error = memwrite(vm, vcpuid, gpa, val1, size, arg);
+                 * perform the operation with the pre-fetched immediate
+                 * operand and write the result
+                 */
+		switch (vie->reg & 7) {
+		case 0x4:
+			/* modrm:reg == b100, AND */
+			val1 &= vie->immediate;
+			break;
+		case 0x1:
+			/* modrm:reg == b001, OR */
+			val1 |= vie->immediate;
+			break;
+		default:
+			error = EINVAL;
+			break;
+		}
+		if (error)
+			break;
+
+		error = memwrite(vm, vcpuid, gpa, val1, size, arg);
 		break;
 	default:
 		break;
@@ -723,6 +741,62 @@ emulate_cmp(void *vm, int vcpuid, uint64
 }
 
 static int
+emulate_sub(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;
+	uint64_t nval, rflags, rflags2, val1, val2;
+	enum vm_reg_name reg;
+
+	size = vie->opsize;
+	error = EINVAL;
+
+	switch (vie->op.op_byte) {
+	case 0x2B:
+		/*
+		 * SUB r/m from r and store the result in r
+		 * 
+		 * 2B/r            SUB r16, r/m16
+		 * 2B/r            SUB r32, r/m32
+		 * REX.W + 2B/r    SUB r64, r/m64
+		 */
+
+		/* get the first operand */
+		reg = gpr_map[vie->reg];
+		error = vie_read_register(vm, vcpuid, reg, &val1);
+		if (error)
+			break;
+
+		/* get the second operand */
+		error = memread(vm, vcpuid, gpa, &val2, size, arg);
+		if (error)
+			break;
+
+		/* perform the operation and write the result */
+		nval = val1 - val2;
+		error = vie_update_register(vm, vcpuid, reg, nval, size);
+		break;
+	default:
+		break;
+	}
+
+	if (!error) {
+		rflags2 = getcc(size, val1, val2);
+		error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS,
+		    &rflags);
+		if (error)
+			return (error);
+
+		rflags &= ~RFLAGS_STATUS_BITS;
+		rflags |= rflags2 & RFLAGS_STATUS_BITS;
+		error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS,
+		    rflags, 8);
+	}
+
+	return (error);
+}
+
+static int
 emulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
     struct vm_guest_paging *paging, mem_region_read_t memread,
     mem_region_write_t memwrite, void *arg)
@@ -865,6 +939,10 @@ vmm_emulate_instruction(void *vm, int vc
 		error = emulate_or(vm, vcpuid, gpa, vie,
 				    memread, memwrite, memarg);
 		break;
+	case VIE_OP_TYPE_SUB:
+		error = emulate_sub(vm, vcpuid, gpa, vie,
+				    memread, memwrite, memarg);
+		break;
 	default:
 		error = EINVAL;
 		break;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408270053.s7R0rvPI024669>