mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 04:02:05 +00:00
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:
parent
5c24f8bb66
commit
40c5139ea3
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user