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)
{
int32_t ret = 0;
uint64_t mask;
if (cpu_mode != CPU_MODE_64BIT) {
return 0;
}
if (cpu_mode == CPU_MODE_64BIT) {
/*
* The value of the bit 47 in the 'gla' should be replicated in the
* most significant 16 bits.
*/
mask = ~((1UL << 48U) - 1UL);
if ((gla & (1UL << 47U)) != 0U) {
return ((gla & mask) != mask) ? 1 : 0;
ret = ((gla & mask) != mask) ? 1 : 0;
} 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)
{
bool ret = true;
uint32_t type;
/* The descriptor type must indicate a code/data segment. */
type = seg_desc_type(desc->access);
if (type < 16U || type > 31U) {
return false;
}
if (type < 16U) {
ret = false;
} else {
if ((prot & PROT_READ) != 0U) {
/* #GP on a read access to a exec-only code segment */
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.
*/
if ((type & 0x8U) != 0U) { /* code segment */
return false;
ret = false;
}
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)
{
uint64_t rflags;
switch (opsize) {
case 1U:
return getcc8((uint8_t) x, (uint8_t) y);
rflags = getcc8((uint8_t) x, (uint8_t) y);
break;
case 2U:
return getcc16((uint16_t) x, (uint16_t) y);
rflags = getcc16((uint16_t) x, (uint16_t) y);
break;
case 4U:
return getcc32((uint32_t) x, (uint32_t) y);
rflags = getcc32((uint32_t) x, (uint32_t) y);
break;
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)
@ -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,
uint8_t addrsize, uint64_t *gva)
{
int32_t ret = 0;
int32_t ret = -EFAULT;
uint32_t err_code;
struct seg_desc desc;
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 {
if ((addrsize != 2U) && (addrsize != 4U)) {
has_exception = true;
} else if (!is_desc_valid(&desc, PROT_WRITE)) {
} else {
if (!is_desc_valid(&desc, PROT_WRITE)) {
has_exception = true;
}
}
}
if (!has_exception) {
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);
}
} else {
/* If we are checking the dest operand for movs instruction,
* we cache the gpa if check pass. It will be used during
* movs instruction emulation.
*/
vie->dst_gpa = gpa;
ret = 0;
}
}
}
if (has_exception) {
vcpu_inject_gp(vcpu, 0U);
ret = -EFAULT;
}
return ret;
@ -1071,9 +1086,10 @@ done:
static int32_t emulate_stos(struct acrn_vcpu *vcpu, const struct instr_emul_vie *vie)
{
bool done = false;
uint8_t repeat, opsize = vie->opsize;
uint64_t val;
uint64_t rcx, rdi, rflags;
uint64_t rcx = 0U, rdi, rflags;
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.
*/
if ((rcx & size2mask[vie->addrsize]) == 0UL) {
return 0;
done = true;
}
}
if (!done) {
val = vm_get_register(vcpu, CPU_REG_RAX);
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);
}
}
}
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)
{
int32_t error = 0;
int32_t ret = 0;
uint8_t size;
uint64_t regop, memop, op1, op2, rflags2;
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;
op2 = regop;
}
rflags2 = getcc(size, op1, op2);
break;
case 0x80U:
case 0x81U:
@ -1426,16 +1443,18 @@ static int32_t emulate_cmp(struct acrn_vcpu *vcpu, const struct instr_emul_vie *
/* get the first operand */
vie_mmio_read(vcpu, &op1);
rflags2 = getcc(size, op1, (uint64_t)vie->immediate);
op2 = (uint64_t)vie->immediate;
break;
default:
return -EINVAL;
ret = -EINVAL;
break;
}
if (ret == 0) {
rflags2 = getcc(size, op1, op2);
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)
@ -1613,11 +1632,9 @@ static int32_t vie_init(struct instr_emul_vie *vie, struct acrn_vcpu *vcpu)
int32_t ret;
if ((inst_len > VIE_INST_SIZE) || (inst_len == 0U)) {
pr_err("%s: invalid instruction length (%d)",
__func__, inst_len);
return -EINVAL;
}
pr_err("%s: invalid instruction length (%d)", __func__, inst_len);
ret = -EINVAL;
} else {
(void)memset(vie, 0U, sizeof(struct instr_emul_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;
err_code = PAGE_FAULT_ID_FLAG;
ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva,
inst_len, &err_code, &fault_addr);
ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva, inst_len, &err_code, &fault_addr);
if (ret < 0) {
if (ret == -EFAULT) {
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 0;
return ret;
}
static int32_t vie_peek(const struct instr_emul_vie *vie, uint8_t *x)
{
int32_t ret;
if (vie->num_processed < vie->num_valid) {
*x = vie->inst[vie->num_processed];
return 0;
ret = 0;
} else {
return -1;
ret = -1;
}
return ret;
}
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)
{
bool override = true;
switch (x) {
case 0x2EU:
*seg = CPU_REG_CS;
@ -1680,9 +1698,10 @@ static bool segment_override(uint8_t x, enum cpu_reg_name *seg)
*seg = CPU_REG_GS;
break;
default:
return false;
override = false;
break;
}
return true;
return override;
}
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)
{
int32_t ret = 0;
uint8_t x;
if (vie_peek(vie, &x) != 0) {
return -1;
}
ret = -1;
} else {
vie->opcode = x;
vie->op = two_byte_opcodes[x];
if (vie->op.op_type == VIE_OP_TYPE_NONE) {
return -1;
ret = -1;
} else {
vie_advance(vie);
}
}
vie_advance(vie);
return 0;
return ret;
}
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;
if (vie_peek(vie, &x) != 0) {
return -1;
}
ret = -1;
} else {
vie->opcode = x;
vie->op = one_byte_opcodes[x];
if (vie->op.op_type == VIE_OP_TYPE_NONE) {
return -1;
}
ret = -1;
} else {
vie_advance(vie);
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)) {
vie->opsize = 1U;
}
}
}
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)
{
uint8_t x;
int32_t ret;
if ((vie->op.op_flags & VIE_OP_F_NO_MODRM) != 0U) {
return 0;
}
if (cpu_mode == CPU_MODE_REAL) {
return -1;
}
if (vie_peek(vie, &x) != 0) {
return -1;
}
ret = 0;
} else if (cpu_mode == CPU_MODE_REAL) {
ret = -1;
} else if (vie_peek(vie, &x) != 0) {
ret = -1;
} else {
vie->mod = (x >> 6U) & 0x3U;
vie->rm = (x >> 0U) & 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.
*/
if (vie->mod == VIE_MOD_DIRECT) {
return -1;
}
ret = -1;
} else {
if (((vie->mod == VIE_MOD_INDIRECT) && (vie->rm == VIE_RM_DISP32)) ||
((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);
/* SIB */
if (vie->mod != VIE_MOD_DIRECT && vie->rm == VIE_RM_SIB) {
goto done;
}
if ((vie->mod != VIE_MOD_DIRECT) && (vie->rm == VIE_RM_SIB)) {
/* done */
} else {
vie->base_register = (enum cpu_reg_name)vie->rm;
switch (vie->mod) {
@ -1899,24 +1913,27 @@ static int32_t decode_modrm(struct instr_emul_vie *vie, enum vm_cpu_mode cpu_mod
break;
}
done:
}
vie_advance(vie);
return 0;
ret = 0;
}
}
return ret;
}
static int32_t decode_sib(struct instr_emul_vie *vie)
{
uint8_t x;
int32_t ret;
/* Proceed only if SIB byte is present */
if ((vie->mod == VIE_MOD_DIRECT) || (vie->rm != VIE_RM_SIB)) {
return 0;
}
if (vie_peek(vie, &x) != 0) {
return -1;
}
ret = 0;
} else if (vie_peek(vie, &x) != 0) {
ret = -1;
} else {
/* De-construct the SIB byte */
vie->ss = (x >> 6U) & 0x3U;
@ -1949,8 +1966,7 @@ static int32_t decode_sib(struct instr_emul_vie *vie)
break;
}
if ((vie->mod == VIE_MOD_INDIRECT) &&
((vie->base == 5U) || (vie->base == 13U))) {
if ((vie->mod == VIE_MOD_INDIRECT) && ((vie->base == 5U) || (vie->base == 13U))) {
/*
* Special case when base register is unused if mod = 0
* and base = %rbp or %r13.
@ -1982,12 +1998,16 @@ static int32_t decode_sib(struct instr_emul_vie *vie)
vie_advance(vie);
return 0;
ret = 0;
}
return ret;
}
static int32_t decode_displacement(struct instr_emul_vie *vie)
{
uint8_t n, i, x;
int32_t ret = 0;
union {
uint8_t buf[4];
@ -1996,37 +2016,39 @@ static int32_t decode_displacement(struct instr_emul_vie *vie)
} u;
n = vie->disp_bytes;
if (n == 0U) {
return 0;
}
if (n != 0U) {
if ((n != 1U) && (n != 4U)) {
pr_err("%s: decode_displacement: invalid disp_bytes %d",
__func__, n);
return -EINVAL;
}
pr_err("%s: decode_displacement: invalid disp_bytes %d", __func__, n);
ret = -EINVAL;
} else {
for (i = 0U; i < n; i++) {
if (vie_peek(vie, &x) != 0) {
return -1;
ret = -1;
break;
}
u.buf[i] = x;
vie_advance(vie);
}
if (ret == 0) {
if (n == 1U) {
vie->displacement = u.signed8; /* sign-extended */
} else {
vie->displacement = u.signed32; /* sign-extended */
}
}
}
}
return 0;
return ret;
}
static int32_t decode_immediate(struct instr_emul_vie *vie)
{
uint8_t i, n, x;
int32_t ret = 0;
union {
uint8_t buf[4];
int8_t signed8;
@ -2056,25 +2078,22 @@ static int32_t decode_immediate(struct instr_emul_vie *vie)
}
n = vie->imm_bytes;
if (n == 0U) {
return 0;
}
if (n != 0U) {
if ((n != 1U) && (n != 2U) && (n != 4U)) {
pr_err("%s: invalid number of immediate bytes: %d",
__func__, n);
return -EINVAL;
}
pr_err("%s: invalid number of immediate bytes: %d", __func__, n);
ret = -EINVAL;
} else {
for (i = 0U; i < n; i++) {
if (vie_peek(vie, &x) != 0) {
return -1;
ret = -1;
break;
}
u.buf[i] = x;
vie_advance(vie);
}
if (ret == 0) {
/* sign-extend the immediate value before use */
if (n == 1U) {
vie->immediate = u.signed8;
@ -2083,22 +2102,23 @@ static int32_t decode_immediate(struct instr_emul_vie *vie)
} else {
vie->immediate = u.signed32;
}
}
}
}
return 0;
return ret;
}
static int32_t decode_moffset(struct instr_emul_vie *vie)
{
uint8_t i, n, x;
int32_t ret = 0;
union {
uint8_t buf[8];
uint64_t u64;
} u;
if ((vie->op.op_flags & VIE_OP_F_MOFFSET) == 0U) {
return 0;
}
if ((vie->op.op_flags & VIE_OP_F_MOFFSET) != 0U) {
/*
* Section 2.2.1.4, "Direct Memory-Offset MOVs", Intel SDM:
* 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;
if ((n != 2U) && (n != 4U) && (n != 8U)) {
pr_err("%s: invalid moffset bytes: %hhu", __func__, n);
return -EINVAL;
}
ret = -EINVAL;
} else {
u.u64 = 0UL;
for (i = 0U; i < n; i++) {
if (vie_peek(vie, &x) != 0) {
return -1;
ret = -1;
break;
}
u.buf[i] = x;
vie_advance(vie);
}
if (ret == 0) {
vie->displacement = (int64_t)u.u64;
return 0;
}
}
}
return ret;
}
static int32_t local_decode_instruction(enum vm_cpu_mode cpu_mode,
bool cs_d, struct instr_emul_vie *vie)
{
int32_t ret;
if (decode_prefixes(vie, cpu_mode, cs_d) != 0) {
return -1;
}
if (decode_opcode(vie) != 0) {
return -1;
}
if (decode_modrm(vie, cpu_mode) != 0) {
return -1;
}
if (decode_sib(vie) != 0) {
return -1;
}
if (decode_displacement(vie) != 0) {
return -1;
}
if (decode_immediate(vie) != 0) {
return -1;
}
if (decode_moffset(vie) != 0) {
return -1;
}
ret = -1;
} else if (decode_opcode(vie) != 0) {
ret = -1;
} else if (decode_modrm(vie, cpu_mode) != 0) {
ret = -1;
} else if (decode_sib(vie) != 0) {
ret = -1;
} else if (decode_displacement(vie) != 0) {
ret = -1;
} else if (decode_immediate(vie) != 0) {
ret = -1;
} else if (decode_moffset(vie) != 0) {
ret = -1;
} else {
vie->decoded = 1U; /* success */
ret = 0;
}
return 0;
return ret;
}
/* 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,
enum vm_cpu_mode cpu_mode)
{
int32_t ret;
int32_t ret = 0;
uint64_t base, segbase, idx, gva, gpa;
uint32_t err_code;
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 {
vcpu_inject_gp(vcpu, 0U);
}
return -EFAULT;
}
err_code = (vcpu->req.reqs.mmio.direction == REQUEST_WRITE) ?
PAGE_FAULT_WR_FLAG : 0U;
ret = -EFAULT;
} else {
err_code = (vcpu->req.reqs.mmio.direction == REQUEST_WRITE) ? PAGE_FAULT_WR_FLAG : 0U;
ret = gva2gpa(vcpu, gva, &gpa, &err_code);
if (ret < 0) {
if (ret == -EFAULT) {
vcpu_inject_pf(vcpu, gva,
err_code);
vcpu_inject_pf(vcpu, gva, err_code);
}
} else {
ret = 0;
}
return ret;
}
return 0;
return ret;
}
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);
if (emul_ctxt == NULL) {
pr_err("%s: Failed to get emul_ctxt", __func__);
return -1;
}
retval = -1;
} else {
emul_ctxt->vcpu = vcpu;
retval = vie_init(&emul_ctxt->vie, vcpu);
if (retval < 0) {
if (retval != -EFAULT) {
pr_err("init vie failed @ 0x%016llx:",
vcpu_get_rip(vcpu));
}
return retval;
pr_err("init vie failed @ 0x%016llx:", vcpu_get_rip(vcpu));
}
} else {
csar = exec_vmread32(VMX_GUEST_CS_ATTR);
get_guest_paging_info(vcpu, emul_ctxt, csar);
cpu_mode = get_vcpu_mode(vcpu);
retval = local_decode_instruction(cpu_mode, seg_desc_def32(csar),
&emul_ctxt->vie);
retval = local_decode_instruction(cpu_mode, seg_desc_def32(csar), &emul_ctxt->vie);
if (retval != 0) {
pr_err("decode instruction failed @ 0x%016llx:",
vcpu_get_rip(vcpu));
pr_err("decode instruction failed @ 0x%016llx:", vcpu_get_rip(vcpu));
vcpu_inject_ud(vcpu);
return -EFAULT;
}
retval = -EFAULT;
} else {
/*
* We do operand check in instruction decode phase and
* 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) {
retval = instr_check_di(vcpu, emul_ctxt);
if (retval < 0) {
return retval;
}
} else {
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)