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
This commit is contained in:
Neel Natu 2013-01-30 04:09:09 +00:00
parent 663a6522a7
commit 8faceb3292
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246108
2 changed files with 60 additions and 1 deletions

View File

@ -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,

View File

@ -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,
@ -160,6 +164,46 @@ vie_read_register(void *vm, int vcpuid, enum vm_reg_name reg, uint64_t *rval)
return (error);
}
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;