The "SUB" instruction used in getcc() actually does 'x -= y' so use the
proper constraint for 'x'. The "+r" constraint indicates that 'x' is an input and output register operand. While here generate code for different variants of getcc() using a macro GETCC(sz) where 'sz' indicates the operand size. Update the status bits in %rflags when emulating AND and OR opcodes. Reviewed by: grehan
This commit is contained in:
parent
1bffa9511f
commit
4c98655ece
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=270857
@ -316,46 +316,36 @@ vie_update_register(void *vm, int vcpuid, enum vm_reg_name reg,
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define RFLAGS_STATUS_BITS (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_V)
|
||||
|
||||
/*
|
||||
* Return the status flags that would result from doing (x - y).
|
||||
*/
|
||||
static u_long
|
||||
getcc16(uint16_t x, uint16_t y)
|
||||
{
|
||||
u_long rflags;
|
||||
#define GETCC(sz) \
|
||||
static u_long \
|
||||
getcc##sz(uint##sz##_t x, uint##sz##_t y) \
|
||||
{ \
|
||||
u_long rflags; \
|
||||
\
|
||||
__asm __volatile("sub %2,%1; pushfq; popq %0" : \
|
||||
"=r" (rflags), "+r" (x) : "m" (y)); \
|
||||
return (rflags); \
|
||||
} struct __hack
|
||||
|
||||
__asm __volatile("sub %1,%2; pushfq; popq %0" :
|
||||
"=r" (rflags) : "m" (y), "r" (x));
|
||||
return (rflags);
|
||||
}
|
||||
|
||||
static u_long
|
||||
getcc32(uint32_t x, uint32_t y)
|
||||
{
|
||||
u_long rflags;
|
||||
|
||||
__asm __volatile("sub %1,%2; pushfq; popq %0" :
|
||||
"=r" (rflags) : "m" (y), "r" (x));
|
||||
return (rflags);
|
||||
}
|
||||
|
||||
static u_long
|
||||
getcc64(uint64_t x, uint64_t y)
|
||||
{
|
||||
u_long rflags;
|
||||
|
||||
__asm __volatile("sub %1,%2; pushfq; popq %0" :
|
||||
"=r" (rflags) : "m" (y), "r" (x));
|
||||
return (rflags);
|
||||
}
|
||||
GETCC(8);
|
||||
GETCC(16);
|
||||
GETCC(32);
|
||||
GETCC(64);
|
||||
|
||||
static u_long
|
||||
getcc(int opsize, uint64_t x, uint64_t y)
|
||||
{
|
||||
KASSERT(opsize == 2 || opsize == 4 || opsize == 8,
|
||||
KASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8,
|
||||
("getcc: invalid operand size %d", opsize));
|
||||
|
||||
if (opsize == 2)
|
||||
if (opsize == 1)
|
||||
return (getcc8(x, y));
|
||||
else if (opsize == 2)
|
||||
return (getcc16(x, y));
|
||||
else if (opsize == 4)
|
||||
return (getcc32(x, y));
|
||||
@ -569,7 +559,7 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
{
|
||||
int error, size;
|
||||
enum vm_reg_name reg;
|
||||
uint64_t val1, val2;
|
||||
uint64_t result, rflags, rflags2, val1, val2;
|
||||
|
||||
size = vie->opsize;
|
||||
error = EINVAL;
|
||||
@ -597,8 +587,8 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
break;
|
||||
|
||||
/* perform the operation and write the result */
|
||||
val1 &= val2;
|
||||
error = vie_update_register(vm, vcpuid, reg, val1, size);
|
||||
result = val1 & val2;
|
||||
error = vie_update_register(vm, vcpuid, reg, result, size);
|
||||
break;
|
||||
case 0x81:
|
||||
/*
|
||||
@ -625,11 +615,11 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
switch (vie->reg & 7) {
|
||||
case 0x4:
|
||||
/* modrm:reg == b100, AND */
|
||||
val1 &= vie->immediate;
|
||||
result = val1 & vie->immediate;
|
||||
break;
|
||||
case 0x1:
|
||||
/* modrm:reg == b001, OR */
|
||||
val1 |= vie->immediate;
|
||||
result = val1 | vie->immediate;
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
@ -638,11 +628,29 @@ emulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
if (error)
|
||||
break;
|
||||
|
||||
error = memwrite(vm, vcpuid, gpa, val1, size, arg);
|
||||
error = memwrite(vm, vcpuid, gpa, result, size, arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* OF and CF are cleared; the SF, ZF and PF flags are set according
|
||||
* to the result; AF is undefined.
|
||||
*
|
||||
* The updated status flags are obtained by subtracting 0 from 'result'.
|
||||
*/
|
||||
rflags2 = getcc(size, result, 0);
|
||||
rflags &= ~RFLAGS_STATUS_BITS;
|
||||
rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N);
|
||||
|
||||
error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -651,7 +659,7 @@ 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;
|
||||
uint64_t val1, result, rflags, rflags2;
|
||||
|
||||
size = vie->opsize;
|
||||
error = EINVAL;
|
||||
@ -681,17 +689,33 @@ emulate_or(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
* perform the operation with the pre-fetched immediate
|
||||
* operand and write the result
|
||||
*/
|
||||
val1 |= vie->immediate;
|
||||
error = memwrite(vm, vcpuid, gpa, val1, size, arg);
|
||||
result = val1 | vie->immediate;
|
||||
error = memwrite(vm, vcpuid, gpa, result, size, arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* OF and CF are cleared; the SF, ZF and PF flags are set according
|
||||
* to the result; AF is undefined.
|
||||
*
|
||||
* The updated status flags are obtained by subtracting 0 from 'result'.
|
||||
*/
|
||||
rflags2 = getcc(size, result, 0);
|
||||
rflags &= ~RFLAGS_STATUS_BITS;
|
||||
rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N);
|
||||
|
||||
error = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define RFLAGS_STATUS_BITS (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_V)
|
||||
|
||||
static int
|
||||
emulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,
|
||||
mem_region_read_t memread, mem_region_write_t memwrite, void *arg)
|
||||
|
Loading…
Reference in New Issue
Block a user