From owner-svn-src-stable-10@FreeBSD.ORG Thu Jan 23 20:21:41 2014 Return-Path: Delivered-To: svn-src-stable-10@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 C1383ACD; Thu, 23 Jan 2014 20:21:41 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a: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 AA31E16CD; Thu, 23 Jan 2014 20:21:41 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s0NKLfEJ012769; Thu, 23 Jan 2014 20:21:41 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s0NKLdCg012757; Thu, 23 Jan 2014 20:21:39 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201401232021.s0NKLdCg012757@svn.freebsd.org> From: John Baldwin Date: Thu, 23 Jan 2014 20:21:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r261088 - in stable/10: lib/libvmmapi sys/amd64/include sys/amd64/vmm sys/amd64/vmm/intel sys/amd64/vmm/io sys/modules/vmm usr.sbin/bhyve X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Jan 2014 20:21:41 -0000 Author: jhb Date: Thu Jan 23 20:21:39 2014 New Revision: 261088 URL: http://svnweb.freebsd.org/changeset/base/261088 Log: MFC 257422,257661,258075,258476,258494,258579,258609,258699: Several enhancements to the I/O APIC support in bhyve including: - Move the I/O APIC device model from userspace into vmm.ko and add ioctls to assert and deassert I/O APIC pins. - Add HPET device emulation including a single timer block with 8 timers. - Remove the 'vdev' abstraction. Approved by: neel Added: stable/10/sys/amd64/vmm/io/vhpet.c - copied, changed from r258579, head/sys/amd64/vmm/io/vhpet.c stable/10/sys/amd64/vmm/io/vhpet.h - copied unchanged from r258579, head/sys/amd64/vmm/io/vhpet.h stable/10/sys/amd64/vmm/io/vioapic.c - copied, changed from r258075, head/sys/amd64/vmm/io/vioapic.c stable/10/sys/amd64/vmm/io/vioapic.h - copied, changed from r258075, head/sys/amd64/vmm/io/vioapic.h Deleted: stable/10/sys/amd64/vmm/io/vdev.c stable/10/sys/amd64/vmm/io/vdev.h stable/10/usr.sbin/bhyve/ioapic.c stable/10/usr.sbin/bhyve/ioapic.h Modified: stable/10/lib/libvmmapi/vmmapi.c stable/10/lib/libvmmapi/vmmapi.h stable/10/sys/amd64/include/vmm.h stable/10/sys/amd64/include/vmm_dev.h stable/10/sys/amd64/vmm/intel/vmx.c stable/10/sys/amd64/vmm/io/ppt.c stable/10/sys/amd64/vmm/io/vlapic.c stable/10/sys/amd64/vmm/io/vlapic.h stable/10/sys/amd64/vmm/vmm.c stable/10/sys/amd64/vmm/vmm_dev.c stable/10/sys/amd64/vmm/vmm_ktr.h stable/10/sys/amd64/vmm/vmm_lapic.c stable/10/sys/amd64/vmm/vmm_lapic.h stable/10/sys/modules/vmm/Makefile stable/10/usr.sbin/bhyve/Makefile stable/10/usr.sbin/bhyve/acpi.c stable/10/usr.sbin/bhyve/bhyverun.c stable/10/usr.sbin/bhyve/mptbl.c stable/10/usr.sbin/bhyve/pci_emul.c stable/10/usr.sbin/bhyve/pci_emul.h stable/10/usr.sbin/bhyve/pci_lpc.c stable/10/usr.sbin/bhyve/pit_8254.c Directory Properties: stable/10/ (props changed) Modified: stable/10/lib/libvmmapi/vmmapi.c ============================================================================== --- stable/10/lib/libvmmapi/vmmapi.c Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/lib/libvmmapi/vmmapi.c Thu Jan 23 20:21:39 2014 (r261088) @@ -397,6 +397,39 @@ vm_lapic_irq(struct vmctx *ctx, int vcpu } int +vm_ioapic_assert_irq(struct vmctx *ctx, int irq) +{ + struct vm_ioapic_irq ioapic_irq; + + bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); + ioapic_irq.irq = irq; + + return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq)); +} + +int +vm_ioapic_deassert_irq(struct vmctx *ctx, int irq) +{ + struct vm_ioapic_irq ioapic_irq; + + bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); + ioapic_irq.irq = irq; + + return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq)); +} + +int +vm_ioapic_pulse_irq(struct vmctx *ctx, int irq) +{ + struct vm_ioapic_irq ioapic_irq; + + bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq)); + ioapic_irq.irq = irq; + + return (ioctl(ctx->fd, VM_IOAPIC_PULSE_IRQ, &ioapic_irq)); +} + +int vm_inject_nmi(struct vmctx *ctx, int vcpu) { struct vm_nmi vmnmi; @@ -792,3 +825,16 @@ vm_get_gpa_pmap(struct vmctx *ctx, uint6 return (error); } + +int +vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities) +{ + int error; + struct vm_hpet_cap cap; + + bzero(&cap, sizeof(struct vm_hpet_cap)); + error = ioctl(ctx->fd, VM_GET_HPET_CAPABILITIES, &cap); + if (capabilities != NULL) + *capabilities = cap.capabilities; + return (error); +} Modified: stable/10/lib/libvmmapi/vmmapi.h ============================================================================== --- stable/10/lib/libvmmapi/vmmapi.h Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/lib/libvmmapi/vmmapi.h Thu Jan 23 20:21:39 2014 (r261088) @@ -67,6 +67,9 @@ int vm_inject_event(struct vmctx *ctx, i int vm_inject_event2(struct vmctx *ctx, int vcpu, enum vm_event_type type, int vector, int error_code); int vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector); +int vm_ioapic_assert_irq(struct vmctx *ctx, int irq); +int vm_ioapic_deassert_irq(struct vmctx *ctx, int irq); +int vm_ioapic_pulse_irq(struct vmctx *ctx, int irq); int vm_inject_nmi(struct vmctx *ctx, int vcpu); int vm_capability_name2type(const char *capname); const char *vm_capability_type2name(int type); @@ -93,6 +96,8 @@ const char *vm_get_stat_desc(struct vmct int vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *s); int vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state s); +int vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities); + /* Reset vcpu register state */ int vcpu_reset(struct vmctx *ctx, int vcpu); Modified: stable/10/sys/amd64/include/vmm.h ============================================================================== --- stable/10/sys/amd64/include/vmm.h Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/sys/amd64/include/vmm.h Thu Jan 23 20:21:39 2014 (r261088) @@ -38,6 +38,8 @@ struct vm_memory_segment; struct seg_desc; struct vm_exit; struct vm_run; +struct vhpet; +struct vioapic; struct vlapic; struct vmspace; struct vm_object; @@ -116,10 +118,13 @@ int vm_nmi_pending(struct vm *vm, int vc void vm_nmi_clear(struct vm *vm, int vcpuid); uint64_t *vm_guest_msrs(struct vm *vm, int cpu); struct vlapic *vm_lapic(struct vm *vm, int cpu); +struct vioapic *vm_ioapic(struct vm *vm); +struct vhpet *vm_hpet(struct vm *vm); int vm_get_capability(struct vm *vm, int vcpu, int type, int *val); int vm_set_capability(struct vm *vm, int vcpu, int type, int val); int vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state); int vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state); +int vm_apicid2vcpuid(struct vm *vm, int apicid); void vm_activate_cpu(struct vm *vm, int vcpu); cpuset_t vm_active_cpus(struct vm *vm); struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); Modified: stable/10/sys/amd64/include/vmm_dev.h ============================================================================== --- stable/10/sys/amd64/include/vmm_dev.h Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/sys/amd64/include/vmm_dev.h Thu Jan 23 20:21:39 2014 (r261088) @@ -71,6 +71,10 @@ struct vm_lapic_irq { int vector; }; +struct vm_ioapic_irq { + int irq; +}; + struct vm_capability { int cpuid; enum vm_cap_type captype; @@ -142,6 +146,10 @@ struct vm_gpa_pte { int ptenum; }; +struct vm_hpet_cap { + uint32_t capabilities; /* lower 32 bits of HPET capabilities */ +}; + enum { /* general routines */ IOCNUM_ABIVERS = 0, @@ -164,6 +172,9 @@ enum { IOCNUM_INJECT_EVENT = 30, IOCNUM_LAPIC_IRQ = 31, IOCNUM_INJECT_NMI = 32, + IOCNUM_IOAPIC_ASSERT_IRQ = 33, + IOCNUM_IOAPIC_DEASSERT_IRQ = 34, + IOCNUM_IOAPIC_PULSE_IRQ = 35, /* PCI pass-thru */ IOCNUM_BIND_PPTDEV = 40, @@ -179,6 +190,7 @@ enum { /* kernel device state */ IOCNUM_SET_X2APIC_STATE = 60, IOCNUM_GET_X2APIC_STATE = 61, + IOCNUM_GET_HPET_CAPABILITIES = 62, }; #define VM_RUN \ @@ -199,6 +211,12 @@ enum { _IOW('v', IOCNUM_INJECT_EVENT, struct vm_event) #define VM_LAPIC_IRQ \ _IOW('v', IOCNUM_LAPIC_IRQ, struct vm_lapic_irq) +#define VM_IOAPIC_ASSERT_IRQ \ + _IOW('v', IOCNUM_IOAPIC_ASSERT_IRQ, struct vm_ioapic_irq) +#define VM_IOAPIC_DEASSERT_IRQ \ + _IOW('v', IOCNUM_IOAPIC_DEASSERT_IRQ, struct vm_ioapic_irq) +#define VM_IOAPIC_PULSE_IRQ \ + _IOW('v', IOCNUM_IOAPIC_PULSE_IRQ, struct vm_ioapic_irq) #define VM_SET_CAPABILITY \ _IOW('v', IOCNUM_SET_CAPABILITY, struct vm_capability) #define VM_GET_CAPABILITY \ @@ -223,6 +241,8 @@ enum { _IOW('v', IOCNUM_SET_X2APIC_STATE, struct vm_x2apic) #define VM_GET_X2APIC_STATE \ _IOWR('v', IOCNUM_GET_X2APIC_STATE, struct vm_x2apic) +#define VM_GET_HPET_CAPABILITIES \ + _IOR('v', IOCNUM_GET_HPET_CAPABILITIES, struct vm_hpet_cap) #define VM_GET_GPA_PMAP \ _IOWR('v', IOCNUM_GET_GPA_PMAP, struct vm_gpa_pte) #endif Modified: stable/10/sys/amd64/vmm/intel/vmx.c ============================================================================== --- stable/10/sys/amd64/vmm/intel/vmx.c Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/sys/amd64/vmm/intel/vmx.c Thu Jan 23 20:21:39 2014 (r261088) @@ -308,8 +308,8 @@ vmx_setjmp_rc2str(int rc) } } -#define SETJMP_TRACE(vmx, vcpu, vmxctx, regname) \ - VMM_CTR1((vmx)->vm, (vcpu), "setjmp trace " #regname " 0x%016lx", \ +#define SETJMP_TRACE(vmx, vcpu, vmxctx, regname) \ + VCPU_CTR1((vmx)->vm, (vcpu), "setjmp trace " #regname " 0x%016lx", \ (vmxctx)->regname) static void @@ -321,14 +321,14 @@ vmx_setjmp_trace(struct vmx *vmx, int vc panic("vmx_setjmp_trace: invalid vmxctx %p; should be %p", vmxctx, &vmx->ctx[vcpu]); - VMM_CTR1((vmx)->vm, (vcpu), "vmxctx = %p", vmxctx); - VMM_CTR2((vmx)->vm, (vcpu), "setjmp return code %s(%d)", + VCPU_CTR1((vmx)->vm, (vcpu), "vmxctx = %p", vmxctx); + VCPU_CTR2((vmx)->vm, (vcpu), "setjmp return code %s(%d)", vmx_setjmp_rc2str(rc), rc); host_rsp = host_rip = ~0; vmread(VMCS_HOST_RIP, &host_rip); vmread(VMCS_HOST_RSP, &host_rsp); - VMM_CTR2((vmx)->vm, (vcpu), "vmcs host_rip 0x%016lx, host_rsp 0x%016lx", + VCPU_CTR2((vmx)->vm, (vcpu), "vmcs host_rip 0x%016lx, host_rsp %#lx", host_rip, host_rsp); SETJMP_TRACE(vmx, vcpu, vmxctx, host_r15); @@ -887,7 +887,7 @@ static __inline void vmx_run_trace(struct vmx *vmx, int vcpu) { #ifdef KTR - VMM_CTR1(vmx->vm, vcpu, "Resume execution at 0x%0lx", vmcs_guest_rip()); + VCPU_CTR1(vmx->vm, vcpu, "Resume execution at %#lx", vmcs_guest_rip()); #endif } @@ -896,7 +896,7 @@ vmx_exit_trace(struct vmx *vmx, int vcpu int handled) { #ifdef KTR - VMM_CTR3(vmx->vm, vcpu, "%s %s vmexit at 0x%0lx", + VCPU_CTR3(vmx->vm, vcpu, "%s %s vmexit at 0x%0lx", handled ? "handled" : "unhandled", exit_reason_to_str(exit_reason), rip); #endif @@ -906,7 +906,7 @@ static __inline void vmx_astpending_trace(struct vmx *vmx, int vcpu, uint64_t rip) { #ifdef KTR - VMM_CTR1(vmx->vm, vcpu, "astpending vmexit at 0x%0lx", rip); + VCPU_CTR1(vmx->vm, vcpu, "astpending vmexit at 0x%0lx", rip); #endif } @@ -1055,7 +1055,7 @@ vmx_inject_nmi(struct vmx *vmx, int vcpu if (error) panic("vmx_inject_nmi: vmwrite(intrinfo) %d", error); - VMM_CTR0(vmx->vm, vcpu, "Injecting vNMI"); + VCPU_CTR0(vmx->vm, vcpu, "Injecting vNMI"); /* Clear the request */ vm_nmi_clear(vmx->vm, vcpu); @@ -1068,7 +1068,7 @@ nmiblocked: */ vmx_set_nmi_window_exiting(vmx, vcpu); - VMM_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting"); + VCPU_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting"); return (1); } @@ -1134,7 +1134,7 @@ vmx_inject_interrupts(struct vmx *vmx, i /* Update the Local APIC ISR */ lapic_intr_accepted(vmx->vm, vcpu, vector); - VMM_CTR1(vmx->vm, vcpu, "Injecting hwintr at vector %d", vector); + VCPU_CTR1(vmx->vm, vcpu, "Injecting hwintr at vector %d", vector); return; @@ -1145,7 +1145,7 @@ cantinject: */ vmx_set_int_window_exiting(vmx, vcpu); - VMM_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); + VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); } static int @@ -1435,7 +1435,7 @@ vmx_exit_process(struct vmx *vmx, int vc case EXIT_REASON_INTR_WINDOW: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INTR_WINDOW, 1); vmx_clear_int_window_exiting(vmx, vcpu); - VMM_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting"); + VCPU_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting"); return (1); case EXIT_REASON_EXT_INTR: /* @@ -1458,7 +1458,7 @@ vmx_exit_process(struct vmx *vmx, int vc /* Exit to allow the pending virtual NMI to be injected */ vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1); vmx_clear_nmi_window_exiting(vmx, vcpu); - VMM_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting"); + VCPU_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting"); return (1); case EXIT_REASON_INOUT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1); @@ -1659,7 +1659,7 @@ vmx_run(void *arg, int vcpu, register_t if (!handled) vmm_stat_incr(vmx->vm, vcpu, VMEXIT_USERSPACE, 1); - VMM_CTR1(vmx->vm, vcpu, "goto userland: exitcode %d",vmexit->exitcode); + VCPU_CTR1(vmx->vm, vcpu, "goto userland: exitcode %d",vmexit->exitcode); /* * XXX Modified: stable/10/sys/amd64/vmm/io/ppt.c ============================================================================== --- stable/10/sys/amd64/vmm/io/ppt.c Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/sys/amd64/vmm/io/ppt.c Thu Jan 23 20:21:39 2014 (r261088) @@ -421,7 +421,7 @@ pptintr(void *arg) vec = pptarg->vec; if (ppt->vm != NULL) - (void) lapic_set_intr(ppt->vm, pptarg->vcpu, vec); + lapic_intr_edge(ppt->vm, pptarg->vcpu, vec); else { /* * XXX Copied and modified: stable/10/sys/amd64/vmm/io/vhpet.c (from r258579, head/sys/amd64/vmm/io/vhpet.c) ============================================================================== --- head/sys/amd64/vmm/io/vhpet.c Mon Nov 25 19:04:51 2013 (r258579, copy source) +++ stable/10/sys/amd64/vmm/io/vhpet.c Thu Jan 23 20:21:39 2014 (r261088) @@ -266,14 +266,14 @@ vhpet_timer_interrupt(struct vhpet *vhpe if (apicid != 0xff) { /* unicast */ vcpuid = vm_apicid2vcpuid(vhpet->vm, apicid); - lapic_set_intr(vhpet->vm, vcpuid, vector); + lapic_intr_edge(vhpet->vm, vcpuid, vector); } else { /* broadcast */ dmask = vm_active_cpus(vhpet->vm); while ((vcpuid = CPU_FFS(&dmask)) != 0) { vcpuid--; CPU_CLR(vcpuid, &dmask); - lapic_set_intr(vhpet->vm, vcpuid, vector); + lapic_intr_edge(vhpet->vm, vcpuid, vector); } } return; @@ -725,8 +725,9 @@ done: struct vhpet * vhpet_init(struct vm *vm) { - int i; + int i, pincount; struct vhpet *vhpet; + uint64_t allowed_irqs; struct vhpet_callout_arg *arg; struct bintime bt; @@ -737,12 +738,20 @@ vhpet_init(struct vm *vm) FREQ2BT(HPET_FREQ, &bt); vhpet->freq_sbt = bttosbt(bt); + pincount = vioapic_pincount(vm); + if (pincount >= 24) + allowed_irqs = 0x00f00000; /* irqs 20, 21, 22 and 23 */ + else + allowed_irqs = 0; + /* * Initialize HPET timer hardware state. */ for (i = 0; i < VHPET_NUM_TIMERS; i++) { - vhpet->timer[i].cap_config = 0UL << 32 | - HPET_TCAP_FSB_INT_DEL | HPET_TCAP_PER_INT; + vhpet->timer[i].cap_config = allowed_irqs << 32; + vhpet->timer[i].cap_config |= HPET_TCAP_PER_INT; + vhpet->timer[i].cap_config |= HPET_TCAP_FSB_INT_DEL; + vhpet->timer[i].compval = 0xffffffff; callout_init(&vhpet->timer[i].callout, 1); Copied: stable/10/sys/amd64/vmm/io/vhpet.h (from r258579, head/sys/amd64/vmm/io/vhpet.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/amd64/vmm/io/vhpet.h Thu Jan 23 20:21:39 2014 (r261088, copy of r258579, head/sys/amd64/vmm/io/vhpet.h) @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2013 Tycho Nightingale + * Copyright (c) 2013 Neel Natu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VHPET_H_ +#define _VHPET_H_ + +#define VHPET_BASE 0xfed00000 +#define VHPET_SIZE 1024 + +struct vhpet *vhpet_init(struct vm *vm); +void vhpet_cleanup(struct vhpet *vhpet); +int vhpet_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t val, + int size, void *arg); +int vhpet_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *val, + int size, void *arg); +int vhpet_getcap(struct vm_hpet_cap *cap); + +#endif /* _VHPET_H_ */ Copied and modified: stable/10/sys/amd64/vmm/io/vioapic.c (from r258075, head/sys/amd64/vmm/io/vioapic.c) ============================================================================== --- head/sys/amd64/vmm/io/vioapic.c Tue Nov 12 22:51:03 2013 (r258075, copy source) +++ stable/10/sys/amd64/vmm/io/vioapic.c Thu Jan 23 20:21:39 2014 (r261088) @@ -49,8 +49,8 @@ __FBSDID("$FreeBSD$"); #define IOREGSEL 0x00 #define IOWIN 0x10 -#define REDIR_ENTRIES 16 -#define INTR_ASSERTED(vioapic, pin) ((vioapic)->rtbl[(pin)].pinstate == true) +#define REDIR_ENTRIES 24 +#define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS)) struct vioapic { struct vm *vm; @@ -59,8 +59,7 @@ struct vioapic { uint32_t ioregsel; struct { uint64_t reg; - bool pinstate; - bool pending; + int acnt; /* sum of pin asserts (+1) and deasserts (-1) */ } rtbl[REDIR_ENTRIES]; }; @@ -79,6 +78,9 @@ static MALLOC_DEFINE(M_VIOAPIC, "vioapic #define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \ VM_CTR3((vioapic)->vm, fmt, a1, a2, a3) +#define VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4) \ + VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4) + #ifdef KTR static const char * pinstate_str(bool asserted) @@ -89,14 +91,25 @@ pinstate_str(bool asserted) else return ("deasserted"); } + +static const char * +trigger_str(bool level) +{ + + if (level) + return ("level"); + else + return ("edge"); +} #endif static void -vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate) +vioapic_send_intr(struct vioapic *vioapic, int pin) { int vector, apicid, vcpuid; uint32_t low, high; cpuset_t dmask; + bool level; KASSERT(pin >= 0 && pin < REDIR_ENTRIES, ("vioapic_set_pinstate: invalid pin number %d", pin)); @@ -104,64 +117,104 @@ vioapic_set_pinstate(struct vioapic *vio KASSERT(VIOAPIC_LOCKED(vioapic), ("vioapic_set_pinstate: vioapic is not locked")); - VIOAPIC_CTR2(vioapic, "ioapic pin%d %s", pin, pinstate_str(newstate)); + low = vioapic->rtbl[pin].reg; + high = vioapic->rtbl[pin].reg >> 32; - /* Nothing to do if interrupt pin has not changed state */ - if (vioapic->rtbl[pin].pinstate == newstate) + /* + * XXX We only deal with: + * - physical destination + * - fixed delivery mode + */ + if ((low & IOART_DESTMOD) != IOART_DESTPHY) { + VIOAPIC_CTR2(vioapic, "ioapic pin%d: unsupported dest mode " + "0x%08x", pin, low); return; + } - vioapic->rtbl[pin].pinstate = newstate; /* record it */ + if ((low & IOART_DELMOD) != IOART_DELFIXED) { + VIOAPIC_CTR2(vioapic, "ioapic pin%d: unsupported delivery mode " + "0x%08x", pin, low); + return; + } - /* Nothing to do if interrupt pin is deasserted */ - if (!INTR_ASSERTED(vioapic, pin)) + if ((low & IOART_INTMASK) == IOART_INTMSET) { + VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin); return; + } - /* - * XXX - * We only deal with: - * - edge triggered interrupts - * - fixed delivery mode - * Level-triggered sources will work so long as there is no sharing. - */ - low = vioapic->rtbl[pin].reg; - high = vioapic->rtbl[pin].reg >> 32; - if ((low & IOART_INTMASK) == IOART_INTMCLR && - (low & IOART_DESTMOD) == IOART_DESTPHY && - (low & IOART_DELMOD) == IOART_DELFIXED) { - vector = low & IOART_INTVEC; - apicid = high >> APIC_ID_SHIFT; - if (apicid != 0xff) { - /* unicast */ - vcpuid = vm_apicid2vcpuid(vioapic->vm, apicid); - VIOAPIC_CTR3(vioapic, "ioapic pin%d triggering " - "intr vector %d on vcpuid %d", pin, vector, vcpuid); - lapic_set_intr(vioapic->vm, vcpuid, vector); - } else { - /* broadcast */ - VIOAPIC_CTR2(vioapic, "ioapic pin%d triggering intr " - "vector %d on all vcpus", pin, vector); - dmask = vm_active_cpus(vioapic->vm); - while ((vcpuid = CPU_FFS(&dmask)) != 0) { - vcpuid--; - CPU_CLR(vcpuid, &dmask); - lapic_set_intr(vioapic->vm, vcpuid, vector); - } + level = low & IOART_TRGRLVL ? true : false; + if (level) + vioapic->rtbl[pin].reg |= IOART_REM_IRR; + + vector = low & IOART_INTVEC; + apicid = high >> APIC_ID_SHIFT; + if (apicid != 0xff) { + /* unicast */ + vcpuid = vm_apicid2vcpuid(vioapic->vm, apicid); + VIOAPIC_CTR4(vioapic, "ioapic pin%d: %s triggered intr " + "vector %d on vcpuid %d", pin, trigger_str(level), + vector, vcpuid); + lapic_set_intr(vioapic->vm, vcpuid, vector, level); + } else { + /* broadcast */ + VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s triggered intr " + "vector %d on all vcpus", pin, trigger_str(level), vector); + dmask = vm_active_cpus(vioapic->vm); + while ((vcpuid = CPU_FFS(&dmask)) != 0) { + vcpuid--; + CPU_CLR(vcpuid, &dmask); + lapic_set_intr(vioapic->vm, vcpuid, vector, level); } - } else if ((low & IOART_INTMASK) != IOART_INTMCLR && - (low & IOART_TRGRLVL) != 0) { - /* - * For level-triggered interrupts that have been - * masked, set the pending bit so that an interrupt - * will be generated on unmask and if the level is - * still asserted - */ - VIOAPIC_CTR1(vioapic, "ioapic pin%d interrupt pending", pin); - vioapic->rtbl[pin].pending = true; } } +static void +vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate) +{ + int oldcnt, newcnt; + bool needintr; + + KASSERT(pin >= 0 && pin < REDIR_ENTRIES, + ("vioapic_set_pinstate: invalid pin number %d", pin)); + + KASSERT(VIOAPIC_LOCKED(vioapic), + ("vioapic_set_pinstate: vioapic is not locked")); + + oldcnt = vioapic->rtbl[pin].acnt; + if (newstate) + vioapic->rtbl[pin].acnt++; + else + vioapic->rtbl[pin].acnt--; + newcnt = vioapic->rtbl[pin].acnt; + + if (newcnt < 0) { + VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d", + pin, newcnt); + } + + needintr = false; + if (oldcnt == 0 && newcnt == 1) { + needintr = true; + VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin); + } else if (oldcnt == 1 && newcnt == 0) { + VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin); + } else { + VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d", + pin, pinstate_str(newstate), newcnt); + } + + if (needintr) + vioapic_send_intr(vioapic, pin); +} + +enum irqstate { + IRQSTATE_ASSERT, + IRQSTATE_DEASSERT, + IRQSTATE_PULSE +}; + static int -vioapic_set_irqstate(struct vm *vm, int irq, bool state) +vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate) { struct vioapic *vioapic; @@ -171,7 +224,20 @@ vioapic_set_irqstate(struct vm *vm, int vioapic = vm_ioapic(vm); VIOAPIC_LOCK(vioapic); - vioapic_set_pinstate(vioapic, irq, state); + switch (irqstate) { + case IRQSTATE_ASSERT: + vioapic_set_pinstate(vioapic, irq, true); + break; + case IRQSTATE_DEASSERT: + vioapic_set_pinstate(vioapic, irq, false); + break; + case IRQSTATE_PULSE: + vioapic_set_pinstate(vioapic, irq, true); + vioapic_set_pinstate(vioapic, irq, false); + break; + default: + panic("vioapic_set_irqstate: invalid irqstate %d", irqstate); + } VIOAPIC_UNLOCK(vioapic); return (0); @@ -181,14 +247,21 @@ int vioapic_assert_irq(struct vm *vm, int irq) { - return (vioapic_set_irqstate(vm, irq, true)); + return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT)); } int vioapic_deassert_irq(struct vm *vm, int irq) { - return (vioapic_set_irqstate(vm, irq, false)); + return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT)); +} + +int +vioapic_pulse_irq(struct vm *vm, int irq) +{ + + return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE)); } static uint32_t @@ -202,7 +275,7 @@ vioapic_read(struct vioapic *vioapic, ui return (vioapic->id); break; case IOAPIC_VER: - return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11); + return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11); break; case IOAPIC_ARB: return (vioapic->id); @@ -229,6 +302,7 @@ vioapic_read(struct vioapic *vioapic, ui static void vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data) { + uint64_t data64, mask64; int regnum, pin, lshift; regnum = addr & 0xff; @@ -253,30 +327,26 @@ vioapic_write(struct vioapic *vioapic, u else lshift = 0; - vioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift); - vioapic->rtbl[pin].reg |= ((uint64_t)data << lshift); + data64 = (uint64_t)data << lshift; + mask64 = (uint64_t)0xffffffff << lshift; + vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS; + vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS; - VIOAPIC_CTR2(vioapic, "ioapic pin%d redir table entry %#lx", + VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx", pin, vioapic->rtbl[pin].reg); - if (vioapic->rtbl[pin].pending && - ((vioapic->rtbl[pin].reg & IOART_INTMASK) == - IOART_INTMCLR)) { - vioapic->rtbl[pin].pending = false; - /* - * Inject the deferred level-triggered int if it is - * still asserted. Simulate by toggling the pin - * off and then on. - */ - if (vioapic->rtbl[pin].pinstate == true) { - VIOAPIC_CTR1(vioapic, "ioapic pin%d pending " - "interrupt delivered", pin); - vioapic_set_pinstate(vioapic, pin, false); - vioapic_set_pinstate(vioapic, pin, true); - } else { - VIOAPIC_CTR1(vioapic, "ioapic pin%d pending " - "interrupt dismissed", pin); - } + /* + * Generate an interrupt if the following conditions are met: + * - pin is not masked + * - previous interrupt has been EOIed + * - pin level is asserted + */ + if ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR && + (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 && + (vioapic->rtbl[pin].acnt > 0)) { + VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl " + "write, acnt %d", pin, vioapic->rtbl[pin].acnt); + vioapic_send_intr(vioapic, pin); } } } @@ -340,6 +410,38 @@ vioapic_mmio_write(void *vm, int vcpuid, return (error); } +void +vioapic_process_eoi(struct vm *vm, int vcpuid, int vector) +{ + struct vioapic *vioapic; + int pin; + + KASSERT(vector >= 0 && vector < 256, + ("vioapic_process_eoi: invalid vector %d", vector)); + + vioapic = vm_ioapic(vm); + VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector); + + /* + * XXX keep track of the pins associated with this vector instead + * of iterating on every single pin each time. + */ + VIOAPIC_LOCK(vioapic); + for (pin = 0; pin < REDIR_ENTRIES; pin++) { + if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0) + continue; + if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector) + continue; + vioapic->rtbl[pin].reg &= ~IOART_REM_IRR; + if (vioapic->rtbl[pin].acnt > 0) { + VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, " + "acnt %d", pin, vioapic->rtbl[pin].acnt); + vioapic_send_intr(vioapic, pin); + } + } + VIOAPIC_UNLOCK(vioapic); +} + struct vioapic * vioapic_init(struct vm *vm) { @@ -364,3 +466,10 @@ vioapic_cleanup(struct vioapic *vioapic) free(vioapic, M_VIOAPIC); } + +int +vioapic_pincount(struct vm *vm) +{ + + return (REDIR_ENTRIES); +} Copied and modified: stable/10/sys/amd64/vmm/io/vioapic.h (from r258075, head/sys/amd64/vmm/io/vioapic.h) ============================================================================== --- head/sys/amd64/vmm/io/vioapic.h Tue Nov 12 22:51:03 2013 (r258075, copy source) +++ stable/10/sys/amd64/vmm/io/vioapic.h Thu Jan 23 20:21:39 2014 (r261088) @@ -30,9 +30,6 @@ #ifndef _VIOAPIC_H_ #define _VIOAPIC_H_ -struct vm; -struct vioapic; - #define VIOAPIC_BASE 0xFEC00000 #define VIOAPIC_SIZE 4096 @@ -41,9 +38,13 @@ void vioapic_cleanup(struct vioapic *vio int vioapic_assert_irq(struct vm *vm, int irq); int vioapic_deassert_irq(struct vm *vm, int irq); +int vioapic_pulse_irq(struct vm *vm, int irq); int vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval, int size, void *arg); int vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval, int size, void *arg); + +int vioapic_pincount(struct vm *vm); +void vioapic_process_eoi(struct vm *vm, int vcpuid, int vector); #endif Modified: stable/10/sys/amd64/vmm/io/vlapic.c ============================================================================== --- stable/10/sys/amd64/vmm/io/vlapic.c Thu Jan 23 20:10:22 2014 (r261087) +++ stable/10/sys/amd64/vmm/io/vlapic.c Thu Jan 23 20:21:39 2014 (r261088) @@ -44,14 +44,14 @@ __FBSDID("$FreeBSD$"); #include "vmm_stat.h" #include "vmm_lapic.h" #include "vmm_ktr.h" -#include "vdev.h" #include "vlapic.h" +#include "vioapic.h" #define VLAPIC_CTR0(vlapic, format) \ - VMM_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) + VCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) #define VLAPIC_CTR1(vlapic, format, p1) \ - VMM_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) + VCPU_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) #define VLAPIC_CTR_IRR(vlapic, msg) \ do { \ @@ -100,8 +100,6 @@ struct vlapic { struct vm *vm; int vcpuid; - struct io_region *mmio; - struct vdev_ops *ops; struct LAPIC apic; int esr_update; @@ -195,9 +193,8 @@ vlapic_init_ipi(struct vlapic *vlapic) } static int -vlapic_op_reset(void* dev) +vlapic_reset(struct vlapic *vlapic) { - struct vlapic *vlapic = (struct vlapic*)dev; struct LAPIC *lapic = &vlapic->apic; memset(lapic, 0, sizeof(*lapic)); @@ -214,36 +211,33 @@ vlapic_op_reset(void* dev) } -static int -vlapic_op_init(void* dev) -{ - struct vlapic *vlapic = (struct vlapic*)dev; - vdev_register_region(vlapic->ops, vlapic, vlapic->mmio); - return vlapic_op_reset(dev); -} - -static int -vlapic_op_halt(void* dev) -{ - struct vlapic *vlapic = (struct vlapic*)dev; - vdev_unregister_region(vlapic, vlapic->mmio); - return 0; - -} - void -vlapic_set_intr_ready(struct vlapic *vlapic, int vector) +vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level) { struct LAPIC *lapic = &vlapic->apic; - uint32_t *irrptr; + uint32_t *irrptr, *tmrptr, mask; int idx; if (vector < 0 || vector >= 256) panic("vlapic_set_intr_ready: invalid vector %d\n", vector); idx = (vector / 32) * 4; + mask = 1 << (vector % 32); + irrptr = &lapic->irr0; - atomic_set_int(&irrptr[idx], 1 << (vector % 32)); + atomic_set_int(&irrptr[idx], mask); + + /* + * Upon acceptance of an interrupt into the IRR the corresponding + * TMR bit is cleared for edge-triggered interrupts and set for + * level-triggered interrupts. + */ + tmrptr = &lapic->tmr0; + if (level) + atomic_set_int(&tmrptr[idx], mask); + else + atomic_clear_int(&tmrptr[idx], mask); + VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); } @@ -371,10 +365,11 @@ static void vlapic_process_eoi(struct vlapic *vlapic) { struct LAPIC *lapic = &vlapic->apic; - uint32_t *isrptr; - int i, idx, bitpos; + uint32_t *isrptr, *tmrptr; + int i, idx, bitpos, vector; isrptr = &lapic->isr0; + tmrptr = &lapic->tmr0; /* * The x86 architecture reserves the the first 32 vectors for use @@ -383,15 +378,20 @@ vlapic_process_eoi(struct vlapic *vlapic for (i = 7; i > 0; i--) { idx = i * 4; bitpos = fls(isrptr[idx]); - if (bitpos != 0) { + if (bitpos-- != 0) { if (vlapic->isrvec_stk_top <= 0) { panic("invalid vlapic isrvec_stk_top %d", vlapic->isrvec_stk_top); } - isrptr[idx] &= ~(1 << (bitpos - 1)); + isrptr[idx] &= ~(1 << bitpos); VLAPIC_CTR_ISR(vlapic, "vlapic_process_eoi"); vlapic->isrvec_stk_top--; vlapic_update_ppr(vlapic); + if ((tmrptr[idx] & (1 << bitpos)) != 0) { + vector = i * 32 + bitpos; + vioapic_process_eoi(vlapic->vm, vlapic->vcpuid, + vector); + } return; } } @@ -426,7 +426,7 @@ vlapic_fire_timer(struct vlapic *vlapic) if (!vlapic_get_lvt_field(lvt, APIC_LVTT_M)) { vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1); vector = vlapic_get_lvt_field(lvt,APIC_LVTT_VECTOR); - vlapic_set_intr_ready(vlapic, vector); + vlapic_set_intr_ready(vlapic, vector, false); } } @@ -472,7 +472,7 @@ lapic_process_icr(struct vlapic *vlapic, i--; CPU_CLR(i, &dmask); if (mode == APIC_DELMODE_FIXED) { - lapic_set_intr(vlapic->vm, i, vec); + lapic_intr_edge(vlapic->vm, i, vec); vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid, IPIS_SENT, i, 1); } else @@ -594,11 +594,9 @@ vlapic_intr_accepted(struct vlapic *vlap } int -vlapic_op_mem_read(void* dev, uint64_t gpa, opsize_t size, uint64_t *data) +vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data) { - struct vlapic *vlapic = (struct vlapic*)dev; struct LAPIC *lapic = &vlapic->apic; - uint64_t offset = gpa & ~(PAGE_SIZE); uint32_t *reg; int i; @@ -686,11 +684,9 @@ vlapic_op_mem_read(void* dev, uint64_t g } int -vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data) +vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data) { - struct vlapic *vlapic = (struct vlapic*)dev; struct LAPIC *lapic = &vlapic->apic; - uint64_t offset = gpa & ~(PAGE_SIZE); uint32_t *reg; int retval; @@ -832,16 +828,6 @@ restart: return (0); } -struct vdev_ops vlapic_dev_ops = { - .name = "vlapic", - .init = vlapic_op_init, - .reset = vlapic_op_reset, - .halt = vlapic_op_halt, - .memread = vlapic_op_mem_read, - .memwrite = vlapic_op_mem_write, -}; -static struct io_region vlapic_mmio[VM_MAXCPU]; - struct vlapic * vlapic_init(struct vm *vm, int vcpuid) { @@ -856,17 +842,7 @@ vlapic_init(struct vm *vm, int vcpuid) if (vcpuid == 0) vlapic->msr_apicbase |= APICBASE_BSP; - vlapic->ops = &vlapic_dev_ops; - - vlapic->mmio = vlapic_mmio + vcpuid; - vlapic->mmio->base = DEFAULT_APIC_BASE; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***