@@ -280,6 +280,10 @@ module_param(avic, int, S_IRUGO);
280
280
static int vls = true;
281
281
module_param (vls , int , 0444 );
282
282
283
+ /* enable/disable Virtual GIF */
284
+ static int vgif = true;
285
+ module_param (vgif , int , 0444 );
286
+
283
287
static void svm_set_cr0 (struct kvm_vcpu * vcpu , unsigned long cr0 );
284
288
static void svm_flush_tlb (struct kvm_vcpu * vcpu );
285
289
static void svm_complete_interrupts (struct vcpu_svm * svm );
@@ -475,19 +479,33 @@ static inline void clr_intercept(struct vcpu_svm *svm, int bit)
475
479
recalc_intercepts (svm );
476
480
}
477
481
482
+ static inline bool vgif_enabled (struct vcpu_svm * svm )
483
+ {
484
+ return !!(svm -> vmcb -> control .int_ctl & V_GIF_ENABLE_MASK );
485
+ }
486
+
478
487
static inline void enable_gif (struct vcpu_svm * svm )
479
488
{
480
- svm -> vcpu .arch .hflags |= HF_GIF_MASK ;
489
+ if (vgif_enabled (svm ))
490
+ svm -> vmcb -> control .int_ctl |= V_GIF_MASK ;
491
+ else
492
+ svm -> vcpu .arch .hflags |= HF_GIF_MASK ;
481
493
}
482
494
483
495
static inline void disable_gif (struct vcpu_svm * svm )
484
496
{
485
- svm -> vcpu .arch .hflags &= ~HF_GIF_MASK ;
497
+ if (vgif_enabled (svm ))
498
+ svm -> vmcb -> control .int_ctl &= ~V_GIF_MASK ;
499
+ else
500
+ svm -> vcpu .arch .hflags &= ~HF_GIF_MASK ;
486
501
}
487
502
488
503
static inline bool gif_set (struct vcpu_svm * svm )
489
504
{
490
- return !!(svm -> vcpu .arch .hflags & HF_GIF_MASK );
505
+ if (vgif_enabled (svm ))
506
+ return !!(svm -> vmcb -> control .int_ctl & V_GIF_MASK );
507
+ else
508
+ return !!(svm -> vcpu .arch .hflags & HF_GIF_MASK );
491
509
}
492
510
493
511
static unsigned long iopm_base ;
@@ -969,6 +987,7 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
969
987
static void disable_nmi_singlestep (struct vcpu_svm * svm )
970
988
{
971
989
svm -> nmi_singlestep = false;
990
+
972
991
if (!(svm -> vcpu .guest_debug & KVM_GUESTDBG_SINGLESTEP )) {
973
992
/* Clear our flags if they were not set by the guest */
974
993
if (!(svm -> nmi_singlestep_guest_rflags & X86_EFLAGS_TF ))
@@ -1106,6 +1125,13 @@ static __init int svm_hardware_setup(void)
1106
1125
}
1107
1126
}
1108
1127
1128
+ if (vgif ) {
1129
+ if (!boot_cpu_has (X86_FEATURE_VGIF ))
1130
+ vgif = false;
1131
+ else
1132
+ pr_info ("Virtual GIF supported\n" );
1133
+ }
1134
+
1109
1135
return 0 ;
1110
1136
1111
1137
err :
@@ -1303,6 +1329,12 @@ static void init_vmcb(struct vcpu_svm *svm)
1303
1329
svm -> vmcb -> control .virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK ;
1304
1330
}
1305
1331
1332
+ if (vgif ) {
1333
+ clr_intercept (svm , INTERCEPT_STGI );
1334
+ clr_intercept (svm , INTERCEPT_CLGI );
1335
+ svm -> vmcb -> control .int_ctl |= V_GIF_ENABLE_MASK ;
1336
+ }
1337
+
1306
1338
mark_all_dirty (svm -> vmcb );
1307
1339
1308
1340
enable_gif (svm );
@@ -3133,6 +3165,13 @@ static int stgi_interception(struct vcpu_svm *svm)
3133
3165
if (nested_svm_check_permissions (svm ))
3134
3166
return 1 ;
3135
3167
3168
+ /*
3169
+ * If VGIF is enabled, the STGI intercept is only added to
3170
+ * detect the opening of the NMI window; remove it now.
3171
+ */
3172
+ if (vgif_enabled (svm ))
3173
+ clr_intercept (svm , INTERCEPT_STGI );
3174
+
3136
3175
svm -> next_rip = kvm_rip_read (& svm -> vcpu ) + 3 ;
3137
3176
ret = kvm_skip_emulated_instruction (& svm -> vcpu );
3138
3177
kvm_make_request (KVM_REQ_EVENT , & svm -> vcpu );
@@ -4668,9 +4707,11 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
4668
4707
* In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
4669
4708
* 1, because that's a separate STGI/VMRUN intercept. The next time we
4670
4709
* get that intercept, this function will be called again though and
4671
- * we'll get the vintr intercept.
4710
+ * we'll get the vintr intercept. However, if the vGIF feature is
4711
+ * enabled, the STGI interception will not occur. Enable the irq
4712
+ * window under the assumption that the hardware will set the GIF.
4672
4713
*/
4673
- if (gif_set (svm ) && nested_svm_intr (svm )) {
4714
+ if (( vgif_enabled ( svm ) || gif_set (svm ) ) && nested_svm_intr (svm )) {
4674
4715
svm_set_vintr (svm );
4675
4716
svm_inject_irq (svm , 0x0 );
4676
4717
}
@@ -4684,8 +4725,11 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
4684
4725
== HF_NMI_MASK )
4685
4726
return ; /* IRET will cause a vm exit */
4686
4727
4687
- if ((svm -> vcpu .arch .hflags & HF_GIF_MASK ) == 0 )
4728
+ if (!gif_set (svm )) {
4729
+ if (vgif_enabled (svm ))
4730
+ set_intercept (svm , INTERCEPT_STGI );
4688
4731
return ; /* STGI will cause a vm exit */
4732
+ }
4689
4733
4690
4734
if (svm -> nested .exit_required )
4691
4735
return ; /* we're not going to run the guest yet */
0 commit comments