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 <Janakarajan.Natarajan@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
d837312dfd
commit
640bd6e575
|
@ -107,6 +107,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||||
#define V_IRQ_SHIFT 8
|
#define V_IRQ_SHIFT 8
|
||||||
#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
|
#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
|
||||||
|
|
||||||
|
#define V_GIF_SHIFT 9
|
||||||
|
#define V_GIF_MASK (1 << V_GIF_SHIFT)
|
||||||
|
|
||||||
#define V_INTR_PRIO_SHIFT 16
|
#define V_INTR_PRIO_SHIFT 16
|
||||||
#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
|
#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
|
||||||
|
|
||||||
|
@ -116,6 +119,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
|
||||||
#define V_INTR_MASKING_SHIFT 24
|
#define V_INTR_MASKING_SHIFT 24
|
||||||
#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
|
#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
|
||||||
|
|
||||||
|
#define V_GIF_ENABLE_SHIFT 25
|
||||||
|
#define V_GIF_ENABLE_MASK (1 << V_GIF_ENABLE_SHIFT)
|
||||||
|
|
||||||
#define AVIC_ENABLE_SHIFT 31
|
#define AVIC_ENABLE_SHIFT 31
|
||||||
#define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT)
|
#define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT)
|
||||||
|
|
||||||
|
|
|
@ -280,6 +280,10 @@ module_param(avic, int, S_IRUGO);
|
||||||
static int vls = true;
|
static int vls = true;
|
||||||
module_param(vls, int, 0444);
|
module_param(vls, int, 0444);
|
||||||
|
|
||||||
|
/* enable/disable Virtual GIF */
|
||||||
|
static int vgif = true;
|
||||||
|
module_param(vgif, int, 0444);
|
||||||
|
|
||||||
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
|
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
|
||||||
static void svm_flush_tlb(struct kvm_vcpu *vcpu);
|
static void svm_flush_tlb(struct kvm_vcpu *vcpu);
|
||||||
static void svm_complete_interrupts(struct vcpu_svm *svm);
|
static void svm_complete_interrupts(struct vcpu_svm *svm);
|
||||||
|
@ -475,18 +479,32 @@ static inline void clr_intercept(struct vcpu_svm *svm, int bit)
|
||||||
recalc_intercepts(svm);
|
recalc_intercepts(svm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool vgif_enabled(struct vcpu_svm *svm)
|
||||||
|
{
|
||||||
|
return !!(svm->vmcb->control.int_ctl & V_GIF_ENABLE_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void enable_gif(struct vcpu_svm *svm)
|
static inline void enable_gif(struct vcpu_svm *svm)
|
||||||
{
|
{
|
||||||
|
if (vgif_enabled(svm))
|
||||||
|
svm->vmcb->control.int_ctl |= V_GIF_MASK;
|
||||||
|
else
|
||||||
svm->vcpu.arch.hflags |= HF_GIF_MASK;
|
svm->vcpu.arch.hflags |= HF_GIF_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void disable_gif(struct vcpu_svm *svm)
|
static inline void disable_gif(struct vcpu_svm *svm)
|
||||||
{
|
{
|
||||||
|
if (vgif_enabled(svm))
|
||||||
|
svm->vmcb->control.int_ctl &= ~V_GIF_MASK;
|
||||||
|
else
|
||||||
svm->vcpu.arch.hflags &= ~HF_GIF_MASK;
|
svm->vcpu.arch.hflags &= ~HF_GIF_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool gif_set(struct vcpu_svm *svm)
|
static inline bool gif_set(struct vcpu_svm *svm)
|
||||||
{
|
{
|
||||||
|
if (vgif_enabled(svm))
|
||||||
|
return !!(svm->vmcb->control.int_ctl & V_GIF_MASK);
|
||||||
|
else
|
||||||
return !!(svm->vcpu.arch.hflags & HF_GIF_MASK);
|
return !!(svm->vcpu.arch.hflags & HF_GIF_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -969,6 +987,7 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
|
||||||
static void disable_nmi_singlestep(struct vcpu_svm *svm)
|
static void disable_nmi_singlestep(struct vcpu_svm *svm)
|
||||||
{
|
{
|
||||||
svm->nmi_singlestep = false;
|
svm->nmi_singlestep = false;
|
||||||
|
|
||||||
if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) {
|
if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) {
|
||||||
/* Clear our flags if they were not set by the guest */
|
/* Clear our flags if they were not set by the guest */
|
||||||
if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF))
|
if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF))
|
||||||
|
@ -1106,6 +1125,13 @@ static __init int svm_hardware_setup(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vgif) {
|
||||||
|
if (!boot_cpu_has(X86_FEATURE_VGIF))
|
||||||
|
vgif = false;
|
||||||
|
else
|
||||||
|
pr_info("Virtual GIF supported\n");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -1303,6 +1329,12 @@ static void init_vmcb(struct vcpu_svm *svm)
|
||||||
svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
|
svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vgif) {
|
||||||
|
clr_intercept(svm, INTERCEPT_STGI);
|
||||||
|
clr_intercept(svm, INTERCEPT_CLGI);
|
||||||
|
svm->vmcb->control.int_ctl |= V_GIF_ENABLE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
mark_all_dirty(svm->vmcb);
|
mark_all_dirty(svm->vmcb);
|
||||||
|
|
||||||
enable_gif(svm);
|
enable_gif(svm);
|
||||||
|
@ -3133,6 +3165,13 @@ static int stgi_interception(struct vcpu_svm *svm)
|
||||||
if (nested_svm_check_permissions(svm))
|
if (nested_svm_check_permissions(svm))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If VGIF is enabled, the STGI intercept is only added to
|
||||||
|
* detect the opening of the NMI window; remove it now.
|
||||||
|
*/
|
||||||
|
if (vgif_enabled(svm))
|
||||||
|
clr_intercept(svm, INTERCEPT_STGI);
|
||||||
|
|
||||||
svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
|
svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
|
||||||
ret = kvm_skip_emulated_instruction(&svm->vcpu);
|
ret = kvm_skip_emulated_instruction(&svm->vcpu);
|
||||||
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
||||||
|
@ -4668,9 +4707,11 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
|
||||||
* In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
|
* In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
|
||||||
* 1, because that's a separate STGI/VMRUN intercept. The next time we
|
* 1, because that's a separate STGI/VMRUN intercept. The next time we
|
||||||
* get that intercept, this function will be called again though and
|
* get that intercept, this function will be called again though and
|
||||||
* we'll get the vintr intercept.
|
* we'll get the vintr intercept. However, if the vGIF feature is
|
||||||
|
* enabled, the STGI interception will not occur. Enable the irq
|
||||||
|
* window under the assumption that the hardware will set the GIF.
|
||||||
*/
|
*/
|
||||||
if (gif_set(svm) && nested_svm_intr(svm)) {
|
if ((vgif_enabled(svm) || gif_set(svm)) && nested_svm_intr(svm)) {
|
||||||
svm_set_vintr(svm);
|
svm_set_vintr(svm);
|
||||||
svm_inject_irq(svm, 0x0);
|
svm_inject_irq(svm, 0x0);
|
||||||
}
|
}
|
||||||
|
@ -4684,8 +4725,11 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
|
||||||
== HF_NMI_MASK)
|
== HF_NMI_MASK)
|
||||||
return; /* IRET will cause a vm exit */
|
return; /* IRET will cause a vm exit */
|
||||||
|
|
||||||
if ((svm->vcpu.arch.hflags & HF_GIF_MASK) == 0)
|
if (!gif_set(svm)) {
|
||||||
|
if (vgif_enabled(svm))
|
||||||
|
set_intercept(svm, INTERCEPT_STGI);
|
||||||
return; /* STGI will cause a vm exit */
|
return; /* STGI will cause a vm exit */
|
||||||
|
}
|
||||||
|
|
||||||
if (svm->nested.exit_required)
|
if (svm->nested.exit_required)
|
||||||
return; /* we're not going to run the guest yet */
|
return; /* we're not going to run the guest yet */
|
||||||
|
|
Loading…
Reference in New Issue