Add support for emulation of the "or r/m, imm8" instruction.

Submitted by:	Zhixiang Yu (zxyu.core@gmail.com)
Obtained from:	GSoC 2013 (AHCI device emulation for bhyve)
This commit is contained in:
neel 2013-07-23 23:43:00 +00:00
parent f5ce18bd6e
commit 8a3e57621d

View File

@ -60,6 +60,7 @@ enum {
VIE_OP_TYPE_NONE = 0,
VIE_OP_TYPE_MOV,
VIE_OP_TYPE_AND,
VIE_OP_TYPE_OR,
VIE_OP_TYPE_LAST
};
@ -94,7 +95,13 @@ static const struct vie_op one_byte_opcodes[256] = {
.op_byte = 0x81,
.op_type = VIE_OP_TYPE_AND,
.op_flags = VIE_OP_F_IMM,
}
},
[0x83] = {
/* XXX Group 1 extended opcode - not just OR */
.op_byte = 0x83,
.op_type = VIE_OP_TYPE_OR,
.op_flags = VIE_OP_F_IMM8,
},
};
/* struct vie.mod */
@ -338,8 +345,8 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
break;
case 0x81:
/*
* AND reg (ModRM:reg) with immediate and store the
* result in reg
* AND mem (ModRM:r/m) with immediate and store the
* result in mem.
*
* 81/ and r/m32, imm32
* REX.W + 81/ and r/m64, imm32 sign-extended to 64
@ -371,6 +378,52 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
return (error);
}
static int
emulate_or(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 val1;
size = 4;
error = EINVAL;
switch (vie->op.op_byte) {
case 0x83:
/*
* OR mem (ModRM:r/m) with immediate and store the
* result in mem.
*
* 83/ OR r/m32, imm8 sign-extended to 32
* REX.W + 83/ OR r/m64, imm8 sign-extended to 64
*
* Currently, only the OR operation of the 0x83 opcode
* is implemented (ModRM:reg = b001).
*/
if ((vie->reg & 7) != 1)
break;
if (vie->rex_w)
size = 8;
/* get the first operand */
error = memread(vm, vcpuid, gpa, &val1, size, arg);
if (error)
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);
break;
default:
break;
}
return (error);
}
int
vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
mem_region_read_t memread, mem_region_write_t memwrite,
@ -390,6 +443,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
error = emulate_and(vm, vcpuid, gpa, vie,
memread, memwrite, memarg);
break;
case VIE_OP_TYPE_OR:
error = emulate_or(vm, vcpuid, gpa, vie,
memread, memwrite, memarg);
break;
default:
error = EINVAL;
break;