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

Fix incorrect interruptibility_state before vmx entry. #233

Merged
merged 1 commit into from
Aug 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intr_blocking = GUEST_INTRSTAT_STI_BLOCKING | GUEST_INTRSTAT_SS_BLOCKING;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I code in this way to prevent line exceeding 80 chars. And possibly more bits will be OR-ed.

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