Author: mr
Date: Tue Mar 10 16:53:49 2020
New Revision: 358848
URL: https://svnweb.freebsd.org/changeset/base/358848
Log:
Untangle TPR shadowing and APIC virtualization.
This speeds up Windows guests tremendously.
The patch does:
Add a new tuneable 'hw.vmm.vmx.use_tpr_shadowing' to disable TLP shadowing.
Also add 'hw.vmm.vmx.cap.tpr_shadowing' to be able to query if TPR shadowing
is used.
Detach the initialization of TPR shadowing from the initialization of APIC
virtualization.
APIC virtualization still needs TPR shadowing, but not vice versa.
Any CPU that supports APIC virtualization should also support TPR shadowing.
When TPR shadowing is used, the APIC page of each vCPU is written to the
VMCS_VIRTUAL_APIC field of the VMCS
so that the CPU can write directly to the page without intercept.
On vm exit, vlapic_update_ppr() is called to update the PPR.
Submitted by: Yamagi Burmeister
MFC after:2 weeks
Differential Revision:https://reviews.freebsd.org/D22942
Modified:
head/sys/amd64/vmm/intel/vmx.c
head/sys/amd64/vmm/io/vlapic.c
head/sys/amd64/vmm/io/vlapic.h
Modified: head/sys/amd64/vmm/intel/vmx.c
==
--- head/sys/amd64/vmm/intel/vmx.c Tue Mar 10 16:36:07 2020
(r358847)
+++ head/sys/amd64/vmm/intel/vmx.c Tue Mar 10 16:53:49 2020
(r358848)
@@ -175,6 +175,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 shadowing 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");
@@ -630,7 +634,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;
@@ -754,6 +758,24 @@ vmx_init(int ipinum)
&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.
*/
procbased2_vid_bits = (PROCBASED2_VIRTUALIZE_APIC_ACCESSES |
@@ -761,13 +783,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);
@@ -779,13 +797,6 @@ vmx_init(int ipinum)
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.
*/
@@ -1054,10 +1065,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);