From owner-p4-projects@FreeBSD.ORG Sat Jan 18 21:23:12 2014 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 6AE26795; Sat, 18 Jan 2014 21:23:12 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 09EF578F for ; Sat, 18 Jan 2014 21:23:12 +0000 (UTC) Received: from skunkworks.freebsd.org (skunkworks.freebsd.org [IPv6:2001:1900:2254:2068::682:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id E6D09125A for ; Sat, 18 Jan 2014 21:23:11 +0000 (UTC) Received: from skunkworks.freebsd.org ([127.0.1.74]) by skunkworks.freebsd.org (8.14.7/8.14.7) with ESMTP id s0ILNBa1016956 for ; Sat, 18 Jan 2014 21:23:11 GMT (envelope-from jhb@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.7/8.14.7/Submit) id s0ILNBX2016953 for perforce@freebsd.org; Sat, 18 Jan 2014 21:23:11 GMT (envelope-from jhb@freebsd.org) Date: Sat, 18 Jan 2014 21:23:11 GMT Message-Id: <201401182123.s0ILNBX2016953@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to jhb@freebsd.org using -f From: John Baldwin Subject: PERFORCE change 1190142 for review To: Perforce Change Reviews Precedence: bulk X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.17 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 18 Jan 2014 21:23:12 -0000 http://p4web.freebsd.org/@@1190142?ac=10 Change 1190142 by jhb@jhb_pippin on 2014/01/18 21:22:36 IFC @1190140 Affected files ... .. //depot/projects/pci/sys/amd64/amd64/identcpu.c#9 integrate .. //depot/projects/pci/sys/amd64/conf/NOTES#12 integrate .. //depot/projects/pci/sys/amd64/include/vmm.h#8 integrate .. //depot/projects/pci/sys/amd64/vmm/amd/amdv.c#5 integrate .. //depot/projects/pci/sys/amd64/vmm/intel/vmcs.c#7 integrate .. //depot/projects/pci/sys/amd64/vmm/intel/vmcs.h#7 integrate .. //depot/projects/pci/sys/amd64/vmm/intel/vmx.c#9 integrate .. //depot/projects/pci/sys/amd64/vmm/intel/vmx.h#6 integrate .. //depot/projects/pci/sys/amd64/vmm/intel/vmx_genassym.c#6 integrate .. //depot/projects/pci/sys/amd64/vmm/intel/vmx_support.S#4 integrate .. //depot/projects/pci/sys/amd64/vmm/io/vioapic.c#3 integrate .. //depot/projects/pci/sys/amd64/vmm/io/vlapic.c#6 integrate .. //depot/projects/pci/sys/amd64/vmm/io/vlapic.h#5 integrate .. //depot/projects/pci/sys/amd64/vmm/vmm.c#8 integrate .. //depot/projects/pci/sys/amd64/vmm/vmm_stat.c#3 integrate .. //depot/projects/pci/sys/amd64/vmm/vmm_stat.h#3 integrate .. //depot/projects/pci/sys/arm/at91/at91_gpio.h#1 branch .. //depot/projects/pci/sys/arm/at91/at91rm9200.c#4 integrate .. //depot/projects/pci/sys/arm/at91/at91sam9260.c#3 integrate .. //depot/projects/pci/sys/arm/at91/at91sam9g20.c#3 integrate .. //depot/projects/pci/sys/arm/at91/at91sam9g45.c#2 integrate .. //depot/projects/pci/sys/arm/at91/at91sam9x5.c#2 integrate .. //depot/projects/pci/sys/arm/at91/at91var.h#3 integrate .. //depot/projects/pci/sys/arm/freescale/imx/imx51_ipuv3_fbd.c#2 integrate .. //depot/projects/pci/sys/cam/cam_periph.c#13 integrate .. //depot/projects/pci/sys/cam/cam_periph.h#8 integrate .. //depot/projects/pci/sys/cam/cam_xpt.c#15 integrate .. //depot/projects/pci/sys/cam/scsi/scsi_xpt.c#10 integrate .. //depot/projects/pci/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c#9 integrate .. //depot/projects/pci/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c#6 integrate .. //depot/projects/pci/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c#6 integrate .. //depot/projects/pci/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c#7 integrate .. //depot/projects/pci/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c#12 integrate .. //depot/projects/pci/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c#9 integrate .. //depot/projects/pci/sys/compat/freebsd32/freebsd32_misc.c#14 integrate .. //depot/projects/pci/sys/conf/files.amd64#13 integrate .. //depot/projects/pci/sys/conf/files.i386#15 integrate .. //depot/projects/pci/sys/contrib/dev/iwn/iwlwifi-105-6-18.168.6.1.fw.uu#1 branch .. //depot/projects/pci/sys/contrib/ipfilter/netinet/ip_compat.h#6 integrate .. //depot/projects/pci/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c#4 integrate .. //depot/projects/pci/sys/dev/ahci/ahci.c#16 integrate .. //depot/projects/pci/sys/dev/altera/atse/if_atse.c#2 integrate .. //depot/projects/pci/sys/dev/bxe/bxe.c#6 integrate .. //depot/projects/pci/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c#4 integrate .. //depot/projects/pci/sys/dev/netmap/netmap.c#7 integrate .. //depot/projects/pci/sys/dev/netmap/netmap_generic.c#3 integrate .. //depot/projects/pci/sys/dev/netmap/netmap_vale.c#3 integrate .. //depot/projects/pci/sys/dev/qlxge/qls_os.c#2 integrate .. //depot/projects/pci/sys/dev/usb/controller/ehci.c#9 integrate .. //depot/projects/pci/sys/dev/usb/controller/uhci.c#6 integrate .. //depot/projects/pci/sys/dev/usb/controller/xhci.c#11 integrate .. //depot/projects/pci/sys/dev/usb/input/ukbd.c#11 integrate .. //depot/projects/pci/sys/dev/usb/net/uhso.c#9 integrate .. //depot/projects/pci/sys/dev/usb/serial/u3g.c#9 integrate .. //depot/projects/pci/sys/dev/usb/serial/umcs.c#5 integrate .. //depot/projects/pci/sys/dev/usb/usb_dev.c#6 integrate .. //depot/projects/pci/sys/dev/usb/usb_device.c#8 integrate .. //depot/projects/pci/sys/dev/usb/usb_device.h#8 integrate .. //depot/projects/pci/sys/dev/usb/usb_hub.c#11 integrate .. //depot/projects/pci/sys/dev/usb/usb_hub.h#4 integrate .. //depot/projects/pci/sys/dev/usb/usb_request.c#8 integrate .. //depot/projects/pci/sys/dev/usb/usb_transfer.c#8 integrate .. //depot/projects/pci/sys/dev/usb/wlan/if_run.c#12 integrate .. //depot/projects/pci/sys/dev/virtio/block/virtio_blk.c#5 integrate .. //depot/projects/pci/sys/dev/virtio/random/virtio_random.c#1 branch .. //depot/projects/pci/sys/dev/virtio/scsi/virtio_scsi.c#4 integrate .. //depot/projects/pci/sys/dev/vt/hw/xboxfb/xboxfb.c#3 integrate .. //depot/projects/pci/sys/fs/ext2fs/ext2_inode_cnv.c#7 integrate .. //depot/projects/pci/sys/fs/nfs/nfs_var.h#12 integrate .. //depot/projects/pci/sys/fs/nfsserver/nfs_nfsdcache.c#9 integrate .. //depot/projects/pci/sys/fs/nfsserver/nfs_nfsdkrpc.c#8 integrate .. //depot/projects/pci/sys/geom/uncompress/g_uncompress.c#3 integrate .. //depot/projects/pci/sys/i386/conf/NOTES#11 integrate .. //depot/projects/pci/sys/i386/i386/identcpu.c#8 integrate .. //depot/projects/pci/sys/ia64/ia64/exception.S#7 integrate .. //depot/projects/pci/sys/kern/kern_event.c#11 integrate .. //depot/projects/pci/sys/kern/subr_sglist.c#3 integrate .. //depot/projects/pci/sys/kern/uipc_mbuf.c#9 integrate .. //depot/projects/pci/sys/kern/uipc_sockbuf.c#7 integrate .. //depot/projects/pci/sys/kern/uipc_socket.c#9 integrate .. //depot/projects/pci/sys/kern/uipc_syscalls.c#14 integrate .. //depot/projects/pci/sys/mips/cavium/ciu.c#4 integrate .. //depot/projects/pci/sys/modules/geom/Makefile#4 integrate .. //depot/projects/pci/sys/modules/geom/geom_uncompress/Makefile#3 integrate .. //depot/projects/pci/sys/modules/iwnfw/Makefile#7 integrate .. //depot/projects/pci/sys/modules/iwnfw/iwn105/Makefile#1 branch .. //depot/projects/pci/sys/modules/sound/driver/ai2s/Makefile#3 integrate .. //depot/projects/pci/sys/modules/virtio/Makefile#3 integrate .. //depot/projects/pci/sys/modules/virtio/random/Makefile#1 branch .. //depot/projects/pci/sys/net/netmap_user.h#6 integrate .. //depot/projects/pci/sys/net80211/ieee80211_mesh.c#11 integrate .. //depot/projects/pci/sys/netinet/in.c#12 integrate .. //depot/projects/pci/sys/netinet/in_mcast.c#8 integrate .. //depot/projects/pci/sys/netinet/ip_output.c#13 integrate .. //depot/projects/pci/sys/netinet6/in6.c#14 integrate .. //depot/projects/pci/sys/netinet6/in6_ifattach.c#10 integrate .. //depot/projects/pci/sys/netinet6/in6_var.h#8 integrate .. //depot/projects/pci/sys/netinet6/nd6_rtr.c#9 integrate .. //depot/projects/pci/sys/netpfil/ipfw/ip_fw_nat.c#4 integrate .. //depot/projects/pci/sys/powerpc/include/atomic.h#4 integrate .. //depot/projects/pci/sys/powerpc/powermac/macgpio.c#3 integrate .. //depot/projects/pci/sys/powerpc/powermac/macgpiovar.h#3 integrate .. //depot/projects/pci/sys/sys/mbuf.h#10 integrate .. //depot/projects/pci/sys/sys/random.h#6 integrate .. //depot/projects/pci/sys/sys/sf_base.h#2 integrate .. //depot/projects/pci/sys/sys/sf_sync.h#2 integrate .. //depot/projects/pci/sys/sys/sglist.h#3 integrate .. //depot/projects/pci/sys/sys/socket.h#8 integrate .. //depot/projects/pci/sys/vm/vm_pageout.c#11 integrate Differences ... ==== //depot/projects/pci/sys/amd64/amd64/identcpu.c#9 (text+ko) ==== @@ -39,7 +39,7 @@ */ #include -__FBSDID("$FreeBSD: head/sys/amd64/amd64/identcpu.c 257856 2013-11-08 16:32:30Z kib $"); +__FBSDID("$FreeBSD: head/sys/amd64/amd64/identcpu.c 260557 2014-01-11 22:41:10Z gavin $"); #include "opt_cpu.h" @@ -206,16 +206,16 @@ } printf("-class CPU)\n"); if (*cpu_vendor) - printf(" Origin = \"%s\"", cpu_vendor); + printf(" Origin=\"%s\"", cpu_vendor); if (cpu_id) - printf(" Id = 0x%x", cpu_id); + printf(" Id=0x%x", cpu_id); if (cpu_vendor_id == CPU_VENDOR_INTEL || cpu_vendor_id == CPU_VENDOR_AMD || cpu_vendor_id == CPU_VENDOR_CENTAUR) { - printf(" Family = 0x%x", CPUID_TO_FAMILY(cpu_id)); - printf(" Model = 0x%x", CPUID_TO_MODEL(cpu_id)); - printf(" Stepping = %u", cpu_id & CPUID_STEPPING); + printf(" Family=0x%x", CPUID_TO_FAMILY(cpu_id)); + printf(" Model=0x%x", CPUID_TO_MODEL(cpu_id)); + printf(" Stepping=%u", cpu_id & CPUID_STEPPING); /* * AMD CPUID Specification ==== //depot/projects/pci/sys/amd64/conf/NOTES#12 (text+ko) ==== @@ -4,7 +4,7 @@ # This file contains machine dependent kernel configuration notes. For # machine independent notes, look in /sys/conf/NOTES. # -# $FreeBSD: head/sys/amd64/conf/NOTES 260376 2014-01-06 17:23:22Z schweikh $ +# $FreeBSD: head/sys/amd64/conf/NOTES 260847 2014-01-18 06:14:38Z bryanv $ # # @@ -472,6 +472,7 @@ device virtio_blk # VirtIO Block device device virtio_scsi # VirtIO SCSI device device virtio_balloon # VirtIO Memory Balloon device +device virtio_random # VirtIO Entropy device device hyperv # HyperV drivers ==== //depot/projects/pci/sys/amd64/include/vmm.h#8 (text+ko) ==== @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/include/vmm.h 260466 2014-01-09 03:25:54Z neel $ + * $FreeBSD: head/sys/amd64/include/vmm.h 260619 2014-01-14 01:55:58Z neel $ */ #ifndef _VMM_H_ @@ -52,7 +52,7 @@ typedef void (*vmm_resume_func_t)(void); typedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap); typedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip, - struct pmap *pmap); + struct pmap *pmap, void *rendezvous_cookie); typedef void (*vmi_cleanup_func_t)(void *vmi); typedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num, uint64_t *retval); @@ -136,6 +136,31 @@ struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); /* + * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'. + * The rendezvous 'func(arg)' is not allowed to do anything that will + * cause the thread to be put to sleep. + * + * If the rendezvous is being initiated from a vcpu context then the + * 'vcpuid' must refer to that vcpu, otherwise it should be set to -1. + * + * The caller cannot hold any locks when initiating the rendezvous. + * + * The implementation of this API may cause vcpus other than those specified + * by 'dest' to be stalled. The caller should not rely on any vcpus making + * forward progress when the rendezvous is in progress. + */ +typedef void (*vm_rendezvous_func_t)(struct vm *vm, int vcpuid, void *arg); +void vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest, + vm_rendezvous_func_t func, void *arg); + +static __inline int +vcpu_rendezvous_pending(void *rendezvous_cookie) +{ + + return (*(uintptr_t *)rendezvous_cookie != 0); +} + +/* * Return 1 if device indicated by bus/slot/func is supposed to be a * pci passthrough device. * @@ -272,6 +297,7 @@ VM_EXITCODE_INST_EMUL, VM_EXITCODE_SPINUP_AP, VM_EXITCODE_SPINDOWN_CPU, + VM_EXITCODE_RENDEZVOUS, VM_EXITCODE_MAX }; ==== //depot/projects/pci/sys/amd64/vmm/amd/amdv.c#5 (text+ko) ==== @@ -23,11 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/amd/amdv.c 260466 2014-01-09 03:25:54Z neel $ + * $FreeBSD: head/sys/amd64/vmm/amd/amdv.c 260619 2014-01-14 01:55:58Z neel $ */ #include -__FBSDID("$FreeBSD: head/sys/amd64/vmm/amd/amdv.c 260466 2014-01-09 03:25:54Z neel $"); +__FBSDID("$FreeBSD: head/sys/amd64/vmm/amd/amdv.c 260619 2014-01-14 01:55:58Z neel $"); #include #include @@ -67,7 +67,7 @@ } static int -amdv_vmrun(void *arg, int vcpu, register_t rip, struct pmap *pmap) +amdv_vmrun(void *arg, int vcpu, register_t rip, struct pmap *pmap, void *cookie) { printf("amdv_vmrun: not implemented\n"); ==== //depot/projects/pci/sys/amd64/vmm/intel/vmcs.c#7 (text+ko) ==== @@ -23,13 +23,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/intel/vmcs.c 260380 2014-01-06 23:16:39Z neel $ + * $FreeBSD: head/sys/amd64/vmm/intel/vmcs.c 260531 2014-01-11 03:14:05Z neel $ */ #include "opt_ddb.h" #include -__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmcs.c 260380 2014-01-06 23:16:39Z neel $"); +__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmcs.c 260531 2014-01-11 03:14:05Z neel $"); #include #include @@ -473,7 +473,7 @@ switch (exit & 0x8000ffff) { case EXIT_REASON_EXCEPTION: case EXIT_REASON_EXT_INTR: - val = vmcs_read(VMCS_EXIT_INTERRUPTION_INFO); + val = vmcs_read(VMCS_EXIT_INTR_INFO); db_printf("Interrupt Type: "); switch (val >> 8 & 0x7) { case 0: @@ -495,7 +495,7 @@ db_printf(" Vector: %lu", val & 0xff); if (val & 0x800) db_printf(" Error Code: %lx", - vmcs_read(VMCS_EXIT_INTERRUPTION_ERROR)); + vmcs_read(VMCS_EXIT_INTR_ERRCODE)); db_printf("\n"); break; case EXIT_REASON_EPT_FAULT: ==== //depot/projects/pci/sys/amd64/vmm/intel/vmcs.h#7 (text+ko) ==== @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/intel/vmcs.h 260410 2014-01-07 21:04:49Z neel $ + * $FreeBSD: head/sys/amd64/vmm/intel/vmcs.h 260836 2014-01-18 02:20:10Z neel $ */ #ifndef _VMCS_H_ @@ -97,6 +97,7 @@ /* 16-bit control fields */ #define VMCS_VPID 0x00000000 +#define VMCS_PIR_VECTOR 0x00000002 /* 16-bit guest-state fields */ #define VMCS_GUEST_ES_SELECTOR 0x00000800 @@ -129,6 +130,7 @@ #define VMCS_TSC_OFFSET 0x00002010 #define VMCS_VIRTUAL_APIC 0x00002012 #define VMCS_APIC_ACCESS 0x00002014 +#define VMCS_PIR_DESC 0x00002016 #define VMCS_EPTP 0x0000201A #define VMCS_EOI_EXIT0 0x0000201C #define VMCS_EOI_EXIT1 0x0000201E @@ -177,8 +179,8 @@ /* 32-bit read-only data fields */ #define VMCS_INSTRUCTION_ERROR 0x00004400 #define VMCS_EXIT_REASON 0x00004402 -#define VMCS_EXIT_INTERRUPTION_INFO 0x00004404 -#define VMCS_EXIT_INTERRUPTION_ERROR 0x00004406 +#define VMCS_EXIT_INTR_INFO 0x00004404 +#define VMCS_EXIT_INTR_ERRCODE 0x00004406 #define VMCS_IDT_VECTORING_INFO 0x00004408 #define VMCS_IDT_VECTORING_ERROR 0x0000440A #define VMCS_EXIT_INSTRUCTION_LENGTH 0x0000440C @@ -329,11 +331,18 @@ #define EXIT_REASON_APIC_WRITE 56 /* + * NMI unblocking due to IRET. + * + * Applies to VM-exits due to hardware exception or EPT fault. + */ +#define EXIT_QUAL_NMIUDTI (1 << 12) +/* * VMCS interrupt information fields */ -#define VMCS_INTERRUPTION_INFO_VALID (1U << 31) -#define VMCS_INTERRUPTION_INFO_HW_INTR (0 << 8) -#define VMCS_INTERRUPTION_INFO_NMI (2 << 8) +#define VMCS_INTR_VALID (1U << 31) +#define VMCS_INTR_T_MASK 0x700 /* Interruption-info type */ +#define VMCS_INTR_T_HWINTR (0 << 8) +#define VMCS_INTR_T_NMI (2 << 8) /* * VMCS IDT-Vectoring information fields ==== //depot/projects/pci/sys/amd64/vmm/intel/vmx.c#9 (text+ko) ==== @@ -23,11 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/intel/vmx.c 260466 2014-01-09 03:25:54Z neel $ + * $FreeBSD: head/sys/amd64/vmm/intel/vmx.c 260836 2014-01-18 02:20:10Z neel $ */ #include -__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmx.c 260466 2014-01-09 03:25:54Z neel $"); +__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmx.c 260836 2014-01-18 02:20:10Z neel $"); #include #include @@ -45,11 +45,13 @@ #include #include #include +#include #include #include #include #include "vmm_host.h" +#include "vmm_ipi.h" #include "vmm_msr.h" #include "vmm_ktr.h" #include "vmm_stat.h" @@ -93,6 +95,7 @@ #define VM_EXIT_CTLS_ONE_SETTING \ (VM_EXIT_CTLS_ONE_SETTING_NO_PAT | \ + VM_EXIT_ACKNOWLEDGE_INTERRUPT | \ VM_EXIT_SAVE_PAT | \ VM_EXIT_LOAD_PAT) #define VM_EXIT_CTLS_ZERO_SETTING VM_EXIT_SAVE_DEBUG_CONTROLS @@ -171,6 +174,14 @@ SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD, &virtual_interrupt_delivery, 0, "APICv virtual interrupt delivery support"); +static int posted_interrupts; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupts, CTLFLAG_RD, + &posted_interrupts, 0, "APICv posted interrupt support"); + +static int pirvec; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupt_vector, CTLFLAG_RD, + &pirvec, 0, "APICv posted interrupt vector"); + static struct unrhdr *vpid_unr; static u_int vpid_alloc_failed; SYSCTL_UINT(_hw_vmm_vmx, OID_AUTO, vpid_alloc_failed, CTLFLAG_RD, @@ -441,6 +452,9 @@ static int vmx_cleanup(void) { + + if (pirvec != 0) + vmm_ipi_free(pirvec); if (vpid_unr != NULL) { delete_unrhdr(vpid_unr); @@ -636,8 +650,32 @@ procbased_ctls |= PROCBASED_USE_TPR_SHADOW; procbased_ctls2 |= procbased2_vid_bits; procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; + + /* + * Check for Posted Interrupts only if Virtual Interrupt + * Delivery is enabled. + */ + error = vmx_set_ctlreg(MSR_VMX_PINBASED_CTLS, + MSR_VMX_TRUE_PINBASED_CTLS, PINBASED_POSTED_INTERRUPT, 0, + &tmp); + if (error == 0) { + pirvec = vmm_ipi_alloc(); + if (pirvec == 0) { + if (bootverbose) { + printf("vmx_init: unable to allocate " + "posted interrupt vector\n"); + } + } else { + posted_interrupts = 1; + TUNABLE_INT_FETCH("hw.vmm.vmx.use_apic_pir", + &posted_interrupts); + } + } } + if (posted_interrupts) + pinbased_ctls |= PINBASED_POSTED_INTERRUPT; + /* Initialize EPT */ error = ept_init(ipinum); if (error) { @@ -680,6 +718,31 @@ return (0); } +static void +vmx_trigger_hostintr(int vector) +{ + uintptr_t func; + struct gate_descriptor *gd; + + gd = &idt[vector]; + + KASSERT(vector >= 32 && vector <= 255, ("vmx_trigger_hostintr: " + "invalid vector %d", vector)); + KASSERT(gd->gd_p == 1, ("gate descriptor for vector %d not present", + vector)); + KASSERT(gd->gd_type == SDT_SYSIGT, ("gate descriptor for vector %d " + "has invalid type %d", vector, gd->gd_type)); + KASSERT(gd->gd_dpl == SEL_KPL, ("gate descriptor for vector %d " + "has invalid dpl %d", vector, gd->gd_dpl)); + KASSERT(gd->gd_selector == GSEL(GCODE_SEL, SEL_KPL), ("gate descriptor " + "for vector %d has invalid selector %d", vector, gd->gd_selector)); + KASSERT(gd->gd_ist == 0, ("gate descriptor for vector %d has invalid " + "IST %d", vector, gd->gd_ist)); + + func = ((long)gd->gd_hioffset << 16 | gd->gd_looffset); + vmx_call_isr(func); +} + static int vmx_setup_cr_shadow(int which, struct vmcs *vmcs, uint32_t initial) { @@ -822,6 +885,11 @@ error += vmwrite(VMCS_EOI_EXIT2, 0); error += vmwrite(VMCS_EOI_EXIT3, 0); } + if (posted_interrupts) { + error += vmwrite(VMCS_PIR_VECTOR, pirvec); + error += vmwrite(VMCS_PIR_DESC, + vtophys(&vmx->pir_desc[i])); + } VMCLEAR(vmcs); KASSERT(error == 0, ("vmx_vminit: error customizing the vmcs")); @@ -997,7 +1065,7 @@ * Inject the virtual NMI. The vector must be the NMI IDT entry * or the VMCS entry check will fail. */ - info = VMCS_INTERRUPTION_INFO_NMI | VMCS_INTERRUPTION_INFO_VALID; + info = VMCS_INTR_T_NMI | VMCS_INTR_VALID; info |= IDT_NMI; vmcs_write(VMCS_ENTRY_INTR_INFO, info); @@ -1035,7 +1103,7 @@ * because of a pending AST. */ info = vmcs_read(VMCS_ENTRY_INTR_INFO); - if (info & VMCS_INTERRUPTION_INFO_VALID) + if (info & VMCS_INTR_VALID) return; /* @@ -1066,7 +1134,7 @@ goto cantinject; /* Inject the interrupt */ - info = VMCS_INTERRUPTION_INFO_HW_INTR | VMCS_INTERRUPTION_INFO_VALID; + info = VMCS_INTR_T_HWINTR | VMCS_INTR_VALID; info |= vector; vmcs_write(VMCS_ENTRY_INTR_INFO, info); @@ -1087,6 +1155,37 @@ VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); } +/* + * If the Virtual NMIs execution control is '1' then the logical processor + * tracks virtual-NMI blocking in the Guest Interruptibility-state field of + * the VMCS. An IRET instruction in VMX non-root operation will remove any + * virtual-NMI blocking. + * + * This unblocking occurs even if the IRET causes a fault. In this case the + * hypervisor needs to restore virtual-NMI blocking before resuming the guest. + */ +static void +vmx_restore_nmi_blocking(struct vmx *vmx, int vcpuid) +{ + uint32_t gi; + + VCPU_CTR0(vmx->vm, vcpuid, "Restore Virtual-NMI blocking"); + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING; + vmcs_write(VMCS_GUEST_INTERRUPTIBILITY, gi); +} + +static void +vmx_clear_nmi_blocking(struct vmx *vmx, int vcpuid) +{ + uint32_t gi; + + VCPU_CTR0(vmx->vm, vcpuid, "Clear Virtual-NMI blocking"); + gi = vmcs_read(VMCS_GUEST_INTERRUPTIBILITY); + gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING; + vmcs_write(VMCS_GUEST_INTERRUPTIBILITY, gi); +} + static int vmx_emulate_cr_access(struct vmx *vmx, int vcpu, uint64_t exitqual) { @@ -1376,10 +1475,12 @@ int error, handled; struct vmxctx *vmxctx; struct vlapic *vlapic; - uint32_t eax, ecx, edx, idtvec_info, idtvec_err, reason; + uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, reason; uint64_t qual, gpa; bool retu; + CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0); + handled = 0; vmxctx = &vmx->ctx[vcpu]; @@ -1412,9 +1513,20 @@ vmcs_write(VMCS_ENTRY_EXCEPTION_ERROR, idtvec_err); } + /* + * If 'virtual NMIs' are being used and the VM-exit + * happened while injecting an NMI during the previous + * VM-entry, then clear "blocking by NMI" in the Guest + * Interruptibility-state. + */ + if ((idtvec_info & VMCS_INTR_T_MASK) == + VMCS_INTR_T_NMI) { + vmx_clear_nmi_blocking(vmx, vcpu); + } vmcs_write(VMCS_ENTRY_INST_LENGTH, vmexit->inst_length); } default: + idtvec_info = 0; break; } @@ -1487,6 +1599,11 @@ * host interrupt handler in the VM's softc. We will inject * this virtual interrupt during the subsequent VM enter. */ + intr_info = vmcs_read(VMCS_EXIT_INTR_INFO); + KASSERT((intr_info & VMCS_INTR_VALID) != 0 && + (intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_HWINTR, + ("VM exit interruption info invalid: %#x", intr_info)); + vmx_trigger_hostintr(intr_info & 0xff); /* * This is special. We want to treat this as an 'handled' @@ -1514,6 +1631,23 @@ vmm_stat_incr(vmx->vm, vcpu, VMEXIT_CPUID, 1); handled = vmx_handle_cpuid(vmx->vm, vcpu, vmxctx); break; + case EXIT_REASON_EXCEPTION: + intr_info = vmcs_read(VMCS_EXIT_INTR_INFO); + KASSERT((intr_info & VMCS_INTR_VALID) != 0, + ("VM exit interruption info invalid: %#x", intr_info)); + /* + * If Virtual NMIs control is 1 and the VM-exit is due to a + * fault encountered during the execution of IRET then we must + * restore the state of "virtual-NMI blocking" before resuming + * the guest. + * + * See "Resuming Guest Software after Handling an Exception". + */ + if ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 && + (intr_info & 0xff) != IDT_DF && + (intr_info & EXIT_QUAL_NMIUDTI) != 0) + vmx_restore_nmi_blocking(vmx, vcpu); + break; case EXIT_REASON_EPT_FAULT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EPT_FAULT, 1); /* @@ -1532,6 +1666,17 @@ vmexit->u.inst_emul.gla = vmcs_gla(); vmexit->u.inst_emul.cr3 = vmcs_guest_cr3(); } + /* + * If Virtual NMIs control is 1 and the VM-exit is due to an + * EPT fault during the execution of IRET then we must restore + * the state of "virtual-NMI blocking" before resuming. + * + * See description of "NMI unblocking due to IRET" in + * "Exit Qualification for EPT Violations". + */ + if ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 && + (qual & EXIT_QUAL_NMIUDTI) != 0) + vmx_restore_nmi_blocking(vmx, vcpu); break; case EXIT_REASON_APIC_ACCESS: handled = vmx_handle_apic_access(vmx, vcpu, vmexit); @@ -1596,6 +1741,18 @@ } static __inline int +vmx_exit_rendezvous(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) +{ + + vmexit->rip = vmcs_guest_rip(); + vmexit->inst_length = 0; + vmexit->exitcode = VM_EXITCODE_RENDEZVOUS; + vmm_stat_incr(vmx->vm, vcpu, VMEXIT_RENDEZVOUS, 1); + + return (UNHANDLED); +} + +static __inline int vmx_exit_inst_error(struct vmxctx *vmxctx, int rc, struct vm_exit *vmexit) { @@ -1624,10 +1781,12 @@ } static int -vmx_run(void *arg, int vcpu, register_t startrip, pmap_t pmap) +vmx_run(void *arg, int vcpu, register_t startrip, pmap_t pmap, + void *rendezvous_cookie) { int rc, handled, launched; struct vmx *vmx; + struct vm *vm; struct vmxctx *vmxctx; struct vmcs *vmcs; struct vm_exit *vmexit; @@ -1636,10 +1795,11 @@ uint32_t exit_reason; vmx = arg; + vm = vmx->vm; vmcs = &vmx->vmcs[vcpu]; vmxctx = &vmx->ctx[vcpu]; - vlapic = vm_lapic(vmx->vm, vcpu); - vmexit = vm_exitinfo(vmx->vm, vcpu); + vlapic = vm_lapic(vm, vcpu); + vmexit = vm_exitinfo(vm, vcpu); launched = 0; KASSERT(vmxctx->pmap == pmap, @@ -1687,6 +1847,12 @@ break; } + if (vcpu_rendezvous_pending(rendezvous_cookie)) { + enable_intr(); + handled = vmx_exit_rendezvous(vmx, vcpu, vmexit); + break; + } + vmx_inject_interrupts(vmx, vcpu, vlapic); vmx_run_trace(vmx, vcpu); rc = vmx_enter_guest(vmxctx, launched); @@ -1720,9 +1886,9 @@ } if (!handled) - vmm_stat_incr(vmx->vm, vcpu, VMEXIT_USERSPACE, 1); + vmm_stat_incr(vm, vcpu, VMEXIT_USERSPACE, 1); - VCPU_CTR1(vmx->vm, vcpu, "returning from vmx_run: exitcode %d", + VCPU_CTR1(vm, vcpu, "returning from vmx_run: exitcode %d", vmexit->exitcode); VMCLEAR(vmcs); @@ -1945,11 +2111,11 @@ if (error) return (error); - if (info & VMCS_INTERRUPTION_INFO_VALID) + if (info & VMCS_INTR_VALID) return (EAGAIN); info = vector | (type_map[type] << 8) | (code_valid ? 1 << 11 : 0); - info |= VMCS_INTERRUPTION_INFO_VALID; + info |= VMCS_INTR_VALID; error = vmcs_setreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), info); if (error != 0) return (error); @@ -2101,19 +2267,9 @@ return (retval); } -/* - * Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM). - */ -struct pir_desc { - uint64_t pir[4]; - uint64_t pending; - uint64_t unused[3]; -} __aligned(64); -CTASSERT(sizeof(struct pir_desc) == 64); - struct vlapic_vtx { struct vlapic vlapic; - struct pir_desc pir_desc; + struct pir_desc *pir_desc; }; #define VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg) \ @@ -2143,7 +2299,7 @@ * XXX need to deal with level triggered interrupts */ vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; /* * Keep track of interrupt requests in the PIR descriptor. This is @@ -2177,7 +2333,7 @@ KASSERT(vecptr == NULL, ("vmx_pending_intr: vecptr must be NULL")); vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; pending = atomic_load_acq_long(&pir_desc->pending); if (!pending) @@ -2215,6 +2371,13 @@ panic("vmx_intr_accepted: not expected to be called"); } +static void +vmx_post_intr(struct vlapic *vlapic, int hostcpu) +{ + + ipi_cpu(hostcpu, pirvec); +} + /* * Transfer the pending interrupts in the PIR descriptor to the IRR * in the virtual APIC page. @@ -2230,7 +2393,7 @@ uint16_t intr_status_old, intr_status_new; vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; if (atomic_cmpset_long(&pir_desc->pending, 1, 0) == 0) { VCPU_CTR0(vlapic->vm, vlapic->vcpuid, "vmx_inject_pir: " "no posted interrupt pending"); @@ -2295,6 +2458,7 @@ { struct vmx *vmx; struct vlapic *vlapic; + struct vlapic_vtx *vlapic_vtx; vmx = arg; @@ -2303,12 +2467,18 @@ vlapic->vcpuid = vcpuid; vlapic->apic_page = (struct LAPIC *)&vmx->apic_page[vcpuid]; + vlapic_vtx = (struct vlapic_vtx *)vlapic; + vlapic_vtx->pir_desc = &vmx->pir_desc[vcpuid]; + 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; } + if (posted_interrupts) + vlapic->ops.post_intr = vmx_post_intr; + vlapic_init(vlapic); return (vlapic); ==== //depot/projects/pci/sys/amd64/vmm/intel/vmx.h#6 (text+ko) ==== @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/intel/vmx.h 260167 2014-01-01 21:17:08Z neel $ + * $FreeBSD: head/sys/amd64/vmm/intel/vmx.h 260532 2014-01-11 04:22:00Z neel $ */ #ifndef _VMX_H_ @@ -93,11 +93,20 @@ }; CTASSERT(sizeof(struct apic_page) == PAGE_SIZE); +/* Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM) */ +struct pir_desc { + uint64_t pir[4]; + uint64_t pending; + uint64_t unused[3]; +} __aligned(64); +CTASSERT(sizeof(struct pir_desc) == 64); + /* virtual machine softc */ struct vmx { struct vmcs vmcs[VM_MAXCPU]; /* one vmcs per virtual cpu */ struct apic_page apic_page[VM_MAXCPU]; /* one apic page per vcpu */ char msr_bitmap[PAGE_SIZE]; + struct pir_desc pir_desc[VM_MAXCPU]; struct msr_entry guest_msrs[VM_MAXCPU][GUEST_MSR_MAX_ENTRIES]; struct vmxctx ctx[VM_MAXCPU]; struct vmxcap cap[VM_MAXCPU]; @@ -108,6 +117,7 @@ CTASSERT((offsetof(struct vmx, vmcs) & PAGE_MASK) == 0); CTASSERT((offsetof(struct vmx, msr_bitmap) & PAGE_MASK) == 0); CTASSERT((offsetof(struct vmx, guest_msrs) & 15) == 0); +CTASSERT((offsetof(struct vmx, pir_desc[0]) & 63) == 0); #define VMX_GUEST_VMEXIT 0 #define VMX_VMRESUME_ERROR 1 @@ -115,6 +125,7 @@ #define VMX_INVEPT_ERROR 3 int vmx_enter_guest(struct vmxctx *ctx, int launched); void vmx_exit_guest(void); +void vmx_call_isr(uintptr_t entry); u_long vmx_fix_cr0(u_long cr0); u_long vmx_fix_cr4(u_long cr4); ==== //depot/projects/pci/sys/amd64/vmm/intel/vmx_genassym.c#6 (text+ko) ==== @@ -23,11 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/intel/vmx_genassym.c 260167 2014-01-01 21:17:08Z neel $ + * $FreeBSD: head/sys/amd64/vmm/intel/vmx_genassym.c 260531 2014-01-11 03:14:05Z neel $ */ #include -__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmx_genassym.c 260167 2014-01-01 21:17:08Z neel $"); +__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmx_genassym.c 260531 2014-01-11 03:14:05Z neel $"); #include #include @@ -84,3 +84,6 @@ ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active)); ASSYM(PM_EPTGEN, offsetof(struct pmap, pm_eptgen)); + +ASSYM(KERNEL_SS, GSEL(GDATA_SEL, SEL_KPL)); +ASSYM(KERNEL_CS, GSEL(GCODE_SEL, SEL_KPL)); ==== //depot/projects/pci/sys/amd64/vmm/intel/vmx_support.S#4 (text+ko) ==== @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/intel/vmx_support.S 260238 2014-01-03 19:29:33Z neel $ + * $FreeBSD: head/sys/amd64/vmm/intel/vmx_support.S 260531 2014-01-11 03:14:05Z neel $ */ #include @@ -234,3 +234,21 @@ movl $VMX_GUEST_VMEXIT, %eax ret END(vmx_exit_guest) + +/* + * %rdi = interrupt handler entry point + * + * Calling sequence described in the "Instruction Set Reference" for the "INT" + * instruction in Intel SDM, Vol 2. + */ +ENTRY(vmx_call_isr) + mov %rsp, %r11 /* save %rsp */ + and $~0xf, %rsp /* align on 16-byte boundary */ + pushq $KERNEL_SS /* %ss */ + pushq %r11 /* %rsp */ + pushfq /* %rflags */ + pushq $KERNEL_CS /* %cs */ + cli /* disable interrupts */ + callq *%rdi /* push %rip and call isr */ + ret +END(vmx_call_isr) ==== //depot/projects/pci/sys/amd64/vmm/io/vioapic.c#3 (text+ko) ==== @@ -24,11 +24,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: head/sys/amd64/vmm/io/vioapic.c 259482 2013-12-16 19:59:31Z neel $ + * $FreeBSD: head/sys/amd64/vmm/io/vioapic.c 260619 2014-01-14 01:55:58Z neel $ */ #include -__FBSDID("$FreeBSD: head/sys/amd64/vmm/io/vioapic.c 259482 2013-12-16 19:59:31Z neel $"); +__FBSDID("$FreeBSD: head/sys/amd64/vmm/io/vioapic.c 260619 2014-01-14 01:55:58Z neel $"); #include #include @@ -222,8 +222,52 @@ return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE)); } +/* + * Reset the vlapic's trigger-mode register to reflect the ioapic pin + * configuration. + */ +static void +vioapic_update_tmr(struct vm *vm, int vcpuid, void *arg) +{ + struct vioapic *vioapic; + struct vlapic *vlapic; + uint32_t low, high, dest; + int delmode, pin, vector; + bool level, phys; + + vlapic = vm_lapic(vm, vcpuid); + vioapic = vm_ioapic(vm); + + VIOAPIC_LOCK(vioapic); + /* + * Reset all vectors to be edge-triggered. + */ + vlapic_reset_tmr(vlapic); + for (pin = 0; pin < REDIR_ENTRIES; pin++) { + low = vioapic->rtbl[pin].reg; + high = vioapic->rtbl[pin].reg >> 32; + + level = low & IOART_TRGRLVL ? true : false; + if (!level) + continue; + + /* + * For a level-triggered 'pin' let the vlapic figure out if + * an assertion on this 'pin' would result in an interrupt + * being delivered to it. If yes, then it will modify the + * TMR bit associated with this vector to level-triggered. + */ + phys = ((low & IOART_DESTMOD) == IOART_DESTPHY); + delmode = low & IOART_DELMOD; + vector = low & IOART_INTVEC; + dest = high >> APIC_ID_SHIFT; + vlapic_set_tmr_level(vlapic, dest, phys, delmode, vector); + } + VIOAPIC_UNLOCK(vioapic); +} + static uint32_t -vioapic_read(struct vioapic *vioapic, uint32_t addr) >>> TRUNCATED FOR MAIL (1000 lines) <<<