-
-
Save Yamagi/de70c08eadeeef14eec4cb42aeb5957f to your computer and use it in GitHub Desktop.
Untangle TPR shadowing and APIC virtualization on VT-x (against 13-CURRENT r355978)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c | |
index 605fd0bda766..324a1e9d0c3c 100644 | |
--- a/sys/amd64/vmm/intel/vmx.c | |
+++ b/sys/amd64/vmm/intel/vmx.c | |
@@ -172,6 +172,10 @@ static int cap_invpcid; | |
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, invpcid, CTLFLAG_RD, &cap_invpcid, | |
0, "Guests are allowed to use INVPCID"); | |
+static int tpr_shadowing; | |
+SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, tpr_shadowing, CTLFLAG_RD, | |
+ &tpr_shadowing, 0, "TPR shadowin support"); | |
+ | |
static int virtual_interrupt_delivery; | |
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD, | |
&virtual_interrupt_delivery, 0, "APICv virtual interrupt delivery support"); | |
@@ -627,7 +631,7 @@ vmx_restore(void) | |
static int | |
vmx_init(int ipinum) | |
{ | |
- int error, use_tpr_shadow; | |
+ int error; | |
uint64_t basic, fixed0, fixed1, feature_control; | |
uint32_t tmp, procbased2_vid_bits; | |
@@ -750,6 +754,24 @@ vmx_init(int ipinum) | |
MSR_VMX_PROCBASED_CTLS2, PROCBASED2_ENABLE_INVPCID, 0, | |
&tmp) == 0); | |
+ /* | |
+ * Check support for TPR shadow. | |
+ */ | |
+ error = vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS, | |
+ MSR_VMX_TRUE_PROCBASED_CTLS, PROCBASED_USE_TPR_SHADOW, 0, | |
+ &tmp); | |
+ if (error == 0) { | |
+ tpr_shadowing = 1; | |
+ TUNABLE_INT_FETCH("hw.vmm.vmx.use_tpr_shadowing", | |
+ &tpr_shadowing); | |
+ } | |
+ | |
+ if (tpr_shadowing) { | |
+ procbased_ctls |= PROCBASED_USE_TPR_SHADOW; | |
+ procbased_ctls &= ~PROCBASED_CR8_LOAD_EXITING; | |
+ procbased_ctls &= ~PROCBASED_CR8_STORE_EXITING; | |
+ } | |
+ | |
/* | |
* Check support for virtual interrupt delivery. | |
*/ | |
@@ -758,13 +780,9 @@ vmx_init(int ipinum) | |
PROCBASED2_APIC_REGISTER_VIRTUALIZATION | | |
PROCBASED2_VIRTUAL_INTERRUPT_DELIVERY); | |
- use_tpr_shadow = (vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS, | |
- MSR_VMX_TRUE_PROCBASED_CTLS, PROCBASED_USE_TPR_SHADOW, 0, | |
- &tmp) == 0); | |
- | |
error = vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS2, MSR_VMX_PROCBASED_CTLS2, | |
procbased2_vid_bits, 0, &tmp); | |
- if (error == 0 && use_tpr_shadow) { | |
+ if (error == 0 && tpr_shadowing) { | |
virtual_interrupt_delivery = 1; | |
TUNABLE_INT_FETCH("hw.vmm.vmx.use_apic_vid", | |
&virtual_interrupt_delivery); | |
@@ -775,13 +793,6 @@ vmx_init(int ipinum) | |
procbased_ctls2 |= procbased2_vid_bits; | |
procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; | |
- /* | |
- * No need to emulate accesses to %CR8 if virtual | |
- * interrupt delivery is enabled. | |
- */ | |
- procbased_ctls &= ~PROCBASED_CR8_LOAD_EXITING; | |
- procbased_ctls &= ~PROCBASED_CR8_STORE_EXITING; | |
- | |
/* | |
* Check for Posted Interrupts only if Virtual Interrupt | |
* Delivery is enabled. | |
@@ -1051,10 +1062,13 @@ vmx_vminit(struct vm *vm, pmap_t pmap) | |
vmx->ctx[i].guest_dr6 = DBREG_DR6_RESERVED1; | |
error += vmwrite(VMCS_GUEST_DR7, DBREG_DR7_RESERVED1); | |
- if (virtual_interrupt_delivery) { | |
- error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS); | |
+ if (tpr_shadowing) { | |
error += vmwrite(VMCS_VIRTUAL_APIC, | |
vtophys(&vmx->apic_page[i])); | |
+ } | |
+ | |
+ if (virtual_interrupt_delivery) { | |
+ error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS); | |
error += vmwrite(VMCS_EOI_EXIT0, 0); | |
error += vmwrite(VMCS_EOI_EXIT1, 0); | |
error += vmwrite(VMCS_EOI_EXIT2, 0); | |
@@ -2313,6 +2327,14 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) | |
} | |
} | |
+ /* | |
+ * If 'TPR shadowing' is used, update the local APICs PPR. | |
+ */ | |
+ if (tpr_shadowing) { | |
+ vlapic = vm_lapic(vmx->vm, vcpu); | |
+ vlapic_update_ppr(vlapic); | |
+ } | |
+ | |
switch (reason) { | |
case EXIT_REASON_TASK_SWITCH: | |
ts = &vmexit->u.task_switch; | |
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c | |
index 74e6cd967396..289fdb7e077d 100644 | |
--- a/sys/amd64/vmm/io/vlapic.c | |
+++ b/sys/amd64/vmm/io/vlapic.c | |
@@ -490,7 +490,7 @@ dump_isrvec_stk(struct vlapic *vlapic) | |
* Algorithm adopted from section "Interrupt, Task and Processor Priority" | |
* in Intel Architecture Manual Vol 3a. | |
*/ | |
-static void | |
+void | |
vlapic_update_ppr(struct vlapic *vlapic) | |
{ | |
int isrvec, tpr, ppr; | |
diff --git a/sys/amd64/vmm/io/vlapic.h b/sys/amd64/vmm/io/vlapic.h | |
index 2a5f54003253..71b97feab6bc 100644 | |
--- a/sys/amd64/vmm/io/vlapic.h | |
+++ b/sys/amd64/vmm/io/vlapic.h | |
@@ -74,6 +74,8 @@ void vlapic_post_intr(struct vlapic *vlapic, int hostcpu, int ipinum); | |
void vlapic_fire_cmci(struct vlapic *vlapic); | |
int vlapic_trigger_lvt(struct vlapic *vlapic, int vector); | |
+void vlapic_update_ppr(struct vlapic *vlapic); | |
+ | |
uint64_t vlapic_get_apicbase(struct vlapic *vlapic); | |
int vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val); | |
void vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state s); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment