Skip to content

Commit 640bd6e

Browse files
Janakarajan Natarajanbonzini
authored andcommitted
KVM: SVM: Enable Virtual GIF feature
Enable the Virtual GIF feature. This is done by setting bit 25 at position 60h in the vmcb. With this feature enabled, the processor uses bit 9 at position 60h as the virtual GIF when executing STGI/CLGI instructions. Since the execution of STGI by the L1 hypervisor does not cause a return to the outermost (L0) hypervisor, the enable_irq_window and enable_nmi_window are modified. The IRQ window will be opened even if GIF is not set, under the assumption that on resuming the L1 hypervisor the IRQ will be held pending until the processor executes the STGI instruction. For the NMI window, the STGI intercept is set. This will assist in opening the window only when GIF=1. Signed-off-by: Janakarajan Natarajan <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent d837312 commit 640bd6e

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

arch/x86/include/asm/svm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
107107
#define V_IRQ_SHIFT 8
108108
#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
109109

110+
#define V_GIF_SHIFT 9
111+
#define V_GIF_MASK (1 << V_GIF_SHIFT)
112+
110113
#define V_INTR_PRIO_SHIFT 16
111114
#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
112115

@@ -116,6 +119,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
116119
#define V_INTR_MASKING_SHIFT 24
117120
#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
118121

122+
#define V_GIF_ENABLE_SHIFT 25
123+
#define V_GIF_ENABLE_MASK (1 << V_GIF_ENABLE_SHIFT)
124+
119125
#define AVIC_ENABLE_SHIFT 31
120126
#define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT)
121127

arch/x86/kvm/svm.c

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,10 @@ module_param(avic, int, S_IRUGO);
280280
static int vls = true;
281281
module_param(vls, int, 0444);
282282

283+
/* enable/disable Virtual GIF */
284+
static int vgif = true;
285+
module_param(vgif, int, 0444);
286+
283287
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
284288
static void svm_flush_tlb(struct kvm_vcpu *vcpu);
285289
static void svm_complete_interrupts(struct vcpu_svm *svm);
@@ -475,19 +479,33 @@ static inline void clr_intercept(struct vcpu_svm *svm, int bit)
475479
recalc_intercepts(svm);
476480
}
477481

482+
static inline bool vgif_enabled(struct vcpu_svm *svm)
483+
{
484+
return !!(svm->vmcb->control.int_ctl & V_GIF_ENABLE_MASK);
485+
}
486+
478487
static inline void enable_gif(struct vcpu_svm *svm)
479488
{
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;
481493
}
482494

483495
static inline void disable_gif(struct vcpu_svm *svm)
484496
{
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;
486501
}
487502

488503
static inline bool gif_set(struct vcpu_svm *svm)
489504
{
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);
491509
}
492510

493511
static unsigned long iopm_base;
@@ -969,6 +987,7 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
969987
static void disable_nmi_singlestep(struct vcpu_svm *svm)
970988
{
971989
svm->nmi_singlestep = false;
990+
972991
if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) {
973992
/* Clear our flags if they were not set by the guest */
974993
if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF))
@@ -1106,6 +1125,13 @@ static __init int svm_hardware_setup(void)
11061125
}
11071126
}
11081127

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+
11091135
return 0;
11101136

11111137
err:
@@ -1303,6 +1329,12 @@ static void init_vmcb(struct vcpu_svm *svm)
13031329
svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
13041330
}
13051331

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+
13061338
mark_all_dirty(svm->vmcb);
13071339

13081340
enable_gif(svm);
@@ -3133,6 +3165,13 @@ static int stgi_interception(struct vcpu_svm *svm)
31333165
if (nested_svm_check_permissions(svm))
31343166
return 1;
31353167

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+
31363175
svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
31373176
ret = kvm_skip_emulated_instruction(&svm->vcpu);
31383177
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
@@ -4668,9 +4707,11 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
46684707
* In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
46694708
* 1, because that's a separate STGI/VMRUN intercept. The next time we
46704709
* 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.
46724713
*/
4673-
if (gif_set(svm) && nested_svm_intr(svm)) {
4714+
if ((vgif_enabled(svm) || gif_set(svm)) && nested_svm_intr(svm)) {
46744715
svm_set_vintr(svm);
46754716
svm_inject_irq(svm, 0x0);
46764717
}
@@ -4684,8 +4725,11 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
46844725
== HF_NMI_MASK)
46854726
return; /* IRET will cause a vm exit */
46864727

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);
46884731
return; /* STGI will cause a vm exit */
4732+
}
46894733

46904734
if (svm->nested.exit_required)
46914735
return; /* we're not going to run the guest yet */

0 commit comments

Comments
 (0)