svn commit: r360177 - head/sys/amd64/vmm
Conrad Meyer
cem at FreeBSD.org
Tue Apr 21 21:34:24 UTC 2020
Author: cem
Date: Tue Apr 21 21:34:24 2020
New Revision: 360177
URL: https://svnweb.freebsd.org/changeset/base/360177
Log:
vmm(4): Decode and emulate BEXTR
Clang 10 -march=native kernels on znver1 emit BEXTR for APIC reads,
apparently. Decode and emulate the instruction.
Reviewed by: grehan
Differential Revision: https://reviews.freebsd.org/D24463
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 Tue Apr 21 21:33:06 2020 (r360176)
+++ head/sys/amd64/vmm/vmm_instruction_emul.c Tue Apr 21 21:34:24 2020 (r360177)
@@ -84,6 +84,7 @@ enum {
VIE_OP_TYPE_TWOB_GRP15,
VIE_OP_TYPE_ADD,
VIE_OP_TYPE_TEST,
+ VIE_OP_TYPE_BEXTR,
VIE_OP_TYPE_LAST
};
@@ -95,6 +96,10 @@ enum {
#define VIE_OP_F_NO_GLA_VERIFICATION (1 << 4)
static const struct vie_op three_byte_opcodes_0f38[256] = {
+ [0xF7] = {
+ .op_byte = 0xF7,
+ .op_type = VIE_OP_TYPE_BEXTR,
+ },
};
static const struct vie_op two_byte_opcodes[256] = {
@@ -1318,6 +1323,83 @@ emulate_test(void *vm, int vcpuid, uint64_t gpa, struc
}
static int
+emulate_bextr(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
+ struct vm_guest_paging *paging, mem_region_read_t memread,
+ mem_region_write_t memwrite, void *arg)
+{
+ uint64_t src1, src2, dst, rflags;
+ unsigned start, len;
+ int error, size;
+
+ size = vie->opsize;
+ error = EINVAL;
+
+ /*
+ * VEX.LZ.0F38.W0 F7 /r BEXTR r32a, r/m32, r32b
+ * VEX.LZ.0F38.W1 F7 /r BEXTR r64a, r/m64, r64b
+ *
+ * Destination operand is ModRM:reg. Source operands are ModRM:r/m and
+ * Vex.vvvv.
+ *
+ * Operand size is always 32-bit if not in 64-bit mode (W1 is ignored).
+ */
+ if (size != 4 && paging->cpu_mode != CPU_MODE_64BIT)
+ size = 4;
+
+ /*
+ * Extracts contiguous bits from the first /source/ operand (second
+ * operand) using an index and length specified in the second /source/
+ * operand (third operand).
+ */
+ error = memread(vm, vcpuid, gpa, &src1, size, arg);
+ if (error)
+ return (error);
+ error = vie_read_register(vm, vcpuid, gpr_map[vie->vex_reg], &src2);
+ if (error)
+ return (error);
+ error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);
+ if (error)
+ return (error);
+
+ start = (src2 & 0xff);
+ len = (src2 & 0xff00) >> 8;
+
+ /* If no bits are extracted, the destination register is cleared. */
+ dst = 0;
+
+ /* If START exceeds the operand size, no bits are extracted. */
+ if (start > size * 8)
+ goto done;
+ /* Length is bounded by both the destination size and start offset. */
+ if (start + len > size * 8)
+ len = (size * 8) - start;
+ if (len == 0)
+ goto done;
+
+ if (start > 0)
+ src1 = (src1 >> start);
+ if (len < 64)
+ src1 = src1 & ((1ull << len) - 1);
+ dst = src1;
+
+done:
+ error = vie_update_register(vm, vcpuid, gpr_map[vie->reg], dst, size);
+ if (error)
+ return (error);
+
+ /*
+ * AMD: OF, CF cleared; SF/AF/PF undefined; ZF set by result.
+ * Intel: ZF is set by result; AF/SF/PF undefined; all others cleared.
+ */
+ rflags &= ~RFLAGS_STATUS_BITS;
+ if (dst == 0)
+ rflags |= PSL_Z;
+ error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags,
+ 8);
+ return (error);
+}
+
+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)
{
@@ -1744,6 +1826,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t
break;
case VIE_OP_TYPE_TEST:
error = emulate_test(vm, vcpuid, gpa, vie,
+ memread, memwrite, memarg);
+ break;
+ case VIE_OP_TYPE_BEXTR:
+ error = emulate_bextr(vm, vcpuid, gpa, vie, paging,
memread, memwrite, memarg);
break;
default:
More information about the svn-src-all
mailing list