summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2013-01-30 04:09:09 +0000
committerneel <neel@FreeBSD.org>2013-01-30 04:09:09 +0000
commit1ae7af0ed87a074e560452e9f87dc50964a20275 (patch)
tree788e6ade362dec2dfc50f82c704250d3b43db371 /sys/amd64
parent4a8d6a5695da92c747161660a417dd68846f21fa (diff)
downloadFreeBSD-src-1ae7af0ed87a074e560452e9f87dc50964a20275.zip
FreeBSD-src-1ae7af0ed87a074e560452e9f87dc50964a20275.tar.gz
Add emulation support for instruction "88/r: mov r/m8, r8".
This instruction moves a byte from a register to a memory location. Tested by: tycho nightingale at pluribusnetworks com
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/include/vmm_instruction_emul.h3
-rw-r--r--sys/amd64/vmm/vmm_instruction_emul.c58
2 files changed, 60 insertions, 1 deletions
diff --git a/sys/amd64/include/vmm_instruction_emul.h b/sys/amd64/include/vmm_instruction_emul.h
index 4cc494b..4c7a346 100644
--- a/sys/amd64/include/vmm_instruction_emul.h
+++ b/sys/amd64/include/vmm_instruction_emul.h
@@ -49,7 +49,8 @@ struct vie {
uint8_t rex_w:1, /* REX prefix */
rex_r:1,
rex_x:1,
- rex_b:1;
+ rex_b:1,
+ rex_present:1;
uint8_t mod:2, /* ModRM byte */
reg:4,
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c
index e73f6bb..40748ea 100644
--- a/sys/amd64/vmm/vmm_instruction_emul.c
+++ b/sys/amd64/vmm/vmm_instruction_emul.c
@@ -65,6 +65,10 @@ enum {
#define VIE_OP_F_IMM8 (1 << 1) /* 8-bit immediate operand */
static const struct vie_op one_byte_opcodes[256] = {
+ [0x88] = {
+ .op_byte = 0x88,
+ .op_type = VIE_OP_TYPE_MOV,
+ },
[0x89] = {
.op_byte = 0x89,
.op_type = VIE_OP_TYPE_MOV,
@@ -161,6 +165,46 @@ vie_read_register(void *vm, int vcpuid, enum vm_reg_name reg, uint64_t *rval)
}
static int
+vie_read_bytereg(void *vm, int vcpuid, struct vie *vie, uint8_t *rval)
+{
+ uint64_t val;
+ int error, rshift;
+ enum vm_reg_name reg;
+
+ rshift = 0;
+ reg = gpr_map[vie->reg];
+
+ /*
+ * 64-bit mode imposes limitations on accessing legacy byte registers.
+ *
+ * The legacy high-byte registers cannot be addressed if the REX
+ * prefix is present. In this case the values 4, 5, 6 and 7 of the
+ * 'ModRM:reg' field address %spl, %bpl, %sil and %dil respectively.
+ *
+ * If the REX prefix is not present then the values 4, 5, 6 and 7
+ * of the 'ModRM:reg' field address the legacy high-byte registers,
+ * %ah, %ch, %dh and %bh respectively.
+ */
+ if (!vie->rex_present) {
+ if (vie->reg & 0x4) {
+ /*
+ * Obtain the value of %ah by reading %rax and shifting
+ * right by 8 bits (same for %bh, %ch and %dh).
+ */
+ rshift = 8;
+ reg = gpr_map[vie->reg & 0x3];
+ }
+ }
+
+ if (!vie_valid_register(reg))
+ return (EINVAL);
+
+ error = vm_get_register(vm, vcpuid, reg, &val);
+ *rval = val >> rshift;
+ return (error);
+}
+
+static int
vie_update_register(void *vm, int vcpuid, enum vm_reg_name reg,
uint64_t val, int size)
{
@@ -209,12 +253,24 @@ emulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
{
int error, size;
enum vm_reg_name reg;
+ uint8_t byte;
uint64_t val;
size = 4;
error = EINVAL;
switch (vie->op.op_byte) {
+ case 0x88:
+ /*
+ * MOV byte from reg (ModRM:reg) to mem (ModRM:r/m)
+ * 88/r: mov r/m8, r8
+ * REX + 88/r: mov r/m8, r8 (%ah, %ch, %dh, %bh not available)
+ */
+ size = 1;
+ error = vie_read_bytereg(vm, vcpuid, vie, &byte);
+ if (error == 0)
+ error = memwrite(vm, vcpuid, gpa, byte, size, arg);
+ break;
case 0x89:
/*
* MOV from reg (ModRM:reg) to mem (ModRM:r/m)
@@ -497,6 +553,8 @@ decode_rex(struct vie *vie)
return (-1);
if (x >= 0x40 && x <= 0x4F) {
+ vie->rex_present = 1;
+
vie->rex_w = x & 0x8 ? 1 : 0;
vie->rex_r = x & 0x4 ? 1 : 0;
vie->rex_x = x & 0x2 ? 1 : 0;
OpenPOWER on IntegriCloud