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

Commit 3c85766

Browse files
authored
Merge pull request #233 from coxuintel/intstate_bit
Fix incorrect interruptibility_state before vmx entry.
2 parents 0335f37 + 6958731 commit 3c85766

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

core/include/vmx.h

+6
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,12 @@ enum {
502502
GAS_CSTATE = 4
503503
};
504504

505+
// Intel SDM Vol. 3C: Table 24-3. Format of Interruptibility State
506+
#define GUEST_INTRSTAT_STI_BLOCKING 0x00000001
507+
#define GUEST_INTRSTAT_SS_BLOCKING 0x00000002
508+
#define GUEST_INTRSTAT_SMI_BLOCKING 0x00000004
509+
#define GUEST_INTRSTAT_NMI_BLOCKING 0x00000008
510+
505511
#ifdef HAX_COMPILER_MSVC
506512
#pragma pack(push, 1)
507513
#endif

core/intr_exc.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,15 @@ uint hax_intr_is_blocked(struct vcpu_t *vcpu)
121121
{
122122
struct vcpu_state_t *state = vcpu->state;
123123
uint32_t intr_status;
124+
uint32_t intr_blocking = 0;
124125

125126
if (!(state->_eflags & EFLAGS_IF))
126127
return 1;
127128

129+
intr_blocking |= GUEST_INTRSTAT_STI_BLOCKING;
130+
intr_blocking |= GUEST_INTRSTAT_SS_BLOCKING;
128131
intr_status = vmx(vcpu, interruptibility_state).raw;
129-
if (intr_status & 3)
132+
if (intr_status & intr_blocking)
130133
return 1;
131134
return 0;
132135
}

core/vcpu.c

+26-3
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,27 @@ static void load_dirty_vmcs_fields(struct vcpu_t *vcpu)
10781078
vcpu->rflags_dirty = 0;
10791079
}
10801080

1081-
// interruptibility
1081+
/*
1082+
* interruptibility
1083+
* 26.3.1.5 Checks on Guest Non-Register State
1084+
* Bit 0 (blocking by STI) must be 0 if the IF flag (bit 9) is 0 in the
1085+
* RFLAGS field.
1086+
* This is a WA to fix the VM-entry failure due to invalid guest state,
1087+
* sometimes when a snapshot is loaded but IF and interruptibility_state
1088+
* don't pass the checks as mentioned in SDM 26.3.1.5.
1089+
* In in-order execution, interruptibility_state is updated when advancing
1090+
* the IP. However when a snapshot is loaded, EFLAGS are restored but
1091+
* guest non-register state not restored.
1092+
* TODO: Find better approach instead of letting the check pass.
1093+
*/
1094+
if (!(state->_rflags & EFLAGS_IF)) {
1095+
if (vmx(vcpu, interruptibility_state).raw &
1096+
GUEST_INTRSTAT_STI_BLOCKING) {
1097+
vmx(vcpu, interruptibility_state).raw &=
1098+
~GUEST_INTRSTAT_STI_BLOCKING;
1099+
vcpu->interruptibility_dirty = 1;
1100+
}
1101+
}
10821102
if (vcpu->interruptibility_dirty) {
10831103
vmwrite(vcpu, GUEST_INTERRUPTIBILITY,
10841104
vmx(vcpu, interruptibility_state).raw);
@@ -1747,9 +1767,12 @@ static void advance_rip(struct vcpu_t *vcpu)
17471767
{
17481768
struct vcpu_state_t *state = vcpu->state;
17491769
uint32_t interruptibility = vmx(vcpu, interruptibility_state).raw;
1770+
uint32_t intr_blocking = 0;
17501771

1751-
if (interruptibility & 3u) {
1752-
interruptibility &= ~3u;
1772+
intr_blocking |= GUEST_INTRSTAT_STI_BLOCKING;
1773+
intr_blocking |= GUEST_INTRSTAT_SS_BLOCKING;
1774+
if (interruptibility & intr_blocking) {
1775+
interruptibility &= ~intr_blocking;
17531776
vmx(vcpu, interruptibility_state).raw = interruptibility;
17541777
vcpu->interruptibility_dirty = 1;
17551778
}

0 commit comments

Comments
 (0)