Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Jun 2019 21:59:43 +0000 (UTC)
From:      "Rodney W. Grimes" <rgrimes@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r349443 - in stable: 11/sys/amd64/vmm 12/sys/amd64/vmm
Message-ID:  <201906262159.x5QLxh2w020387@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rgrimes
Date: Wed Jun 26 21:59:43 2019
New Revision: 349443
URL: https://svnweb.freebsd.org/changeset/base/349443

Log:
  MFC: r347065 (by jhb) Emulate the "ADD reg, r/m" instruction (opcode 03H).
  
  OVMF's flash variable storage is using add instructions when indexing
  the variable store bootrom location.

Modified:
  stable/11/sys/amd64/vmm/vmm_instruction_emul.c
Directory Properties:
  stable/11/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/12/sys/amd64/vmm/vmm_instruction_emul.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/11/sys/amd64/vmm/vmm_instruction_emul.c
==============================================================================
--- stable/11/sys/amd64/vmm/vmm_instruction_emul.c	Wed Jun 26 21:43:41 2019	(r349442)
+++ stable/11/sys/amd64/vmm/vmm_instruction_emul.c	Wed Jun 26 21:59:43 2019	(r349443)
@@ -75,6 +75,7 @@ enum {
 	VIE_OP_TYPE_STOS,
 	VIE_OP_TYPE_BITTEST,
 	VIE_OP_TYPE_TWOB_GRP15,
+	VIE_OP_TYPE_ADD,
 	VIE_OP_TYPE_LAST
 };
 
@@ -110,6 +111,10 @@ static const struct vie_op two_byte_opcodes[256] = {
 };
 
 static const struct vie_op one_byte_opcodes[256] = {
+	[0x03] = {
+		.op_byte = 0x03,
+		.op_type = VIE_OP_TYPE_ADD,
+	},
 	[0x0F] = {
 		.op_byte = 0x0F,
 		.op_type = VIE_OP_TYPE_TWO_BYTE
@@ -408,6 +413,41 @@ getcc(int opsize, uint64_t x, uint64_t y)
 		return (getcc64(x, y));
 }
 
+/*
+ * Macro creation of functions getaddflags{8,16,32,64}
+ */
+#define	GETADDFLAGS(sz)							\
+static u_long								\
+getaddflags##sz(uint##sz##_t x, uint##sz##_t y)				\
+{									\
+	u_long rflags;							\
+									\
+	__asm __volatile("add %2,%1; pushfq; popq %0" :			\
+	    "=r" (rflags), "+r" (x) : "m" (y));				\
+	return (rflags);						\
+} struct __hack
+
+GETADDFLAGS(8);
+GETADDFLAGS(16);
+GETADDFLAGS(32);
+GETADDFLAGS(64);
+
+static u_long
+getaddflags(int opsize, uint64_t x, uint64_t y)
+{
+	KASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8,
+	    ("getaddflags: invalid operand size %d", opsize));
+
+	if (opsize == 1)
+		return (getaddflags8(x, y));
+	else if (opsize == 2)
+		return (getaddflags16(x, y));
+	else if (opsize == 4)
+		return (getaddflags32(x, y));
+	else
+		return (getaddflags64(x, y));
+}
+
 static int
 emulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
 	    mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
@@ -1177,6 +1217,62 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct
 }
 
 static int
+emulate_add(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 0x03:
+		/*
+		 * ADD r/m to r and store the result in r
+		 *
+		 * 03/r            ADD r16, r/m16
+		 * 03/r            ADD r32, r/m32
+		 * REX.W + 03/r    ADD 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 = getaddflags(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_sub(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
 	    mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
 {
@@ -1540,6 +1636,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t
 	case VIE_OP_TYPE_TWOB_GRP15:
 		error = emulate_twob_group15(vm, vcpuid, gpa, vie,
 		    memread, memwrite, memarg);
+		break;
+	case VIE_OP_TYPE_ADD:
+		error = emulate_add(vm, vcpuid, gpa, vie, memread,
+		    memwrite, memarg);
 		break;
 	default:
 		error = EINVAL;



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