diff --git a/hypervisor/arch/x86/guest/instr_emul.c b/hypervisor/arch/x86/guest/instr_emul.c index 89fe7ccc4..c44b931f6 100644 --- a/hypervisor/arch/x86/guest/instr_emul.c +++ b/hypervisor/arch/x86/guest/instr_emul.c @@ -361,6 +361,26 @@ vie_update_register(struct vcpu *vcpu, enum cpu_reg_name reg, #define RFLAGS_STATUS_BITS (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_V) +static int vie_update_rflags(struct vcpu *vcpu, uint64_t rflags2, uint64_t psl) +{ + int error; + uint8_t size; + uint64_t rflags; + + error = vie_read_register(vcpu, CPU_REG_RFLAGS, &rflags); + if (error != 0) { + return error; + } + + rflags &= ~RFLAGS_STATUS_BITS; + rflags |= rflags2 & psl; + size = 8U; + + error = vie_update_register(vcpu, CPU_REG_RFLAGS, rflags, size); + + return error; +} + /* * Return the status flags that would result from doing (x - y). */ @@ -832,7 +852,7 @@ emulate_test(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, int error; uint8_t size; enum cpu_reg_name reg; - uint64_t result, rflags, rflags2, val1, val2; + uint64_t result, rflags2, val1, val2; size = vie->opsize; error = -EINVAL; @@ -878,11 +898,6 @@ emulate_test(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, return error; } - error = vie_read_register(vcpu, CPU_REG_RFLAGS, &rflags); - if (error != 0) { - return error; - } - /* * OF and CF are cleared; the SF, ZF and PF flags are set according * to the result; AF is undefined. @@ -890,10 +905,8 @@ emulate_test(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, * The updated status flags are obtained by subtracting 0 from 'result'. */ rflags2 = getcc(size, result, 0UL); - rflags &= ~RFLAGS_STATUS_BITS; - rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N); - size = 8U; - error = vie_update_register(vcpu, CPU_REG_RFLAGS, rflags, size); + error = vie_update_rflags(vcpu, rflags2, PSL_PF | PSL_Z | PSL_N); + return error; } @@ -905,7 +918,7 @@ emulate_and(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, int error; uint8_t size; enum cpu_reg_name reg; - uint64_t result, rflags, rflags2, val1, val2; + uint64_t result, rflags2, val1, val2; size = vie->opsize; error = -EINVAL; @@ -974,11 +987,6 @@ emulate_and(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, return error; } - error = vie_read_register(vcpu, CPU_REG_RFLAGS, &rflags); - if (error != 0) { - return error; - } - /* * OF and CF are cleared; the SF, ZF and PF flags are set according * to the result; AF is undefined. @@ -986,10 +994,8 @@ emulate_and(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, * The updated status flags are obtained by subtracting 0 from 'result'. */ rflags2 = getcc(size, result, 0UL); - rflags &= ~RFLAGS_STATUS_BITS; - rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N); - size = 8U; - error = vie_update_register(vcpu, CPU_REG_RFLAGS, rflags, size); + error = vie_update_rflags(vcpu, rflags2, PSL_PF | PSL_Z | PSL_N); + return error; } @@ -1001,7 +1007,7 @@ emulate_or(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, int error; uint8_t size; enum cpu_reg_name reg; - uint64_t val1, val2, result, rflags, rflags2; + uint64_t val1, val2, result, rflags2; size = vie->opsize; error = -EINVAL; @@ -1073,11 +1079,6 @@ emulate_or(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, return error; } - error = vie_read_register(vcpu, CPU_REG_RFLAGS, &rflags); - if (error != 0) { - return error; - } - /* * OF and CF are cleared; the SF, ZF and PF flags are set according * to the result; AF is undefined. @@ -1085,10 +1086,8 @@ emulate_or(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, * The updated status flags are obtained by subtracting 0 from 'result'. */ rflags2 = getcc(size, result, 0UL); - rflags &= ~RFLAGS_STATUS_BITS; - rflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N); - size = 8U; - error = vie_update_register(vcpu, CPU_REG_RFLAGS, rflags, size); + error = vie_update_rflags(vcpu, rflags2, PSL_PF | PSL_Z | PSL_N); + return error; } @@ -1099,7 +1098,7 @@ emulate_cmp(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, { int error; uint8_t size; - uint64_t regop, memop, op1, op2, rflags, rflags2; + uint64_t regop, memop, op1, op2, rflags2; enum cpu_reg_name reg; size = vie->opsize; @@ -1184,14 +1183,9 @@ emulate_cmp(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, default: return -EINVAL; } - error = vie_read_register(vcpu, CPU_REG_RFLAGS, &rflags); - if (error != 0) { - return error; - } - rflags &= ~RFLAGS_STATUS_BITS; - rflags |= rflags2 & RFLAGS_STATUS_BITS; - size = 8U; - error = vie_update_register(vcpu, CPU_REG_RFLAGS, rflags, size); + + error = vie_update_rflags(vcpu, rflags2, RFLAGS_STATUS_BITS); + return error; } @@ -1202,7 +1196,7 @@ emulate_sub(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, { int error; uint8_t size; - uint64_t nval, rflags, rflags2, val1, val2; + uint64_t nval, rflags2, val1, val2; enum cpu_reg_name reg; size = vie->opsize; @@ -1240,21 +1234,13 @@ emulate_sub(struct vcpu *vcpu, uint64_t gpa, struct vie *vie, break; } - if (error == 0) { - rflags2 = getcc(size, val1, val2); - error = vie_read_register(vcpu, CPU_REG_RFLAGS, - &rflags); - if (error != 0) { - return error; - } - - rflags &= ~RFLAGS_STATUS_BITS; - rflags |= rflags2 & RFLAGS_STATUS_BITS; - size = 8U; - error = vie_update_register(vcpu, CPU_REG_RFLAGS, - rflags, size); + if (error != 0) { + return error; } + rflags2 = getcc(size, val1, val2); + error = vie_update_rflags(vcpu, rflags2, RFLAGS_STATUS_BITS); + return error; }