From owner-svn-src-projects@FreeBSD.ORG Tue Feb 4 05:03:17 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 0F029813; Tue, 4 Feb 2014 05:03:17 +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 EC7FF1213; Tue, 4 Feb 2014 05:03:16 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s1453G5v073995; Tue, 4 Feb 2014 05:03:16 GMT (envelope-from grehan@svn.freebsd.org) Received: (from grehan@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s1453Ee5073979; Tue, 4 Feb 2014 05:03:14 GMT (envelope-from grehan@svn.freebsd.org) Message-Id: <201402040503.s1453Ee5073979@svn.freebsd.org> From: Peter Grehan Date: Tue, 4 Feb 2014 05:03:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r261457 - in projects/bhyve_svm/sys/amd64/vmm: . intel io X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Feb 2014 05:03:17 -0000 Author: grehan Date: Tue Feb 4 05:03:14 2014 New Revision: 261457 URL: http://svnweb.freebsd.org/changeset/base/261457 Log: Roll back botched partial MFC :( Added: projects/bhyve_svm/sys/amd64/vmm/io/vdev.c - copied unchanged from r261451, projects/bhyve_svm/sys/amd64/vmm/io/vdev.c projects/bhyve_svm/sys/amd64/vmm/io/vdev.h - copied unchanged from r261451, projects/bhyve_svm/sys/amd64/vmm/io/vdev.h Deleted: projects/bhyve_svm/sys/amd64/vmm/io/vhpet.c projects/bhyve_svm/sys/amd64/vmm/io/vhpet.h projects/bhyve_svm/sys/amd64/vmm/io/vioapic.c projects/bhyve_svm/sys/amd64/vmm/io/vioapic.h Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.c projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.h projects/bhyve_svm/sys/amd64/vmm/intel/vmx.c projects/bhyve_svm/sys/amd64/vmm/intel/vmx.h projects/bhyve_svm/sys/amd64/vmm/intel/vmx_controls.h projects/bhyve_svm/sys/amd64/vmm/intel/vmx_genassym.c projects/bhyve_svm/sys/amd64/vmm/intel/vtd.c projects/bhyve_svm/sys/amd64/vmm/io/ppt.c projects/bhyve_svm/sys/amd64/vmm/io/vlapic.c projects/bhyve_svm/sys/amd64/vmm/io/vlapic.h projects/bhyve_svm/sys/amd64/vmm/vmm.c projects/bhyve_svm/sys/amd64/vmm/vmm_dev.c projects/bhyve_svm/sys/amd64/vmm/vmm_instruction_emul.c projects/bhyve_svm/sys/amd64/vmm/vmm_ktr.h projects/bhyve_svm/sys/amd64/vmm/vmm_lapic.c projects/bhyve_svm/sys/amd64/vmm/vmm_lapic.h projects/bhyve_svm/sys/amd64/vmm/vmm_msr.c projects/bhyve_svm/sys/amd64/vmm/vmm_msr.h projects/bhyve_svm/sys/amd64/vmm/x86.c Directory Properties: projects/bhyve_svm/sys/amd64/vmm/ (props changed) Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.c ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.c Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.c Tue Feb 4 05:03:14 2014 (r261457) @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include #include "vmm_host.h" #include "vmcs.h" Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.h ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.h Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vmcs.h Tue Feb 4 05:03:14 2014 (r261457) @@ -318,7 +318,7 @@ uint64_t vmcs_read(uint32_t encoding); /* * VMCS IDT-Vectoring information fields */ -#define VMCS_IDT_VEC_VALID (1U << 31) +#define VMCS_IDT_VEC_VALID (1 << 31) #define VMCS_IDT_VEC_ERRCODE_VALID (1 << 11) /* Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmx.c ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vmx.c Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vmx.c Tue Feb 4 05:03:14 2014 (r261457) @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -163,7 +164,6 @@ static int cap_halt_exit; static int cap_pause_exit; static int cap_unrestricted_guest; static int cap_monitor_trap; -static int cap_invpcid; static struct unrhdr *vpid_unr; static u_int vpid_alloc_failed; @@ -307,8 +307,8 @@ vmx_setjmp_rc2str(int rc) } } -#define SETJMP_TRACE(vmx, vcpu, vmxctx, regname) \ - VCPU_CTR1((vmx)->vm, (vcpu), "setjmp trace " #regname " 0x%016lx", \ +#define SETJMP_TRACE(vmx, vcpu, vmxctx, regname) \ + VMM_CTR1((vmx)->vm, (vcpu), "setjmp trace " #regname " 0x%016lx", \ (vmxctx)->regname) static void @@ -320,14 +320,14 @@ vmx_setjmp_trace(struct vmx *vmx, int vc panic("vmx_setjmp_trace: invalid vmxctx %p; should be %p", vmxctx, &vmx->ctx[vcpu]); - VCPU_CTR1((vmx)->vm, (vcpu), "vmxctx = %p", vmxctx); - VCPU_CTR2((vmx)->vm, (vcpu), "setjmp return code %s(%d)", + VMM_CTR1((vmx)->vm, (vcpu), "vmxctx = %p", vmxctx); + VMM_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); - VCPU_CTR2((vmx)->vm, (vcpu), "vmcs host_rip 0x%016lx, host_rsp %#lx", + VMM_CTR2((vmx)->vm, (vcpu), "vmcs host_rip 0x%016lx, host_rsp 0x%016lx", host_rip, host_rsp); SETJMP_TRACE(vmx, vcpu, vmxctx, host_r15); @@ -660,11 +660,6 @@ vmx_init(void) PROCBASED2_UNRESTRICTED_GUEST, 0, &tmp) == 0); - cap_invpcid = (vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS2, - MSR_VMX_PROCBASED_CTLS2, PROCBASED2_ENABLE_INVPCID, 0, - &tmp) == 0); - - /* Initialize EPT */ error = ept_init(); if (error) { @@ -833,7 +828,6 @@ vmx_vminit(struct vm *vm, pmap_t pmap) vmx->cap[i].set = 0; vmx->cap[i].proc_ctls = procbased_ctls; - vmx->cap[i].proc_ctls2 = procbased_ctls2; vmx->state[i].lastcpu = -1; vmx->state[i].vpid = vpid[i]; @@ -886,7 +880,7 @@ static __inline void vmx_run_trace(struct vmx *vmx, int vcpu) { #ifdef KTR - VCPU_CTR1(vmx->vm, vcpu, "Resume execution at %#lx", vmcs_guest_rip()); + VMM_CTR1(vmx->vm, vcpu, "Resume execution at 0x%0lx", vmcs_guest_rip()); #endif } @@ -895,7 +889,7 @@ vmx_exit_trace(struct vmx *vmx, int vcpu int handled) { #ifdef KTR - VCPU_CTR3(vmx->vm, vcpu, "%s %s vmexit at 0x%0lx", + VMM_CTR3(vmx->vm, vcpu, "%s %s vmexit at 0x%0lx", handled ? "handled" : "unhandled", exit_reason_to_str(exit_reason), rip); #endif @@ -905,7 +899,7 @@ static __inline void vmx_astpending_trace(struct vmx *vmx, int vcpu, uint64_t rip) { #ifdef KTR - VCPU_CTR1(vmx->vm, vcpu, "astpending vmexit at 0x%0lx", rip); + VMM_CTR1(vmx->vm, vcpu, "astpending vmexit at 0x%0lx", rip); #endif } @@ -1054,7 +1048,7 @@ vmx_inject_nmi(struct vmx *vmx, int vcpu if (error) panic("vmx_inject_nmi: vmwrite(intrinfo) %d", error); - VCPU_CTR0(vmx->vm, vcpu, "Injecting vNMI"); + VMM_CTR0(vmx->vm, vcpu, "Injecting vNMI"); /* Clear the request */ vm_nmi_clear(vmx->vm, vcpu); @@ -1067,7 +1061,7 @@ nmiblocked: */ vmx_set_nmi_window_exiting(vmx, vcpu); - VCPU_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting"); + VMM_CTR0(vmx->vm, vcpu, "Enabling NMI window exiting"); return (1); } @@ -1133,7 +1127,7 @@ vmx_inject_interrupts(struct vmx *vmx, i /* Update the Local APIC ISR */ lapic_intr_accepted(vmx->vm, vcpu, vector); - VCPU_CTR1(vmx->vm, vcpu, "Injecting hwintr at vector %d", vector); + VMM_CTR1(vmx->vm, vcpu, "Injecting hwintr at vector %d", vector); return; @@ -1144,7 +1138,7 @@ cantinject: */ vmx_set_int_window_exiting(vmx, vcpu); - VCPU_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); + VMM_CTR0(vmx->vm, vcpu, "Enabling interrupt window exiting"); } static int @@ -1301,6 +1295,21 @@ ept_fault_type(uint64_t ept_qual) return (fault_type); } +static int +ept_protection(uint64_t ept_qual) +{ + int prot = 0; + + if (ept_qual & EPT_VIOLATION_GPA_READABLE) + prot |= VM_PROT_READ; + if (ept_qual & EPT_VIOLATION_GPA_WRITEABLE) + prot |= VM_PROT_WRITE; + if (ept_qual & EPT_VIOLATION_GPA_EXECUTABLE) + prot |= VM_PROT_EXECUTE; + + return (prot); +} + static boolean_t ept_emulation_fault(uint64_t ept_qual) { @@ -1336,8 +1345,7 @@ vmx_exit_process(struct vmx *vmx, int vc struct vmcs *vmcs; struct vmxctx *vmxctx; uint32_t eax, ecx, edx, idtvec_info, idtvec_err, reason; - uint64_t qual, gpa, rflags; - bool retu; + uint64_t qual, gpa; handled = 0; vmcs = &vmx->vmcs[vcpu]; @@ -1383,46 +1391,31 @@ vmx_exit_process(struct vmx *vmx, int vc break; case EXIT_REASON_RDMSR: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_RDMSR, 1); - retu = false; ecx = vmxctx->guest_rcx; - error = emulate_rdmsr(vmx->vm, vcpu, ecx, &retu); + error = emulate_rdmsr(vmx->vm, vcpu, ecx); if (error) { vmexit->exitcode = VM_EXITCODE_RDMSR; vmexit->u.msr.code = ecx; - } else if (!retu) { + } else handled = 1; - } else { - /* Return to userspace with a valid exitcode */ - KASSERT(vmexit->exitcode != VM_EXITCODE_BOGUS, - ("emulate_wrmsr retu with bogus exitcode")); - } break; case EXIT_REASON_WRMSR: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_WRMSR, 1); - retu = false; eax = vmxctx->guest_rax; ecx = vmxctx->guest_rcx; edx = vmxctx->guest_rdx; error = emulate_wrmsr(vmx->vm, vcpu, ecx, - (uint64_t)edx << 32 | eax, &retu); + (uint64_t)edx << 32 | eax); if (error) { vmexit->exitcode = VM_EXITCODE_WRMSR; vmexit->u.msr.code = ecx; vmexit->u.msr.wval = (uint64_t)edx << 32 | eax; - } else if (!retu) { + } else handled = 1; - } else { - /* Return to userspace with a valid exitcode */ - KASSERT(vmexit->exitcode != VM_EXITCODE_BOGUS, - ("emulate_wrmsr retu with bogus exitcode")); - } break; case EXIT_REASON_HLT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_HLT, 1); - if ((error = vmread(VMCS_GUEST_RFLAGS, &rflags)) != 0) - panic("vmx_exit_process: vmread(rflags) %d", error); vmexit->exitcode = VM_EXITCODE_HLT; - vmexit->u.hlt.rflags = rflags; break; case EXIT_REASON_MTF: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_MTRAP, 1); @@ -1435,7 +1428,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); - VCPU_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting"); + VMM_CTR0(vmx->vm, vcpu, "Disabling interrupt window exiting"); return (1); case EXIT_REASON_EXT_INTR: /* @@ -1458,7 +1451,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); - VCPU_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting"); + VMM_CTR0(vmx->vm, vcpu, "Disabling NMI window exiting"); return (1); case EXIT_REASON_INOUT: vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1); @@ -1486,6 +1479,7 @@ vmx_exit_process(struct vmx *vmx, int vc vmexit->exitcode = VM_EXITCODE_PAGING; vmexit->u.paging.gpa = gpa; vmexit->u.paging.fault_type = ept_fault_type(qual); + vmexit->u.paging.protection = ept_protection(qual); } else if (ept_emulation_fault(qual)) { vmexit->exitcode = VM_EXITCODE_INST_EMUL; vmexit->u.inst_emul.gpa = gpa; @@ -1576,6 +1570,7 @@ vmx_run(void *arg, int vcpu, register_t panic("vmx_run: error %d setting up pcpu defaults", error); do { + lapic_timer_tick(vmx->vm, vcpu); vmx_inject_interrupts(vmx, vcpu); vmx_run_trace(vmx, vcpu); rc = vmx_setjmp(vmxctx); @@ -1657,7 +1652,7 @@ vmx_run(void *arg, int vcpu, register_t if (!handled) vmm_stat_incr(vmx->vm, vcpu, VMEXIT_USERSPACE, 1); - VCPU_CTR1(vmx->vm, vcpu, "goto userland: exitcode %d",vmexit->exitcode); + VMM_CTR1(vmx->vm, vcpu, "goto userland: exitcode %d",vmexit->exitcode); /* * XXX @@ -1937,10 +1932,6 @@ vmx_getcap(void *arg, int vcpu, int type if (cap_unrestricted_guest) ret = 0; break; - case VM_CAP_ENABLE_INVPCID: - if (cap_invpcid) - ret = 0; - break; default: break; } @@ -1997,21 +1988,11 @@ vmx_setcap(void *arg, int vcpu, int type case VM_CAP_UNRESTRICTED_GUEST: if (cap_unrestricted_guest) { retval = 0; - pptr = &vmx->cap[vcpu].proc_ctls2; - baseval = *pptr; + baseval = procbased_ctls2; flag = PROCBASED2_UNRESTRICTED_GUEST; reg = VMCS_SEC_PROC_BASED_CTLS; } break; - case VM_CAP_ENABLE_INVPCID: - if (cap_invpcid) { - retval = 0; - pptr = &vmx->cap[vcpu].proc_ctls2; - baseval = *pptr; - flag = PROCBASED2_ENABLE_INVPCID; - reg = VMCS_SEC_PROC_BASED_CTLS; - } - break; default: break; } Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmx.h ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vmx.h Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vmx.h Tue Feb 4 05:03:14 2014 (r261457) @@ -84,7 +84,6 @@ struct vmxctx { struct vmxcap { int set; uint32_t proc_ctls; - uint32_t proc_ctls2; }; struct vmxstate { Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmx_controls.h ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vmx_controls.h Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vmx_controls.h Tue Feb 4 05:03:14 2014 (r261457) @@ -56,7 +56,7 @@ #define PROCBASED_MSR_BITMAPS (1 << 28) #define PROCBASED_MONITOR_EXITING (1 << 29) #define PROCBASED_PAUSE_EXITING (1 << 30) -#define PROCBASED_SECONDARY_CONTROLS (1U << 31) +#define PROCBASED_SECONDARY_CONTROLS (1 << 31) /* Secondary Processor-Based VM-Execution Controls */ #define PROCBASED2_VIRTUALIZE_APIC (1 << 0) @@ -68,7 +68,6 @@ #define PROCBASED2_WBINVD_EXITING (1 << 6) #define PROCBASED2_UNRESTRICTED_GUEST (1 << 7) #define PROCBASED2_PAUSE_LOOP_EXITING (1 << 10) -#define PROCBASED2_ENABLE_INVPCID (1 << 12) /* VM Exit Controls */ #define VM_EXIT_SAVE_DEBUG_CONTROLS (1 << 2) Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vmx_genassym.c ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vmx_genassym.c Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vmx_genassym.c Tue Feb 4 05:03:14 2014 (r261457) @@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include #include "vmx.h" #include "vmx_cpufunc.h" Modified: projects/bhyve_svm/sys/amd64/vmm/intel/vtd.c ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/intel/vtd.c Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/intel/vtd.c Tue Feb 4 05:03:14 2014 (r261457) @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include @@ -73,11 +74,11 @@ struct vtdmap { #define VTD_GCR_WBF (1 << 27) #define VTD_GCR_SRTP (1 << 30) -#define VTD_GCR_TE (1U << 31) +#define VTD_GCR_TE (1 << 31) #define VTD_GSR_WBFS (1 << 27) #define VTD_GSR_RTPS (1 << 30) -#define VTD_GSR_TES (1U << 31) +#define VTD_GSR_TES (1 << 31) #define VTD_CCR_ICC (1UL << 63) /* invalidate context cache */ #define VTD_CCR_CIRG_GLOBAL (1UL << 61) /* global invalidation */ Modified: projects/bhyve_svm/sys/amd64/vmm/io/ppt.c ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/io/ppt.c Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/io/ppt.c Tue Feb 4 05:03:14 2014 (r261457) @@ -421,7 +421,7 @@ pptintr(void *arg) vec = pptarg->vec; if (ppt->vm != NULL) - lapic_intr_edge(ppt->vm, pptarg->vcpu, vec); + (void) lapic_set_intr(ppt->vm, pptarg->vcpu, vec); else { /* * XXX Copied: projects/bhyve_svm/sys/amd64/vmm/io/vdev.c (from r261451, projects/bhyve_svm/sys/amd64/vmm/io/vdev.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/bhyve_svm/sys/amd64/vmm/io/vdev.c Tue Feb 4 05:03:14 2014 (r261457, copy of r261451, projects/bhyve_svm/sys/amd64/vmm/io/vdev.c) @@ -0,0 +1,270 @@ +/*- + * Copyright (c) 2011 NetApp, Inc. + * 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$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "vdev.h" + +struct vdev { + SLIST_ENTRY(vdev) entry; + struct vdev_ops *ops; + void *dev; +}; +static SLIST_HEAD(, vdev) vdev_head; +static int vdev_count; + +struct vdev_region { + SLIST_ENTRY(vdev_region) entry; + struct vdev_ops *ops; + void *dev; + struct io_region *io; +}; +static SLIST_HEAD(, vdev_region) region_head; +static int region_count; + +static MALLOC_DEFINE(M_VDEV, "vdev", "vdev"); + +#define VDEV_INIT (0) +#define VDEV_RESET (1) +#define VDEV_HALT (2) + +// static const char* vdev_event_str[] = {"VDEV_INIT", "VDEV_RESET", "VDEV_HALT"}; + +static int +vdev_system_event(int event) +{ + struct vdev *vd; + int rc; + + // TODO: locking + SLIST_FOREACH(vd, &vdev_head, entry) { + // printf("%s : %s Device %s\n", __func__, vdev_event_str[event], vd->ops->name); + switch (event) { + case VDEV_INIT: + rc = vd->ops->init(vd->dev); + break; + case VDEV_RESET: + rc = vd->ops->reset(vd->dev); + break; + case VDEV_HALT: + rc = vd->ops->halt(vd->dev); + break; + default: + break; + } + if (rc) { + printf("vdev %s init failed rc=%d\n", + vd->ops->name, rc); + return rc; + } + } + return 0; +} + +int +vdev_init(void) +{ + return vdev_system_event(VDEV_INIT); +} + +int +vdev_reset(void) +{ + return vdev_system_event(VDEV_RESET); +} + +int +vdev_halt(void) +{ + return vdev_system_event(VDEV_HALT); +} + +void +vdev_vm_init(void) +{ + SLIST_INIT(&vdev_head); + vdev_count = 0; + + SLIST_INIT(®ion_head); + region_count = 0; +} +void +vdev_vm_cleanup(void) +{ + struct vdev *vd; + + // TODO: locking + while (!SLIST_EMPTY(&vdev_head)) { + vd = SLIST_FIRST(&vdev_head); + SLIST_REMOVE_HEAD(&vdev_head, entry); + free(vd, M_VDEV); + vdev_count--; + } +} + +int +vdev_register(struct vdev_ops *ops, void *dev) +{ + struct vdev *vd; + vd = malloc(sizeof(*vd), M_VDEV, M_WAITOK | M_ZERO); + vd->ops = ops; + vd->dev = dev; + + // TODO: locking + SLIST_INSERT_HEAD(&vdev_head, vd, entry); + vdev_count++; + return 0; +} + +void +vdev_unregister(void *dev) +{ + struct vdev *vd, *found; + + found = NULL; + // TODO: locking + SLIST_FOREACH(vd, &vdev_head, entry) { + if (vd->dev == dev) { + found = vd; + } + } + + if (found) { + SLIST_REMOVE(&vdev_head, found, vdev, entry); + free(found, M_VDEV); + } +} + +#define IN_RANGE(val, start, end) \ + (((val) >= (start)) && ((val) < (end))) + +static struct vdev_region* +vdev_find_region(struct io_region *io, void *dev) +{ + struct vdev_region *region, *found; + uint64_t region_base; + uint64_t region_end; + + found = NULL; + + // TODO: locking + // FIXME: we should verify we are in the context the current + // vcpu here as well. + SLIST_FOREACH(region, ®ion_head, entry) { + region_base = region->io->base; + region_end = region_base + region->io->len; + if (IN_RANGE(io->base, region_base, region_end) && + IN_RANGE(io->base+io->len, region_base, region_end+1) && + (dev && dev == region->dev)) { + found = region; + break; + } + } + return found; +} + +int +vdev_register_region(struct vdev_ops *ops, void *dev, struct io_region *io) +{ + struct vdev_region *region; + + region = vdev_find_region(io, dev); + if (region) { + return -EEXIST; + } + + region = malloc(sizeof(*region), M_VDEV, M_WAITOK | M_ZERO); + region->io = io; + region->ops = ops; + region->dev = dev; + + // TODO: locking + SLIST_INSERT_HEAD(®ion_head, region, entry); + region_count++; + + return 0; +} + +void +vdev_unregister_region(void *dev, struct io_region *io) +{ + struct vdev_region *region; + + region = vdev_find_region(io, dev); + + if (region) { + SLIST_REMOVE(®ion_head, region, vdev_region, entry); + free(region, M_VDEV); + region_count--; + } +} + +static int +vdev_memrw(uint64_t gpa, opsize_t size, uint64_t *data, int read) +{ + struct vdev_region *region; + struct io_region io; + region_attr_t attr; + int rc; + + io.base = gpa; + io.len = size; + + region = vdev_find_region(&io, NULL); + if (!region) + return -EINVAL; + + attr = (read) ? MMIO_READ : MMIO_WRITE; + if (!(region->io->attr & attr)) + return -EPERM; + + if (read) + rc = region->ops->memread(region->dev, gpa, size, data); + else + rc = region->ops->memwrite(region->dev, gpa, size, *data); + + return rc; +} + +int +vdev_memread(uint64_t gpa, opsize_t size, uint64_t *data) +{ + return vdev_memrw(gpa, size, data, 1); +} + +int +vdev_memwrite(uint64_t gpa, opsize_t size, uint64_t data) +{ + return vdev_memrw(gpa, size, &data, 0); +} Copied: projects/bhyve_svm/sys/amd64/vmm/io/vdev.h (from r261451, projects/bhyve_svm/sys/amd64/vmm/io/vdev.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/bhyve_svm/sys/amd64/vmm/io/vdev.h Tue Feb 4 05:03:14 2014 (r261457, copy of r261451, projects/bhyve_svm/sys/amd64/vmm/io/vdev.h) @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2011 NetApp, Inc. + * 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 _VDEV_H_ +#define _VDEV_H_ + +typedef enum { + BYTE = 1, + WORD = 2, + DWORD = 4, + QWORD = 8, +} opsize_t; + +typedef enum { + MMIO_READ = 1, + MMIO_WRITE = 2, +} region_attr_t; + +struct io_region { + uint64_t base; + uint64_t len; + region_attr_t attr; + int vcpu; +}; + +typedef int (*vdev_init_t)(void* dev); +typedef int (*vdev_reset_t)(void* dev); +typedef int (*vdev_halt_t)(void* dev); +typedef int (*vdev_memread_t)(void* dev, uint64_t gpa, opsize_t size, uint64_t *data); +typedef int (*vdev_memwrite_t)(void* dev, uint64_t gpa, opsize_t size, uint64_t data); + + +struct vdev_ops { + const char *name; + vdev_init_t init; + vdev_reset_t reset; + vdev_halt_t halt; + vdev_memread_t memread; + vdev_memwrite_t memwrite; +}; + + +void vdev_vm_init(void); +void vdev_vm_cleanup(void); + +int vdev_register(struct vdev_ops *ops, void *dev); +void vdev_unregister(void *dev); + +int vdev_register_region(struct vdev_ops *ops, void *dev, struct io_region *io); +void vdev_unregister_region(void *dev, struct io_region *io); + +int vdev_init(void); +int vdev_reset(void); +int vdev_halt(void); +int vdev_memread(uint64_t gpa, opsize_t size, uint64_t *data); +int vdev_memwrite(uint64_t gpa, opsize_t size, uint64_t data); + +#endif /* _VDEV_H_ */ + Modified: projects/bhyve_svm/sys/amd64/vmm/io/vlapic.c ============================================================================== --- projects/bhyve_svm/sys/amd64/vmm/io/vlapic.c Tue Feb 4 03:59:35 2014 (r261456) +++ projects/bhyve_svm/sys/amd64/vmm/io/vlapic.c Tue Feb 4 05:03:14 2014 (r261457) @@ -30,10 +30,8 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include -#include #include #include @@ -46,17 +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) \ - VCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) + VMM_CTR0((vlapic)->vm, (vlapic)->vcpuid, format) #define VLAPIC_CTR1(vlapic, format, p1) \ - VCPU_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) - -#define VLAPIC_CTR2(vlapic, format, p1, p2) \ - VCPU_CTR2((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2) + VMM_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1) #define VLAPIC_CTR_IRR(vlapic, msg) \ do { \ @@ -105,15 +100,14 @@ struct vlapic { struct vm *vm; int vcpuid; - struct LAPIC apic; + struct io_region *mmio; + struct vdev_ops *ops; + struct LAPIC apic; int esr_update; - struct callout callout; /* vlapic timer */ - struct bintime timer_fire_bt; /* callout expiry time */ - struct bintime timer_freq_bt; /* timer frequency */ - struct bintime timer_period_bt; /* timer period */ - struct mtx timer_mtx; + int divisor; + int ccr_ticks; /* * The 'isrvec_stk' is a stack of vectors injected by the local apic. @@ -128,21 +122,6 @@ struct vlapic { enum boot_state boot_state; }; -/* - * The 'vlapic->timer_mtx' is used to provide mutual exclusion between the - * vlapic_callout_handler() and vcpu accesses to the following registers: - * - initial count register aka icr_timer - * - current count register aka ccr_timer - * - divide config register aka dcr_timer - * - timer LVT register - * - * Note that the vlapic_callout_handler() does not write to any of these - * registers so they can be safely read from the vcpu context without locking. - */ -#define VLAPIC_TIMER_LOCK(vlapic) mtx_lock_spin(&((vlapic)->timer_mtx)) -#define VLAPIC_TIMER_UNLOCK(vlapic) mtx_unlock_spin(&((vlapic)->timer_mtx)) -#define VLAPIC_TIMER_LOCKED(vlapic) mtx_owned(&((vlapic)->timer_mtx)) - #define VLAPIC_BUS_FREQ tsc_freq static int @@ -190,62 +169,11 @@ vlapic_dump_lvt(uint32_t offset, uint32_ } #endif -static uint32_t +static uint64_t vlapic_get_ccr(struct vlapic *vlapic) { - struct bintime bt_now, bt_rem; - struct LAPIC *lapic; - uint32_t ccr; - - ccr = 0; - lapic = &vlapic->apic; - - VLAPIC_TIMER_LOCK(vlapic); - if (callout_active(&vlapic->callout)) { - /* - * If the timer is scheduled to expire in the future then - * compute the value of 'ccr' based on the remaining time. - */ - binuptime(&bt_now); - if (bintime_cmp(&vlapic->timer_fire_bt, &bt_now, >)) { - bt_rem = vlapic->timer_fire_bt; - bintime_sub(&bt_rem, &bt_now); - ccr += bt_rem.sec * BT2FREQ(&vlapic->timer_freq_bt); - ccr += bt_rem.frac / vlapic->timer_freq_bt.frac; - } - } - KASSERT(ccr <= lapic->icr_timer, ("vlapic_get_ccr: invalid ccr %#x, " - "icr_timer is %#x", ccr, lapic->icr_timer)); - VLAPIC_CTR2(vlapic, "vlapic ccr_timer = %#x, icr_timer = %#x", - ccr, lapic->icr_timer); - VLAPIC_TIMER_UNLOCK(vlapic); - return (ccr); -} - -static void -vlapic_set_dcr(struct vlapic *vlapic, uint32_t dcr) -{ - struct LAPIC *lapic; - int divisor; - - lapic = &vlapic->apic; - VLAPIC_TIMER_LOCK(vlapic); - - lapic->dcr_timer = dcr; - divisor = vlapic_timer_divisor(dcr); - VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d", dcr, divisor); - - /* - * Update the timer frequency and the timer period. - * - * XXX changes to the frequency divider will not take effect until - * the timer is reloaded. - */ - FREQ2BT(VLAPIC_BUS_FREQ / divisor, &vlapic->timer_freq_bt); - vlapic->timer_period_bt = vlapic->timer_freq_bt; - bintime_mul(&vlapic->timer_period_bt, lapic->icr_timer); - - VLAPIC_TIMER_UNLOCK(vlapic); + struct LAPIC *lapic = &vlapic->apic; + return lapic->ccr_timer; } static void @@ -267,14 +195,15 @@ vlapic_init_ipi(struct vlapic *vlapic) } static int -vlapic_reset(struct vlapic *vlapic) +vlapic_op_reset(void* dev) { + struct vlapic *vlapic = (struct vlapic*)dev; struct LAPIC *lapic = &vlapic->apic; memset(lapic, 0, sizeof(*lapic)); lapic->apr = vlapic->vcpuid; vlapic_init_ipi(vlapic); - vlapic_set_dcr(vlapic, 0); + vlapic->divisor = vlapic_timer_divisor(lapic->dcr_timer); if (vlapic->vcpuid == 0) vlapic->boot_state = BS_RUNNING; /* BSP */ @@ -285,44 +214,63 @@ vlapic_reset(struct vlapic *vlapic) } +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, bool level) +vlapic_set_intr_ready(struct vlapic *vlapic, int vector) { struct LAPIC *lapic = &vlapic->apic; - uint32_t *irrptr, *tmrptr, mask; + uint32_t *irrptr; int idx; if (vector < 0 || vector >= 256) panic("vlapic_set_intr_ready: invalid vector %d\n", vector); - if (!(lapic->svr & APIC_SVR_ENABLE)) { - VLAPIC_CTR1(vlapic, "vlapic is software disabled, ignoring " - "interrupt %d", vector); - return; - } - idx = (vector / 32) * 4; - mask = 1 << (vector % 32); - irrptr = &lapic->irr0; - atomic_set_int(&irrptr[idx], mask); + atomic_set_int(&irrptr[idx], 1 << (vector % 32)); + VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); +} - /* - * 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); +static void +vlapic_start_timer(struct vlapic *vlapic, uint32_t elapsed) +{ + uint32_t icr_timer; - VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready"); + icr_timer = vlapic->apic.icr_timer; + + vlapic->ccr_ticks = ticks; + if (elapsed < icr_timer) + vlapic->apic.ccr_timer = icr_timer - elapsed; + else { + /* + * This can happen when the guest is trying to run its local + * apic timer higher that the setting of 'hz' in the host. + * + * We deal with this by running the guest local apic timer + * at the rate of the host's 'hz' setting. + */ + vlapic->apic.ccr_timer = 0; + } } static __inline uint32_t * -vlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset) +vlapic_get_lvt(struct vlapic *vlapic, uint32_t offset) { struct LAPIC *lapic = &vlapic->apic; int i; @@ -334,33 +282,6 @@ vlapic_get_lvtptr(struct vlapic *vlapic, return ((&lapic->lvt_timer) + i);; } -static __inline uint32_t *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***