Implement the 0x2B SUB instruction, and the OR variant of 0x81.
Found with local APIC accesses from bitrig/amd64 bsd.rd, 07/15-snap. Reviewed by: neel MFC after: 3 days
This commit is contained in:
parent
e404dc33e2
commit
fc3dde9099
@ -65,6 +65,7 @@ enum {
|
||||
VIE_OP_TYPE_MOVZX,
|
||||
VIE_OP_TYPE_AND,
|
||||
VIE_OP_TYPE_OR,
|
||||
VIE_OP_TYPE_SUB,
|
||||
VIE_OP_TYPE_TWO_BYTE,
|
||||
VIE_OP_TYPE_PUSH,
|
||||
VIE_OP_TYPE_CMP,
|
||||
@ -97,6 +98,10 @@ static const struct vie_op one_byte_opcodes[256] = {
|
||||
.op_byte = 0x0F,
|
||||
.op_type = VIE_OP_TYPE_TWO_BYTE
|
||||
},
|
||||
[0x2B] = {
|
||||
.op_byte = 0x2B,
|
||||
.op_type = VIE_OP_TYPE_SUB,
|
||||
},
|
||||
[0x3B] = {
|
||||
.op_byte = 0x3B,
|
||||
.op_type = VIE_OP_TYPE_CMP,
|
||||
@ -597,18 +602,16 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
break;
|
||||
case 0x81:
|
||||
/*
|
||||
* AND mem (ModRM:r/m) with immediate and store the
|
||||
* AND/OR mem (ModRM:r/m) with immediate and store the
|
||||
* result in mem.
|
||||
*
|
||||
* 81 /4 and r/m16, imm16
|
||||
* 81 /4 and r/m32, imm32
|
||||
* REX.W + 81 /4 and r/m64, imm32 sign-extended to 64
|
||||
* AND: i = 4
|
||||
* OR: i = 1
|
||||
* 81 /i op r/m16, imm16
|
||||
* 81 /i op r/m32, imm32
|
||||
* REX.W + 81 /i op r/m64, imm32 sign-extended to 64
|
||||
*
|
||||
* Currently, only the AND operation of the 0x81 opcode
|
||||
* is implemented (ModRM:reg = b100).
|
||||
*/
|
||||
if ((vie->reg & 7) != 4)
|
||||
break;
|
||||
|
||||
/* get the first operand */
|
||||
error = memread(vm, vcpuid, gpa, &val1, size, arg);
|
||||
@ -616,11 +619,26 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
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);
|
||||
* perform the operation with the pre-fetched immediate
|
||||
* operand and write the result
|
||||
*/
|
||||
switch (vie->reg & 7) {
|
||||
case 0x4:
|
||||
/* modrm:reg == b100, AND */
|
||||
val1 &= vie->immediate;
|
||||
break;
|
||||
case 0x1:
|
||||
/* modrm:reg == b001, OR */
|
||||
val1 |= vie->immediate;
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
|
||||
error = memwrite(vm, vcpuid, gpa, val1, size, arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -722,6 +740,62 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
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)
|
||||
{
|
||||
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 0x2B:
|
||||
/*
|
||||
* SUB r/m from r and store the result in r
|
||||
*
|
||||
* 2B/r SUB r16, r/m16
|
||||
* 2B/r SUB r32, r/m32
|
||||
* REX.W + 2B/r SUB 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 = getcc(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_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,
|
||||
struct vm_guest_paging *paging, mem_region_read_t memread,
|
||||
@ -865,6 +939,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
error = emulate_or(vm, vcpuid, gpa, vie,
|
||||
memread, memwrite, memarg);
|
||||
break;
|
||||
case VIE_OP_TYPE_SUB:
|
||||
error = emulate_sub(vm, vcpuid, gpa, vie,
|
||||
memread, memwrite, memarg);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user