Skip to content
This repository has been archived by the owner on Jan 28, 2023. It is now read-only.

Commit

Permalink
Fix incorrect interruptibility_state before vmx entry.
Browse files Browse the repository at this point in the history
According to SDM 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.
There is an issue during snapshot loading, that IF and
interruptibility_state don't pass the checks, which will result in
VM-entry failure due to invalid guest state.
This WA correct the bit so that vmx entry check could pass. The normal
interruptibility_state update is done when advancing the IP.
In future, proper approach is expected to replace the WA.

Signed-off-by: Colin Xu <colin.xu@intel.com>
  • Loading branch information
coxuintel committed Aug 16, 2019
1 parent be7b3c6 commit 6958731
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 4 deletions.
6 changes: 6 additions & 0 deletions core/include/vmx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion core/intr_exc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
29 changes: 26 additions & 3 deletions core/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 6958731

Please sign in to comment.