hv: inst_emul: clean the "Procedure has more than one exit point"

Misra C requires Function must have only 1 return entry.

Tracked-On: #861
Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
Li, Fei1 2019-01-09 07:47:35 +08:00 committed by acrnsi
parent 5c24f8bb66
commit 40c5139ea3

View File

@ -426,38 +426,40 @@ static void get_guest_paging_info(struct acrn_vcpu *vcpu, struct instr_emul_ctxt
static int32_t vie_canonical_check(enum vm_cpu_mode cpu_mode, uint64_t gla) static int32_t vie_canonical_check(enum vm_cpu_mode cpu_mode, uint64_t gla)
{ {
int32_t ret = 0;
uint64_t mask; uint64_t mask;
if (cpu_mode != CPU_MODE_64BIT) { if (cpu_mode == CPU_MODE_64BIT) {
return 0;
}
/* /*
* The value of the bit 47 in the 'gla' should be replicated in the * The value of the bit 47 in the 'gla' should be replicated in the
* most significant 16 bits. * most significant 16 bits.
*/ */
mask = ~((1UL << 48U) - 1UL); mask = ~((1UL << 48U) - 1UL);
if ((gla & (1UL << 47U)) != 0U) { if ((gla & (1UL << 47U)) != 0U) {
return ((gla & mask) != mask) ? 1 : 0; ret = ((gla & mask) != mask) ? 1 : 0;
} else { } else {
return ((gla & mask) != 0U) ? 1 : 0; ret = ((gla & mask) != 0U) ? 1 : 0;
} }
}
return ret;
} }
static bool is_desc_valid(struct seg_desc *desc, uint32_t prot) static bool is_desc_valid(struct seg_desc *desc, uint32_t prot)
{ {
bool ret = true;
uint32_t type; uint32_t type;
/* The descriptor type must indicate a code/data segment. */ /* The descriptor type must indicate a code/data segment. */
type = seg_desc_type(desc->access); type = seg_desc_type(desc->access);
if (type < 16U || type > 31U) {
return false;
}
if (type < 16U) {
ret = false;
} else {
if ((prot & PROT_READ) != 0U) { if ((prot & PROT_READ) != 0U) {
/* #GP on a read access to a exec-only code segment */ /* #GP on a read access to a exec-only code segment */
if ((type & 0xAU) == 0x8U) { if ((type & 0xAU) == 0x8U) {
return false; ret = false;
} }
} }
@ -467,15 +469,16 @@ static bool is_desc_valid(struct seg_desc *desc, uint32_t prot)
* read-only data segment. * read-only data segment.
*/ */
if ((type & 0x8U) != 0U) { /* code segment */ if ((type & 0x8U) != 0U) { /* code segment */
return false; ret = false;
} }
if ((type & 0xAU) == 0U) { /* read-only data seg */ if ((type & 0xAU) == 0U) { /* read-only data seg */
return false; ret = false;
}
} }
} }
return true; return ret;
} }
/* /*
@ -673,16 +676,23 @@ build_getcc(getcc64, uint64_t)
*/ */
static uint64_t getcc(uint8_t opsize, uint64_t x, uint64_t y) static uint64_t getcc(uint8_t opsize, uint64_t x, uint64_t y)
{ {
uint64_t rflags;
switch (opsize) { switch (opsize) {
case 1U: case 1U:
return getcc8((uint8_t) x, (uint8_t) y); rflags = getcc8((uint8_t) x, (uint8_t) y);
break;
case 2U: case 2U:
return getcc16((uint16_t) x, (uint16_t) y); rflags = getcc16((uint16_t) x, (uint16_t) y);
break;
case 4U: case 4U:
return getcc32((uint32_t) x, (uint32_t) y); rflags = getcc32((uint32_t) x, (uint32_t) y);
break;
default: /* opsize == 8 */ default: /* opsize == 8 */
return getcc64(x, y); rflags = getcc64(x, y);
break;
} }
return rflags;
} }
static int32_t emulate_mov(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie) static int32_t emulate_mov(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie)
@ -918,7 +928,7 @@ static void get_gva_si_nocheck(const struct acrn_vcpu *vcpu, uint8_t addrsize,
static int32_t get_gva_di_check(struct acrn_vcpu *vcpu, struct instr_emul_vie *vie, static int32_t get_gva_di_check(struct acrn_vcpu *vcpu, struct instr_emul_vie *vie,
uint8_t addrsize, uint64_t *gva) uint8_t addrsize, uint64_t *gva)
{ {
int32_t ret = 0; int32_t ret = -EFAULT;
uint32_t err_code; uint32_t err_code;
struct seg_desc desc; struct seg_desc desc;
enum vm_cpu_mode cpu_mode; enum vm_cpu_mode cpu_mode;
@ -935,10 +945,12 @@ static int32_t get_gva_di_check(struct acrn_vcpu *vcpu, struct instr_emul_vie *v
} else { } else {
if ((addrsize != 2U) && (addrsize != 4U)) { if ((addrsize != 2U) && (addrsize != 4U)) {
has_exception = true; has_exception = true;
} else if (!is_desc_valid(&desc, PROT_WRITE)) { } else {
if (!is_desc_valid(&desc, PROT_WRITE)) {
has_exception = true; has_exception = true;
} }
} }
}
if (!has_exception) { if (!has_exception) {
val = vm_get_register(vcpu, CPU_REG_RDI); val = vm_get_register(vcpu, CPU_REG_RDI);
@ -954,18 +966,21 @@ static int32_t get_gva_di_check(struct acrn_vcpu *vcpu, struct instr_emul_vie *v
vcpu_inject_pf(vcpu, (uint64_t)gva, err_code); vcpu_inject_pf(vcpu, (uint64_t)gva, err_code);
} }
} else { } else {
/* If we are checking the dest operand for movs instruction, /* If we are checking the dest operand for movs instruction,
* we cache the gpa if check pass. It will be used during * we cache the gpa if check pass. It will be used during
* movs instruction emulation. * movs instruction emulation.
*/ */
vie->dst_gpa = gpa; vie->dst_gpa = gpa;
ret = 0;
} }
} }
} }
if (has_exception) { if (has_exception) {
vcpu_inject_gp(vcpu, 0U); vcpu_inject_gp(vcpu, 0U);
ret = -EFAULT;
} }
return ret; return ret;
@ -1071,9 +1086,10 @@ done:
static int32_t emulate_stos(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie) static int32_t emulate_stos(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie)
{ {
bool done = false;
uint8_t repeat, opsize = vie->opsize; uint8_t repeat, opsize = vie->opsize;
uint64_t val; uint64_t val;
uint64_t rcx, rdi, rflags; uint64_t rcx = 0U, rdi, rflags;
repeat = vie->repz_present | vie->repnz_present; repeat = vie->repz_present | vie->repnz_present;
@ -1085,10 +1101,11 @@ static int32_t emulate_stos(struct acrn_vcpu *vcpu, const struct instr_emul_vie
* address size of the instruction. * address size of the instruction.
*/ */
if ((rcx & size2mask[vie->addrsize]) == 0UL) { if ((rcx & size2mask[vie->addrsize]) == 0UL) {
return 0; done = true;
} }
} }
if (!done) {
val = vm_get_register(vcpu, CPU_REG_RAX); val = vm_get_register(vcpu, CPU_REG_RAX);
vie_mmio_write(vcpu, val); vie_mmio_write(vcpu, val);
@ -1115,6 +1132,7 @@ static int32_t emulate_stos(struct acrn_vcpu *vcpu, const struct instr_emul_vie
vcpu_retain_rip(vcpu); vcpu_retain_rip(vcpu);
} }
} }
}
return 0; return 0;
} }
@ -1354,7 +1372,7 @@ static int32_t emulate_or(struct acrn_vcpu *vcpu, const struct instr_emul_vie *v
static int32_t emulate_cmp(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie) static int32_t emulate_cmp(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie)
{ {
int32_t error = 0; int32_t ret = 0;
uint8_t size; uint8_t size;
uint64_t regop, memop, op1, op2, rflags2; uint64_t regop, memop, op1, op2, rflags2;
enum cpu_reg_name reg; enum cpu_reg_name reg;
@ -1392,7 +1410,6 @@ static int32_t emulate_cmp(struct acrn_vcpu *vcpu, const struct instr_emul_vie *
op1 = memop; op1 = memop;
op2 = regop; op2 = regop;
} }
rflags2 = getcc(size, op1, op2);
break; break;
case 0x80U: case 0x80U:
case 0x81U: case 0x81U:
@ -1426,16 +1443,18 @@ static int32_t emulate_cmp(struct acrn_vcpu *vcpu, const struct instr_emul_vie *
/* get the first operand */ /* get the first operand */
vie_mmio_read(vcpu, &op1); vie_mmio_read(vcpu, &op1);
op2 = (uint64_t)vie->immediate;
rflags2 = getcc(size, op1, (uint64_t)vie->immediate);
break; break;
default: default:
return -EINVAL; ret = -EINVAL;
break;
} }
if (ret == 0) {
rflags2 = getcc(size, op1, op2);
vie_update_rflags(vcpu, rflags2, RFLAGS_STATUS_BITS); vie_update_rflags(vcpu, rflags2, RFLAGS_STATUS_BITS);
}
return error; return ret;
} }
static int32_t emulate_sub(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie) static int32_t emulate_sub(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie)
@ -1613,11 +1632,9 @@ static int32_t vie_init(struct instr_emul_vie *vie, struct acrn_vcpu *vcpu)
int32_t ret; int32_t ret;
if ((inst_len > VIE_INST_SIZE) || (inst_len == 0U)) { if ((inst_len > VIE_INST_SIZE) || (inst_len == 0U)) {
pr_err("%s: invalid instruction length (%d)", pr_err("%s: invalid instruction length (%d)", __func__, inst_len);
__func__, inst_len); ret = -EINVAL;
return -EINVAL; } else {
}
(void)memset(vie, 0U, sizeof(struct instr_emul_vie)); (void)memset(vie, 0U, sizeof(struct instr_emul_vie));
/* init register fields in vie. */ /* init register fields in vie. */
@ -1626,29 +1643,30 @@ static int32_t vie_init(struct instr_emul_vie *vie, struct acrn_vcpu *vcpu)
vie->segment_register = CPU_REG_LAST; vie->segment_register = CPU_REG_LAST;
err_code = PAGE_FAULT_ID_FLAG; err_code = PAGE_FAULT_ID_FLAG;
ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva, ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva, inst_len, &err_code, &fault_addr);
inst_len, &err_code, &fault_addr);
if (ret < 0) { if (ret < 0) {
if (ret == -EFAULT) { if (ret == -EFAULT) {
vcpu_inject_pf(vcpu, fault_addr, err_code); vcpu_inject_pf(vcpu, fault_addr, err_code);
} }
return ret; } else {
vie->num_valid = (uint8_t)inst_len;
ret = 0;
}
} }
vie->num_valid = (uint8_t)inst_len; return ret;
return 0;
} }
static int32_t vie_peek(const struct instr_emul_vie *vie, uint8_t *x) static int32_t vie_peek(const struct instr_emul_vie *vie, uint8_t *x)
{ {
int32_t ret;
if (vie->num_processed < vie->num_valid) { if (vie->num_processed < vie->num_valid) {
*x = vie->inst[vie->num_processed]; *x = vie->inst[vie->num_processed];
return 0; ret = 0;
} else { } else {
return -1; ret = -1;
} }
return ret;
} }
static void vie_advance(struct instr_emul_vie *vie) static void vie_advance(struct instr_emul_vie *vie)
@ -1659,7 +1677,7 @@ static void vie_advance(struct instr_emul_vie *vie)
static bool segment_override(uint8_t x, enum cpu_reg_name *seg) static bool segment_override(uint8_t x, enum cpu_reg_name *seg)
{ {
bool override = true;
switch (x) { switch (x) {
case 0x2EU: case 0x2EU:
*seg = CPU_REG_CS; *seg = CPU_REG_CS;
@ -1680,9 +1698,10 @@ static bool segment_override(uint8_t x, enum cpu_reg_name *seg)
*seg = CPU_REG_GS; *seg = CPU_REG_GS;
break; break;
default: default:
return false; override = false;
break;
} }
return true; return override;
} }
static int32_t decode_prefixes(struct instr_emul_vie *vie, static int32_t decode_prefixes(struct instr_emul_vie *vie,
@ -1759,22 +1778,23 @@ static int32_t decode_prefixes(struct instr_emul_vie *vie,
static int32_t decode_two_byte_opcode(struct instr_emul_vie *vie) static int32_t decode_two_byte_opcode(struct instr_emul_vie *vie)
{ {
int32_t ret = 0;
uint8_t x; uint8_t x;
if (vie_peek(vie, &x) != 0) { if (vie_peek(vie, &x) != 0) {
return -1; ret = -1;
} } else {
vie->opcode = x; vie->opcode = x;
vie->op = two_byte_opcodes[x]; vie->op = two_byte_opcodes[x];
if (vie->op.op_type == VIE_OP_TYPE_NONE) { if (vie->op.op_type == VIE_OP_TYPE_NONE) {
return -1; ret = -1;
} else {
vie_advance(vie);
}
} }
vie_advance(vie); return ret;
return 0;
} }
static int32_t decode_opcode(struct instr_emul_vie *vie) static int32_t decode_opcode(struct instr_emul_vie *vie)
@ -1783,16 +1803,14 @@ static int32_t decode_opcode(struct instr_emul_vie *vie)
uint8_t x; uint8_t x;
if (vie_peek(vie, &x) != 0) { if (vie_peek(vie, &x) != 0) {
return -1; ret = -1;
} } else {
vie->opcode = x; vie->opcode = x;
vie->op = one_byte_opcodes[x]; vie->op = one_byte_opcodes[x];
if (vie->op.op_type == VIE_OP_TYPE_NONE) { if (vie->op.op_type == VIE_OP_TYPE_NONE) {
return -1; ret = -1;
} } else {
vie_advance(vie); vie_advance(vie);
if (vie->op.op_type == VIE_OP_TYPE_TWO_BYTE) { if (vie->op.op_type == VIE_OP_TYPE_TWO_BYTE) {
@ -1808,6 +1826,8 @@ static int32_t decode_opcode(struct instr_emul_vie *vie)
if ((ret == 0) && ((vie->opcode & 0x1U) == 0U)) { if ((ret == 0) && ((vie->opcode & 0x1U) == 0U)) {
vie->opsize = 1U; vie->opsize = 1U;
} }
}
}
return ret; return ret;
} }
@ -1815,19 +1835,15 @@ static int32_t decode_opcode(struct instr_emul_vie *vie)
static int32_t decode_modrm(struct instr_emul_vie *vie, enum vm_cpu_mode cpu_mode) static int32_t decode_modrm(struct instr_emul_vie *vie, enum vm_cpu_mode cpu_mode)
{ {
uint8_t x; uint8_t x;
int32_t ret;
if ((vie->op.op_flags & VIE_OP_F_NO_MODRM) != 0U) { if ((vie->op.op_flags & VIE_OP_F_NO_MODRM) != 0U) {
return 0; ret = 0;
} } else if (cpu_mode == CPU_MODE_REAL) {
ret = -1;
if (cpu_mode == CPU_MODE_REAL) { } else if (vie_peek(vie, &x) != 0) {
return -1; ret = -1;
} } else {
if (vie_peek(vie, &x) != 0) {
return -1;
}
vie->mod = (x >> 6U) & 0x3U; vie->mod = (x >> 6U) & 0x3U;
vie->rm = (x >> 0U) & 0x7U; vie->rm = (x >> 0U) & 0x7U;
vie->reg = (x >> 3U) & 0x7U; vie->reg = (x >> 3U) & 0x7U;
@ -1838,9 +1854,8 @@ static int32_t decode_modrm(struct instr_emul_vie *vie, enum vm_cpu_mode cpu_mod
* EPT fault. * EPT fault.
*/ */
if (vie->mod == VIE_MOD_DIRECT) { if (vie->mod == VIE_MOD_DIRECT) {
return -1; ret = -1;
} } else {
if (((vie->mod == VIE_MOD_INDIRECT) && (vie->rm == VIE_RM_DISP32)) || if (((vie->mod == VIE_MOD_INDIRECT) && (vie->rm == VIE_RM_DISP32)) ||
((vie->mod != VIE_MOD_DIRECT) && (vie->rm == VIE_RM_SIB))) { ((vie->mod != VIE_MOD_DIRECT) && (vie->rm == VIE_RM_SIB))) {
/* /*
@ -1862,10 +1877,9 @@ static int32_t decode_modrm(struct instr_emul_vie *vie, enum vm_cpu_mode cpu_mod
vie->reg |= (vie->rex_r << 3U); vie->reg |= (vie->rex_r << 3U);
/* SIB */ /* SIB */
if (vie->mod != VIE_MOD_DIRECT && vie->rm == VIE_RM_SIB) { if ((vie->mod != VIE_MOD_DIRECT) && (vie->rm == VIE_RM_SIB)) {
goto done; /* done */
} } else {
vie->base_register = (enum cpu_reg_name)vie->rm; vie->base_register = (enum cpu_reg_name)vie->rm;
switch (vie->mod) { switch (vie->mod) {
@ -1899,24 +1913,27 @@ static int32_t decode_modrm(struct instr_emul_vie *vie, enum vm_cpu_mode cpu_mod
break; break;
} }
done: }
vie_advance(vie); vie_advance(vie);
return 0; ret = 0;
}
}
return ret;
} }
static int32_t decode_sib(struct instr_emul_vie *vie) static int32_t decode_sib(struct instr_emul_vie *vie)
{ {
uint8_t x; uint8_t x;
int32_t ret;
/* Proceed only if SIB byte is present */ /* Proceed only if SIB byte is present */
if ((vie->mod == VIE_MOD_DIRECT) || (vie->rm != VIE_RM_SIB)) { if ((vie->mod == VIE_MOD_DIRECT) || (vie->rm != VIE_RM_SIB)) {
return 0; ret = 0;
} } else if (vie_peek(vie, &x) != 0) {
ret = -1;
if (vie_peek(vie, &x) != 0) { } else {
return -1;
}
/* De-construct the SIB byte */ /* De-construct the SIB byte */
vie->ss = (x >> 6U) & 0x3U; vie->ss = (x >> 6U) & 0x3U;
@ -1949,8 +1966,7 @@ static int32_t decode_sib(struct instr_emul_vie *vie)
break; break;
} }
if ((vie->mod == VIE_MOD_INDIRECT) && if ((vie->mod == VIE_MOD_INDIRECT) && ((vie->base == 5U) || (vie->base == 13U))) {
((vie->base == 5U) || (vie->base == 13U))) {
/* /*
* Special case when base register is unused if mod = 0 * Special case when base register is unused if mod = 0
* and base = %rbp or %r13. * and base = %rbp or %r13.
@ -1982,12 +1998,16 @@ static int32_t decode_sib(struct instr_emul_vie *vie)
vie_advance(vie); vie_advance(vie);
return 0; ret = 0;
}
return ret;
} }
static int32_t decode_displacement(struct instr_emul_vie *vie) static int32_t decode_displacement(struct instr_emul_vie *vie)
{ {
uint8_t n, i, x; uint8_t n, i, x;
int32_t ret = 0;
union { union {
uint8_t buf[4]; uint8_t buf[4];
@ -1996,37 +2016,39 @@ static int32_t decode_displacement(struct instr_emul_vie *vie)
} u; } u;
n = vie->disp_bytes; n = vie->disp_bytes;
if (n == 0U) { if (n != 0U) {
return 0;
}
if ((n != 1U) && (n != 4U)) { if ((n != 1U) && (n != 4U)) {
pr_err("%s: decode_displacement: invalid disp_bytes %d", pr_err("%s: decode_displacement: invalid disp_bytes %d", __func__, n);
__func__, n); ret = -EINVAL;
return -EINVAL; } else {
}
for (i = 0U; i < n; i++) { for (i = 0U; i < n; i++) {
if (vie_peek(vie, &x) != 0) { if (vie_peek(vie, &x) != 0) {
return -1; ret = -1;
break;
} }
u.buf[i] = x; u.buf[i] = x;
vie_advance(vie); vie_advance(vie);
} }
if (ret == 0) {
if (n == 1U) { if (n == 1U) {
vie->displacement = u.signed8; /* sign-extended */ vie->displacement = u.signed8; /* sign-extended */
} else { } else {
vie->displacement = u.signed32; /* sign-extended */ vie->displacement = u.signed32; /* sign-extended */
} }
}
}
}
return 0; return ret;
} }
static int32_t decode_immediate(struct instr_emul_vie *vie) static int32_t decode_immediate(struct instr_emul_vie *vie)
{ {
uint8_t i, n, x; uint8_t i, n, x;
int32_t ret = 0;
union { union {
uint8_t buf[4]; uint8_t buf[4];
int8_t signed8; int8_t signed8;
@ -2056,25 +2078,22 @@ static int32_t decode_immediate(struct instr_emul_vie *vie)
} }
n = vie->imm_bytes; n = vie->imm_bytes;
if (n == 0U) { if (n != 0U) {
return 0;
}
if ((n != 1U) && (n != 2U) && (n != 4U)) { if ((n != 1U) && (n != 2U) && (n != 4U)) {
pr_err("%s: invalid number of immediate bytes: %d", pr_err("%s: invalid number of immediate bytes: %d", __func__, n);
__func__, n); ret = -EINVAL;
return -EINVAL; } else {
}
for (i = 0U; i < n; i++) { for (i = 0U; i < n; i++) {
if (vie_peek(vie, &x) != 0) { if (vie_peek(vie, &x) != 0) {
return -1; ret = -1;
break;
} }
u.buf[i] = x; u.buf[i] = x;
vie_advance(vie); vie_advance(vie);
} }
if (ret == 0) {
/* sign-extend the immediate value before use */ /* sign-extend the immediate value before use */
if (n == 1U) { if (n == 1U) {
vie->immediate = u.signed8; vie->immediate = u.signed8;
@ -2083,22 +2102,23 @@ static int32_t decode_immediate(struct instr_emul_vie *vie)
} else { } else {
vie->immediate = u.signed32; vie->immediate = u.signed32;
} }
}
}
}
return 0; return ret;
} }
static int32_t decode_moffset(struct instr_emul_vie *vie) static int32_t decode_moffset(struct instr_emul_vie *vie)
{ {
uint8_t i, n, x; uint8_t i, n, x;
int32_t ret = 0;
union { union {
uint8_t buf[8]; uint8_t buf[8];
uint64_t u64; uint64_t u64;
} u; } u;
if ((vie->op.op_flags & VIE_OP_F_MOFFSET) == 0U) { if ((vie->op.op_flags & VIE_OP_F_MOFFSET) != 0U) {
return 0;
}
/* /*
* Section 2.2.1.4, "Direct Memory-Offset MOVs", Intel SDM: * Section 2.2.1.4, "Direct Memory-Offset MOVs", Intel SDM:
* The memory offset size follows the address-size of the instruction. * The memory offset size follows the address-size of the instruction.
@ -2106,56 +2126,52 @@ static int32_t decode_moffset(struct instr_emul_vie *vie)
n = vie->addrsize; n = vie->addrsize;
if ((n != 2U) && (n != 4U) && (n != 8U)) { if ((n != 2U) && (n != 4U) && (n != 8U)) {
pr_err("%s: invalid moffset bytes: %hhu", __func__, n); pr_err("%s: invalid moffset bytes: %hhu", __func__, n);
return -EINVAL; ret = -EINVAL;
} } else {
u.u64 = 0UL; u.u64 = 0UL;
for (i = 0U; i < n; i++) { for (i = 0U; i < n; i++) {
if (vie_peek(vie, &x) != 0) { if (vie_peek(vie, &x) != 0) {
return -1; ret = -1;
break;
} }
u.buf[i] = x; u.buf[i] = x;
vie_advance(vie); vie_advance(vie);
} }
if (ret == 0) {
vie->displacement = (int64_t)u.u64; vie->displacement = (int64_t)u.u64;
return 0; }
}
}
return ret;
} }
static int32_t local_decode_instruction(enum vm_cpu_mode cpu_mode, static int32_t local_decode_instruction(enum vm_cpu_mode cpu_mode,
bool cs_d, struct instr_emul_vie *vie) bool cs_d, struct instr_emul_vie *vie)
{ {
int32_t ret;
if (decode_prefixes(vie, cpu_mode, cs_d) != 0) { if (decode_prefixes(vie, cpu_mode, cs_d) != 0) {
return -1; ret = -1;
} } else if (decode_opcode(vie) != 0) {
ret = -1;
if (decode_opcode(vie) != 0) { } else if (decode_modrm(vie, cpu_mode) != 0) {
return -1; ret = -1;
} } else if (decode_sib(vie) != 0) {
ret = -1;
if (decode_modrm(vie, cpu_mode) != 0) { } else if (decode_displacement(vie) != 0) {
return -1; ret = -1;
} } else if (decode_immediate(vie) != 0) {
ret = -1;
if (decode_sib(vie) != 0) { } else if (decode_moffset(vie) != 0) {
return -1; ret = -1;
} } else {
if (decode_displacement(vie) != 0) {
return -1;
}
if (decode_immediate(vie) != 0) {
return -1;
}
if (decode_moffset(vie) != 0) {
return -1;
}
vie->decoded = 1U; /* success */ vie->decoded = 1U; /* success */
ret = 0;
}
return 0; return ret;
} }
/* for instruction MOVS/STO, check the gva gotten from DI/SI. */ /* for instruction MOVS/STO, check the gva gotten from DI/SI. */
@ -2179,7 +2195,7 @@ static int32_t instr_check_di(struct acrn_vcpu *vcpu, struct instr_emul_ctxt *em
static int32_t instr_check_gva(struct acrn_vcpu *vcpu, struct instr_emul_ctxt *emul_ctxt, static int32_t instr_check_gva(struct acrn_vcpu *vcpu, struct instr_emul_ctxt *emul_ctxt,
enum vm_cpu_mode cpu_mode) enum vm_cpu_mode cpu_mode)
{ {
int32_t ret; int32_t ret = 0;
uint64_t base, segbase, idx, gva, gpa; uint64_t base, segbase, idx, gva, gpa;
uint32_t err_code; uint32_t err_code;
enum cpu_reg_name seg; enum cpu_reg_name seg;
@ -2244,22 +2260,21 @@ static int32_t instr_check_gva(struct acrn_vcpu *vcpu, struct instr_emul_ctxt *e
} else { } else {
vcpu_inject_gp(vcpu, 0U); vcpu_inject_gp(vcpu, 0U);
} }
return -EFAULT; ret = -EFAULT;
} } else {
err_code = (vcpu->req.reqs.mmio.direction == REQUEST_WRITE) ? PAGE_FAULT_WR_FLAG : 0U;
err_code = (vcpu->req.reqs.mmio.direction == REQUEST_WRITE) ?
PAGE_FAULT_WR_FLAG : 0U;
ret = gva2gpa(vcpu, gva, &gpa, &err_code); ret = gva2gpa(vcpu, gva, &gpa, &err_code);
if (ret < 0) { if (ret < 0) {
if (ret == -EFAULT) { if (ret == -EFAULT) {
vcpu_inject_pf(vcpu, gva, vcpu_inject_pf(vcpu, gva, err_code);
err_code); }
} else {
ret = 0;
} }
return ret;
} }
return 0; return ret;
} }
int32_t decode_instruction(struct acrn_vcpu *vcpu) int32_t decode_instruction(struct acrn_vcpu *vcpu)
@ -2272,33 +2287,28 @@ int32_t decode_instruction(struct acrn_vcpu *vcpu)
emul_ctxt = &per_cpu(g_inst_ctxt, vcpu->pcpu_id); emul_ctxt = &per_cpu(g_inst_ctxt, vcpu->pcpu_id);
if (emul_ctxt == NULL) { if (emul_ctxt == NULL) {
pr_err("%s: Failed to get emul_ctxt", __func__); pr_err("%s: Failed to get emul_ctxt", __func__);
return -1; retval = -1;
} } else {
emul_ctxt->vcpu = vcpu; emul_ctxt->vcpu = vcpu;
retval = vie_init(&emul_ctxt->vie, vcpu); retval = vie_init(&emul_ctxt->vie, vcpu);
if (retval < 0) { if (retval < 0) {
if (retval != -EFAULT) { if (retval != -EFAULT) {
pr_err("init vie failed @ 0x%016llx:", pr_err("init vie failed @ 0x%016llx:", vcpu_get_rip(vcpu));
vcpu_get_rip(vcpu));
}
return retval;
} }
} else {
csar = exec_vmread32(VMX_GUEST_CS_ATTR); csar = exec_vmread32(VMX_GUEST_CS_ATTR);
get_guest_paging_info(vcpu, emul_ctxt, csar); get_guest_paging_info(vcpu, emul_ctxt, csar);
cpu_mode = get_vcpu_mode(vcpu); cpu_mode = get_vcpu_mode(vcpu);
retval = local_decode_instruction(cpu_mode, seg_desc_def32(csar), retval = local_decode_instruction(cpu_mode, seg_desc_def32(csar), &emul_ctxt->vie);
&emul_ctxt->vie);
if (retval != 0) { if (retval != 0) {
pr_err("decode instruction failed @ 0x%016llx:", pr_err("decode instruction failed @ 0x%016llx:", vcpu_get_rip(vcpu));
vcpu_get_rip(vcpu));
vcpu_inject_ud(vcpu); vcpu_inject_ud(vcpu);
return -EFAULT; retval = -EFAULT;
} } else {
/* /*
* We do operand check in instruction decode phase and * We do operand check in instruction decode phase and
* inject exception accordingly. In late instruction * inject exception accordingly. In late instruction
@ -2312,17 +2322,18 @@ int32_t decode_instruction(struct acrn_vcpu *vcpu)
*/ */
if ((emul_ctxt->vie.op.op_flags & VIE_OP_F_CHECK_GVA_DI) != 0U) { if ((emul_ctxt->vie.op.op_flags & VIE_OP_F_CHECK_GVA_DI) != 0U) {
retval = instr_check_di(vcpu, emul_ctxt); retval = instr_check_di(vcpu, emul_ctxt);
if (retval < 0) {
return retval;
}
} else { } else {
retval = instr_check_gva(vcpu, emul_ctxt, cpu_mode); retval = instr_check_gva(vcpu, emul_ctxt, cpu_mode);
if (retval < 0) { }
return retval;
if (retval >= 0) {
retval = (int32_t)(emul_ctxt->vie.opsize);
}
}
} }
} }
return (int32_t)(emul_ctxt->vie.opsize); return retval;
} }
int32_t emulate_instruction(const struct acrn_vcpu *vcpu) int32_t emulate_instruction(const struct acrn_vcpu *vcpu)