aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-03-10 17:49:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-03-10 17:49:09 +0000
commitfc23be915c5124ad09589fbe792b21f6450186f4 (patch)
treedcbdc99d6d7418843625a63b430257ae1f01fedf
parenta15261d2861796d67bc47c4568c3c28a85eb7638 (diff)
parent1bc51bad2bad362356163a901af4a47e2a71970e (diff)
Notes
-rw-r--r--lib/libusb/libusb_global_linux.h7
-rw-r--r--sys/amd64/vmm/intel/vmx.c91
-rw-r--r--sys/amd64/vmm/io/vlapic.c9
-rw-r--r--sys/amd64/vmm/io/vlapic.h2
-rw-r--r--sys/compat/linux/linux_ioctl.c3
-rw-r--r--sys/compat/linux/linux_ioctl.h3
-rw-r--r--sys/sys/param.h2
7 files changed, 97 insertions, 20 deletions
diff --git a/lib/libusb/libusb_global_linux.h b/lib/libusb/libusb_global_linux.h
index 3753a9fba309..9886bd4486f5 100644
--- a/lib/libusb/libusb_global_linux.h
+++ b/lib/libusb/libusb_global_linux.h
@@ -77,4 +77,11 @@
} while (0)
#endif
+#ifndef TAILQ_FOREACH_SAFE
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+#endif
+
#endif /* _LIBUSB_GLOBAL_LINUX_H_ */
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index e3710af8d863..9f610ea50852 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -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);
error += vmwrite(VMCS_EOI_EXIT2, 0);
@@ -2661,6 +2675,12 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
SDT_PROBE3(vmm, vmx, exit, mwait, vmx, vcpu, vmexit);
vmexit->exitcode = VM_EXITCODE_MWAIT;
break;
+ case EXIT_REASON_TPR:
+ vlapic = vm_lapic(vmx->vm, vcpu);
+ vlapic_sync_tpr(vlapic);
+ vmexit->inst_length = 0;
+ handled = HANDLED;
+ break;
case EXIT_REASON_VMCALL:
case EXIT_REASON_VMCLEAR:
case EXIT_REASON_VMLAUNCH:
@@ -2947,6 +2967,16 @@ vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap,
}
/*
+ * If TPR Shadowing is enabled, the TPR Threshold
+ * must be updated right before entering the guest.
+ */
+ if (tpr_shadowing && !virtual_interrupt_delivery) {
+ if ((vmx->cap[vcpu].proc_ctls & PROCBASED_USE_TPR_SHADOW) != 0) {
+ vmcs_write(VMCS_TPR_THRESHOLD, vlapic_get_cr8(vlapic));
+ }
+ }
+
+ /*
* VM exits restore the base address but not the
* limits of GDTR and IDTR. The VMCS only stores the
* base address, so VM exits set the limits to 0xffff.
@@ -3634,7 +3664,30 @@ vmx_set_tmr(struct vlapic *vlapic, int vector, bool level)
}
static void
-vmx_enable_x2apic_mode(struct vlapic *vlapic)
+vmx_enable_x2apic_mode_ts(struct vlapic *vlapic)
+{
+ struct vmx *vmx;
+ struct vmcs *vmcs;
+ uint32_t proc_ctls;
+ int vcpuid;
+
+ vcpuid = vlapic->vcpuid;
+ vmx = ((struct vlapic_vtx *)vlapic)->vmx;
+ vmcs = &vmx->vmcs[vcpuid];
+
+ proc_ctls = vmx->cap[vcpuid].proc_ctls;
+ proc_ctls &= ~PROCBASED_USE_TPR_SHADOW;
+ proc_ctls |= PROCBASED_CR8_LOAD_EXITING;
+ proc_ctls |= PROCBASED_CR8_STORE_EXITING;
+ vmx->cap[vcpuid].proc_ctls = proc_ctls;
+
+ VMPTRLD(vmcs);
+ vmcs_write(VMCS_PRI_PROC_BASED_CTLS, proc_ctls);
+ VMCLEAR(vmcs);
+}
+
+static void
+vmx_enable_x2apic_mode_vid(struct vlapic *vlapic)
{
struct vmx *vmx;
struct vmcs *vmcs;
@@ -3795,12 +3848,16 @@ vmx_vlapic_init(void *arg, int vcpuid)
vlapic_vtx->pir_desc = &vmx->pir_desc[vcpuid];
vlapic_vtx->vmx = vmx;
+ if (tpr_shadowing) {
+ vlapic->ops.enable_x2apic_mode = vmx_enable_x2apic_mode_ts;
+ }
+
if (virtual_interrupt_delivery) {
vlapic->ops.set_intr_ready = vmx_set_intr_ready;
vlapic->ops.pending_intr = vmx_pending_intr;
vlapic->ops.intr_accepted = vmx_intr_accepted;
vlapic->ops.set_tmr = vmx_set_tmr;
- vlapic->ops.enable_x2apic_mode = vmx_enable_x2apic_mode;
+ vlapic->ops.enable_x2apic_mode = vmx_enable_x2apic_mode_vid;
}
if (posted_interrupts)
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index 74e6cd967396..069989f12386 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -555,6 +555,12 @@ vlapic_update_ppr(struct vlapic *vlapic)
VLAPIC_CTR1(vlapic, "vlapic_update_ppr 0x%02x", ppr);
}
+void
+vlapic_sync_tpr(struct vlapic *vlapic)
+{
+ vlapic_update_ppr(vlapic);
+}
+
static VMM_STAT(VLAPIC_GRATUITOUS_EOI, "EOI without any in-service interrupt");
static void
@@ -1079,6 +1085,8 @@ vlapic_pending_intr(struct vlapic *vlapic, int *vecptr)
int idx, i, bitpos, vector;
uint32_t *irrptr, val;
+ vlapic_update_ppr(vlapic);
+
if (vlapic->ops.pending_intr)
return ((*vlapic->ops.pending_intr)(vlapic, vecptr));
@@ -1136,7 +1144,6 @@ vlapic_intr_accepted(struct vlapic *vlapic, int vector)
panic("isrvec_stk_top overflow %d", stk_top);
vlapic->isrvec_stk[stk_top] = vector;
- vlapic_update_ppr(vlapic);
}
void
diff --git a/sys/amd64/vmm/io/vlapic.h b/sys/amd64/vmm/io/vlapic.h
index 2a5f54003253..bd650efa8cc1 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_sync_tpr(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);
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index 78a48f6586c0..6b46b29547d6 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -3488,6 +3488,9 @@ linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args)
case FBSD_LUSB_GET_POWER_USAGE:
args->cmd = USB_GET_POWER_USAGE;
break;
+ case FBSD_LUSB_DEVICESTATS:
+ args->cmd = USB_DEVICESTATS;
+ break;
default:
error = ENOIOCTL;
}
diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h
index 011df41f29e4..15fd560e116b 100644
--- a/sys/compat/linux/linux_ioctl.h
+++ b/sys/compat/linux/linux_ioctl.h
@@ -743,9 +743,10 @@
#define FBSD_LUSB_FS_OPEN_STREAM 0xffdf
#define FBSD_LUSB_GET_DEV_PORT_PATH 0xffde
#define FBSD_LUSB_GET_POWER_USAGE 0xffdd
+#define FBSD_LUSB_DEVICESTATS 0xffdc
#define FBSD_LUSB_MAX 0xffff
-#define FBSD_LUSB_MIN 0xffdd
+#define FBSD_LUSB_MIN 0xffdc
/*
* Linux btrfs clone operation
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 13742bf3c5ff..cdaaf0e3c89e 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -60,7 +60,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1300082 /* Master, propagated to newvers */
+#define __FreeBSD_version 1300083 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,