hv: instr_emul: check the bit 0(w bit) of opcode when necessary

Not every instruction supports the operand-size bit (w). This patch try to correct
what done in commit-id 9df8790 by setting a flag VIE_OP_F_BYTE_OP to indicate which
instruction supports the operand-size bit (w).

This bug is found by removing VMX_PROCBASED_CTLS2_VAPIC_REGS VMCS setting when the
physical doesn't support this APICv feature. However, if emulated this in MRB board,
the android can't boot because when switch to trusty world, it will check
"Delivery Status" in ICR first. It turns out that this Bit Test instruction is not
emulated correctly.

Tracked-On: #1337
Signed-off-by: Qi Yadong <yadong.qi@intel.com>
Signed-off-by: Li, Fei1 <fei1.li@intel.com>
Reviewed-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
Li, Fei1 2019-04-18 08:10:49 +08:00 committed by wenlingz
parent 7ccb44afda
commit 4fc2009770

View File

@ -89,10 +89,18 @@
#define VIE_OP_F_MOFFSET (1U << 2U) /* 16/32/64-bit immediate moffset */
#define VIE_OP_F_NO_MODRM (1U << 3U)
#define VIE_OP_F_CHECK_GVA_DI (1U << 4U) /* for movs, need to check DI */
/*
* The VIE_OP_F_BYTE_OP only set when the instruction support
* Encoding of Operand Size (w) Bit and the w bit of opcode is 0.
* according B.2 GENERAL-PURPOSE INSTRUCTION FORMATS AND ENCODINGS
* FOR NON-64-BIT MODES, Vol 2, Intel SDM.
*/
#define VIE_OP_F_BYTE_OP (1U << 5U) /* 8-bit operands. */
static const struct instr_emul_vie_op two_byte_opcodes[256] = {
[0xB6] = {
.op_type = VIE_OP_TYPE_MOVZX,
.op_flags = VIE_OP_F_BYTE_OP,
},
[0xB7] = {
.op_type = VIE_OP_TYPE_MOVZX,
@ -103,6 +111,7 @@ static const struct instr_emul_vie_op two_byte_opcodes[256] = {
},
[0xBE] = {
.op_type = VIE_OP_TYPE_MOVSX,
.op_flags = VIE_OP_F_BYTE_OP,
},
};
@ -121,12 +130,14 @@ static const struct instr_emul_vie_op one_byte_opcodes[256] = {
},
[0x88] = {
.op_type = VIE_OP_TYPE_MOV,
.op_flags = VIE_OP_F_BYTE_OP,
},
[0x89] = {
.op_type = VIE_OP_TYPE_MOV,
},
[0x8A] = {
.op_type = VIE_OP_TYPE_MOV,
.op_flags = VIE_OP_F_BYTE_OP,
},
[0x8B] = {
.op_type = VIE_OP_TYPE_MOV,
@ -141,15 +152,15 @@ static const struct instr_emul_vie_op one_byte_opcodes[256] = {
},
[0xA4] = {
.op_type = VIE_OP_TYPE_MOVS,
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_CHECK_GVA_DI
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_CHECK_GVA_DI | VIE_OP_F_BYTE_OP,
},
[0xA5] = {
.op_type = VIE_OP_TYPE_MOVS,
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_CHECK_GVA_DI
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_CHECK_GVA_DI,
},
[0xAA] = {
.op_type = VIE_OP_TYPE_STOS,
.op_flags = VIE_OP_F_NO_MODRM
.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_BYTE_OP,
},
[0xAB] = {
.op_type = VIE_OP_TYPE_STOS,
@ -158,7 +169,7 @@ static const struct instr_emul_vie_op one_byte_opcodes[256] = {
[0xC6] = {
/* XXX Group 11 extended opcode - not just MOV */
.op_type = VIE_OP_TYPE_MOV,
.op_flags = VIE_OP_F_IMM8,
.op_flags = VIE_OP_F_IMM8 | VIE_OP_F_BYTE_OP,
},
[0xC7] = {
.op_type = VIE_OP_TYPE_MOV,
@ -184,12 +195,14 @@ static const struct instr_emul_vie_op one_byte_opcodes[256] = {
},
[0x84] = {
.op_type = VIE_OP_TYPE_TEST,
.op_flags = VIE_OP_F_BYTE_OP,
},
[0x85] = {
.op_type = VIE_OP_TYPE_TEST,
},
[0x08] = {
.op_type = VIE_OP_TYPE_OR,
.op_flags = VIE_OP_F_BYTE_OP,
},
[0x09] = {
.op_type = VIE_OP_TYPE_OR,
@ -1892,8 +1905,10 @@ static int32_t decode_opcode(struct instr_emul_vie *vie)
* If w bit of opcode is 1, the operand size is decided
* by prefix and default operand size attribute (handled
* in decode_prefixes).
* The VIE_OP_F_BYTE_OP only set when the instruction support
* Encoding of Operand Size (w) Bit and the w bit of opcode is 0.
*/
if ((ret == 0) && ((vie->opcode & 0x1U) == 0U)) {
if ((ret == 0) && ((vie->op.op_flags & VIE_OP_F_BYTE_OP) != 0U)) {
vie->opsize = 1U;
}
}