Emulate the "ADD reg, r/m" instruction (opcode 03H).
OVMF's flash variable storage is using add instructions when indexing the variable store bootrom location. Submitted by: D Scott Phillips <d.scott.phillips@intel.com> Reviewed by: rgrimes MFC after: 1 week Sponsored by: Intel Corporation Differential Revision: https://reviews.freebsd.org/D19975
This commit is contained in:
parent
e28330c77b
commit
e24f761963
@ -77,6 +77,7 @@ enum {
|
||||
VIE_OP_TYPE_STOS,
|
||||
VIE_OP_TYPE_BITTEST,
|
||||
VIE_OP_TYPE_TWOB_GRP15,
|
||||
VIE_OP_TYPE_ADD,
|
||||
VIE_OP_TYPE_LAST
|
||||
};
|
||||
|
||||
@ -112,6 +113,10 @@ static const struct vie_op two_byte_opcodes[256] = {
|
||||
};
|
||||
|
||||
static const struct vie_op one_byte_opcodes[256] = {
|
||||
[0x03] = {
|
||||
.op_byte = 0x03,
|
||||
.op_type = VIE_OP_TYPE_ADD,
|
||||
},
|
||||
[0x0F] = {
|
||||
.op_byte = 0x0F,
|
||||
.op_type = VIE_OP_TYPE_TWO_BYTE
|
||||
@ -410,6 +415,41 @@ getcc(int opsize, uint64_t x, uint64_t y)
|
||||
return (getcc64(x, y));
|
||||
}
|
||||
|
||||
/*
|
||||
* Macro creation of functions getaddflags{8,16,32,64}
|
||||
*/
|
||||
#define GETADDFLAGS(sz) \
|
||||
static u_long \
|
||||
getaddflags##sz(uint##sz##_t x, uint##sz##_t y) \
|
||||
{ \
|
||||
u_long rflags; \
|
||||
\
|
||||
__asm __volatile("add %2,%1; pushfq; popq %0" : \
|
||||
"=r" (rflags), "+r" (x) : "m" (y)); \
|
||||
return (rflags); \
|
||||
} struct __hack
|
||||
|
||||
GETADDFLAGS(8);
|
||||
GETADDFLAGS(16);
|
||||
GETADDFLAGS(32);
|
||||
GETADDFLAGS(64);
|
||||
|
||||
static u_long
|
||||
getaddflags(int opsize, uint64_t x, uint64_t y)
|
||||
{
|
||||
KASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8,
|
||||
("getaddflags: invalid operand size %d", opsize));
|
||||
|
||||
if (opsize == 1)
|
||||
return (getaddflags8(x, y));
|
||||
else if (opsize == 2)
|
||||
return (getaddflags16(x, y));
|
||||
else if (opsize == 4)
|
||||
return (getaddflags32(x, y));
|
||||
else
|
||||
return (getaddflags64(x, y));
|
||||
}
|
||||
|
||||
static int
|
||||
emulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
|
||||
@ -1178,6 +1218,62 @@ emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
emulate_add(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 0x03:
|
||||
/*
|
||||
* ADD r/m to r and store the result in r
|
||||
*
|
||||
* 03/r ADD r16, r/m16
|
||||
* 03/r ADD r32, r/m32
|
||||
* REX.W + 03/r ADD 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 = getaddflags(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_sub(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
|
||||
@ -1543,6 +1639,10 @@ vmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
error = emulate_twob_group15(vm, vcpuid, gpa, vie,
|
||||
memread, memwrite, memarg);
|
||||
break;
|
||||
case VIE_OP_TYPE_ADD:
|
||||
error = emulate_add(vm, vcpuid, gpa, vie, memread,
|
||||
memwrite, memarg);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user