Skip to content

Commit 4d1d794

Browse files
ssuthiku-amdbonzini
authored andcommitted
KVM: SVM: Introduce logic to (de)activate x2AVIC mode
Introduce logic to (de)activate AVIC, which also allows switching between AVIC to x2AVIC mode at runtime. When an AVIC-enabled guest switches from APIC to x2APIC mode, the SVM driver needs to perform the following steps: 1. Set the x2APIC mode bit for AVIC in VMCB along with the maximum APIC ID support for each mode accodingly. 2. Disable x2APIC MSRs interception in order to allow the hardware to virtualize x2APIC MSRs accesses. Reported-by: kernel test robot <[email protected]> Reviewed-by: Maxim Levitsky <[email protected]> Signed-off-by: Suravee Suthikulpanit <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 7a8f7c1 commit 4d1d794

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

arch/x86/include/asm/svm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ enum avic_ipi_failure_cause {
256256
AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
257257
};
258258

259+
#define AVIC_PHYSICAL_MAX_INDEX_MASK GENMASK_ULL(9, 0)
259260

260261
/*
261262
* For AVIC, the max index allowed for physical APIC ID

arch/x86/kvm/svm/avic.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ struct amd_svm_iommu_ir {
6363
void *data; /* Storing pointer to struct amd_ir_data */
6464
};
6565

66+
static void avic_activate_vmcb(struct vcpu_svm *svm)
67+
{
68+
struct vmcb *vmcb = svm->vmcb01.ptr;
69+
70+
vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK);
71+
vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK;
72+
73+
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
74+
if (apic_x2apic_mode(svm->vcpu.arch.apic)) {
75+
vmcb->control.int_ctl |= X2APIC_MODE_MASK;
76+
vmcb->control.avic_physical_id |= X2AVIC_MAX_PHYSICAL_ID;
77+
/* Disabling MSR intercept for x2APIC registers */
78+
svm_set_x2apic_msr_interception(svm, false);
79+
} else {
80+
vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID;
81+
/* Enabling MSR intercept for x2APIC registers */
82+
svm_set_x2apic_msr_interception(svm, true);
83+
}
84+
}
85+
86+
static void avic_deactivate_vmcb(struct vcpu_svm *svm)
87+
{
88+
struct vmcb *vmcb = svm->vmcb01.ptr;
89+
90+
vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK);
91+
vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK;
92+
93+
/* Enabling MSR intercept for x2APIC registers */
94+
svm_set_x2apic_msr_interception(svm, true);
95+
}
6696

6797
/* Note:
6898
* This function is called from IOMMU driver to notify
@@ -179,13 +209,12 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb)
179209
vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK;
180210
vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
181211
vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
182-
vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID;
183212
vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE & VMCB_AVIC_APIC_BAR_MASK;
184213

185214
if (kvm_apicv_activated(svm->vcpu.kvm))
186-
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
215+
avic_activate_vmcb(svm);
187216
else
188-
vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
217+
avic_deactivate_vmcb(svm);
189218
}
190219

191220
static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu,
@@ -1049,9 +1078,9 @@ void avic_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
10491078
* accordingly before re-activating.
10501079
*/
10511080
avic_apicv_post_state_restore(vcpu);
1052-
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
1081+
avic_activate_vmcb(svm);
10531082
} else {
1054-
vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
1083+
avic_deactivate_vmcb(svm);
10551084
}
10561085
vmcb_mark_dirty(vmcb, VMCB_AVIC);
10571086

arch/x86/kvm/svm/svm.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,24 @@ void svm_vcpu_init_msrpm(struct kvm_vcpu *vcpu, u32 *msrpm)
805805
}
806806
}
807807

808+
void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept)
809+
{
810+
int i;
811+
812+
if (avic_mode != AVIC_MODE_X2 ||
813+
!apic_x2apic_mode(svm->vcpu.arch.apic))
814+
return;
815+
816+
for (i = 0; i < MAX_DIRECT_ACCESS_MSRS; i++) {
817+
int index = direct_access_msrs[i].index;
818+
819+
if ((index < APIC_BASE_MSR) ||
820+
(index > APIC_BASE_MSR + 0xff))
821+
continue;
822+
set_msr_interception(&svm->vcpu, svm->msrpm, index,
823+
!intercept, !intercept);
824+
}
825+
}
808826

809827
void svm_vcpu_free_msrpm(u32 *msrpm)
810828
{

arch/x86/kvm/svm/svm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ void svm_set_gif(struct vcpu_svm *svm, bool value);
555555
int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code);
556556
void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
557557
int read, int write);
558+
void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool disable);
558559
void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode,
559560
int trig_mode, int vec);
560561

0 commit comments

Comments
 (0)