Skip to content

Instantly share code, notes, and snippets.

@Yamagi
Created December 21, 2019 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Yamagi/de70c08eadeeef14eec4cb42aeb5957f to your computer and use it in GitHub Desktop.
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)
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