diff --git a/core/include/vmx.h b/core/include/vmx.h index f09b0fd6..0d7e4fa9 100644 --- a/core/include/vmx.h +++ b/core/include/vmx.h @@ -502,6 +502,12 @@ enum { GAS_CSTATE = 4 }; +// Intel SDM Vol. 3C: Table 24-3. Format of Interruptibility State +#define GUEST_INTRSTAT_STI_BLOCKING 0x00000001 +#define GUEST_INTRSTAT_SS_BLOCKING 0x00000002 +#define GUEST_INTRSTAT_SMI_BLOCKING 0x00000004 +#define GUEST_INTRSTAT_NMI_BLOCKING 0x00000008 + #ifdef HAX_COMPILER_MSVC #pragma pack(push, 1) #endif diff --git a/core/intr_exc.c b/core/intr_exc.c index 80bd18a0..745f324b 100644 --- a/core/intr_exc.c +++ b/core/intr_exc.c @@ -121,12 +121,15 @@ uint hax_intr_is_blocked(struct vcpu_t *vcpu) { struct vcpu_state_t *state = vcpu->state; uint32_t intr_status; + uint32_t intr_blocking = 0; if (!(state->_eflags & EFLAGS_IF)) return 1; + intr_blocking |= GUEST_INTRSTAT_STI_BLOCKING; + intr_blocking |= GUEST_INTRSTAT_SS_BLOCKING; intr_status = vmx(vcpu, interruptibility_state).raw; - if (intr_status & 3) + if (intr_status & intr_blocking) return 1; return 0; } diff --git a/core/vcpu.c b/core/vcpu.c index 2ee7bb65..4b4be3bc 100644 --- a/core/vcpu.c +++ b/core/vcpu.c @@ -1078,7 +1078,27 @@ static void load_dirty_vmcs_fields(struct vcpu_t *vcpu) vcpu->rflags_dirty = 0; } - // interruptibility + /* + * interruptibility + * 26.3.1.5 Checks on Guest Non-Register State + * Bit 0 (blocking by STI) must be 0 if the IF flag (bit 9) is 0 in the + * RFLAGS field. + * This is a WA to fix the VM-entry failure due to invalid guest state, + * sometimes when a snapshot is loaded but IF and interruptibility_state + * don't pass the checks as mentioned in SDM 26.3.1.5. + * In in-order execution, interruptibility_state is updated when advancing + * the IP. However when a snapshot is loaded, EFLAGS are restored but + * guest non-register state not restored. + * TODO: Find better approach instead of letting the check pass. + */ + if (!(state->_rflags & EFLAGS_IF)) { + if (vmx(vcpu, interruptibility_state).raw & + GUEST_INTRSTAT_STI_BLOCKING) { + vmx(vcpu, interruptibility_state).raw &= + ~GUEST_INTRSTAT_STI_BLOCKING; + vcpu->interruptibility_dirty = 1; + } + } if (vcpu->interruptibility_dirty) { vmwrite(vcpu, GUEST_INTERRUPTIBILITY, vmx(vcpu, interruptibility_state).raw); @@ -1747,9 +1767,12 @@ static void advance_rip(struct vcpu_t *vcpu) { struct vcpu_state_t *state = vcpu->state; uint32_t interruptibility = vmx(vcpu, interruptibility_state).raw; + uint32_t intr_blocking = 0; - if (interruptibility & 3u) { - interruptibility &= ~3u; + intr_blocking |= GUEST_INTRSTAT_STI_BLOCKING; + intr_blocking |= GUEST_INTRSTAT_SS_BLOCKING; + if (interruptibility & intr_blocking) { + interruptibility &= ~intr_blocking; vmx(vcpu, interruptibility_state).raw = interruptibility; vcpu->interruptibility_dirty = 1; }