@@ -1078,7 +1078,27 @@ static void load_dirty_vmcs_fields(struct vcpu_t *vcpu)
1078
1078
vcpu -> rflags_dirty = 0 ;
1079
1079
}
1080
1080
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
+ }
1082
1102
if (vcpu -> interruptibility_dirty ) {
1083
1103
vmwrite (vcpu , GUEST_INTERRUPTIBILITY ,
1084
1104
vmx (vcpu , interruptibility_state ).raw );
@@ -1747,9 +1767,12 @@ static void advance_rip(struct vcpu_t *vcpu)
1747
1767
{
1748
1768
struct vcpu_state_t * state = vcpu -> state ;
1749
1769
uint32_t interruptibility = vmx (vcpu , interruptibility_state ).raw ;
1770
+ uint32_t intr_blocking = 0 ;
1750
1771
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 ;
1753
1776
vmx (vcpu , interruptibility_state ).raw = interruptibility ;
1754
1777
vcpu -> interruptibility_dirty = 1 ;
1755
1778
}
0 commit comments