diff options
author | grehan <grehan@FreeBSD.org> | 2014-09-16 01:59:19 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2014-09-16 01:59:19 +0000 |
commit | 4f02bb3b6b1f0cd64fdf90db819bdf04b6e2045b (patch) | |
tree | d6be453ad650e29a2c501470dadbb2126ab9f5f3 | |
parent | 5a730084f5bed105f33ae57e87cd3bae9b61a8a2 (diff) | |
download | FreeBSD-src-4f02bb3b6b1f0cd64fdf90db819bdf04b6e2045b.zip FreeBSD-src-4f02bb3b6b1f0cd64fdf90db819bdf04b6e2045b.tar.gz |
MFC r270689:
Implement the 0x2B SUB instruction, and the OR variant of 0x81.
Found with local APIC accesses from bitrig/amd64 bsd.rd, 07/15-snap.
Approved by: re (rodrigc)
-rw-r--r-- | sys/amd64/vmm/vmm_instruction_emul.c | 104 |
1 files changed, 91 insertions, 13 deletions
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c index a65b125..09453a2 100644 --- a/sys/amd64/vmm/vmm_instruction_emul.c +++ b/sys/amd64/vmm/vmm_instruction_emul.c @@ -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; @@ -723,6 +741,62 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie, } 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, mem_region_write_t memwrite, void *arg) @@ -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; |