From owner-svn-src-all@FreeBSD.ORG Thu Jul 24 01:38:13 2014 Return-Path: Delivered-To: svn-src-all@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 7DF5358E; Thu, 24 Jul 2014 01:38:13 +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)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 69A482189; Thu, 24 Jul 2014 01:38:13 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s6O1cD2n014574; Thu, 24 Jul 2014 01:38:13 GMT (envelope-from neel@svn.freebsd.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s6O1cCaT014560; Thu, 24 Jul 2014 01:38:12 GMT (envelope-from neel@svn.freebsd.org) Message-Id: <201407240138.s6O1cCaT014560@svn.freebsd.org> From: Neel Natu Date: Thu, 24 Jul 2014 01:38:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r269042 - in head: lib/libvmmapi sys/amd64/include sys/amd64/vmm usr.sbin/bhyve X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Jul 2014 01:38:13 -0000 Author: neel Date: Thu Jul 24 01:38:11 2014 New Revision: 269042 URL: http://svnweb.freebsd.org/changeset/base/269042 Log: Fix fault injection in bhyve. The faulting instruction needs to be restarted when the exception handler is done handling the fault. bhyve now does this correctly by setting 'vmexit[vcpu].inst_length' to zero so the %rip is not advanced. A minor complication is that the fault injection APIs are used by instruction emulation code that is shared by vmm.ko and bhyve. Thus the argument that refers to 'struct vm *' in kernel or 'struct vmctx *' in userspace needs to be loosely typed as a 'void *'. Modified: head/lib/libvmmapi/vmmapi.c head/lib/libvmmapi/vmmapi.h head/sys/amd64/include/vmm.h head/sys/amd64/vmm/vmm.c head/usr.sbin/bhyve/bhyverun.c head/usr.sbin/bhyve/inout.c head/usr.sbin/bhyve/task_switch.c Modified: head/lib/libvmmapi/vmmapi.c ============================================================================== --- head/lib/libvmmapi/vmmapi.c Thu Jul 24 01:35:41 2014 (r269041) +++ head/lib/libvmmapi/vmmapi.c Thu Jul 24 01:38:11 2014 (r269042) @@ -1146,30 +1146,3 @@ vm_set_intinfo(struct vmctx *ctx, int vc error = ioctl(ctx->fd, VM_SET_INTINFO, &vmii); return (error); } - -void -vm_inject_ss(struct vmctx *ctx, int vcpu, int errcode) -{ - int error; - - error = vm_inject_exception2(ctx, vcpu, IDT_SS, errcode); - assert(error == 0); -} - -void -vm_inject_ac(struct vmctx *ctx, int vcpu, int errcode) -{ - int error; - - error = vm_inject_exception2(ctx, vcpu, IDT_AC, errcode); - assert(error == 0); -} - -void -vm_inject_gp(struct vmctx *ctx, int vcpu, int errcode) -{ - int error; - - error = vm_inject_exception2(ctx, vcpu, IDT_GP, errcode); - assert(error == 0); -} Modified: head/lib/libvmmapi/vmmapi.h ============================================================================== --- head/lib/libvmmapi/vmmapi.h Thu Jul 24 01:35:41 2014 (r269041) +++ head/lib/libvmmapi/vmmapi.h Thu Jul 24 01:38:11 2014 (r269042) @@ -133,11 +133,6 @@ void vm_copyin(struct vmctx *ctx, int vc void vm_copyout(struct vmctx *ctx, int vcpu, const void *host_src, struct iovec *guest_iov, size_t len); -/* Helper functions to inject exceptions */ -void vm_inject_ss(struct vmctx *ctx, int vcpu, int errcode); -void vm_inject_ac(struct vmctx *ctx, int vcpu, int errcode); -void vm_inject_gp(struct vmctx *ctx, int vcpu, int errcode); - /* Reset vcpu register state */ int vcpu_reset(struct vmctx *ctx, int vcpu); Modified: head/sys/amd64/include/vmm.h ============================================================================== --- head/sys/amd64/include/vmm.h Thu Jul 24 01:35:41 2014 (r269041) +++ head/sys/amd64/include/vmm.h Thu Jul 24 01:38:11 2014 (r269042) @@ -29,6 +29,8 @@ #ifndef _VMM_H_ #define _VMM_H_ +#include + enum vm_suspend_how { VM_SUSPEND_NONE, VM_SUSPEND_RESET, @@ -316,12 +318,6 @@ int vm_entry_intinfo(struct vm *vm, int int vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2); -void vm_inject_gp(struct vm *vm, int vcpuid); /* general protection fault */ -void vm_inject_ud(struct vm *vm, int vcpuid); /* undefined instruction fault */ -void vm_inject_ac(struct vm *vm, int vcpuid, int errcode); /* #AC */ -void vm_inject_ss(struct vm *vm, int vcpuid, int errcode); /* #SS */ -void vm_inject_pf(struct vm *vm, int vcpuid, int error_code, uint64_t cr2); - enum vm_reg_name vm_segment_name(int seg_encoding); struct vm_copyinfo { @@ -579,4 +575,34 @@ struct vm_exit { } u; }; +/* APIs to inject faults into the guest */ +void vm_inject_fault(void *vm, int vcpuid, int vector, int errcode_valid, + int errcode); + +static void __inline +vm_inject_ud(void *vm, int vcpuid) +{ + vm_inject_fault(vm, vcpuid, IDT_UD, 0, 0); +} + +static void __inline +vm_inject_gp(void *vm, int vcpuid) +{ + vm_inject_fault(vm, vcpuid, IDT_GP, 1, 0); +} + +static void __inline +vm_inject_ac(void *vm, int vcpuid, int errcode) +{ + vm_inject_fault(vm, vcpuid, IDT_AC, 1, errcode); +} + +static void __inline +vm_inject_ss(void *vm, int vcpuid, int errcode) +{ + vm_inject_fault(vm, vcpuid, IDT_SS, 1, errcode); +} + +void vm_inject_pf(void *vm, int vcpuid, int error_code, uint64_t cr2); + #endif /* _VMM_H_ */ Modified: head/sys/amd64/vmm/vmm.c ============================================================================== --- head/sys/amd64/vmm/vmm.c Thu Jul 24 01:35:41 2014 (r269041) +++ head/sys/amd64/vmm/vmm.c Thu Jul 24 01:38:11 2014 (r269042) @@ -1689,13 +1689,21 @@ vm_inject_exception(struct vm *vm, int v return (0); } -static void -vm_inject_fault(struct vm *vm, int vcpuid, struct vm_exception *exception) +void +vm_inject_fault(void *vmarg, int vcpuid, int vector, int errcode_valid, + int errcode) { + struct vm_exception exception; struct vm_exit *vmexit; + struct vm *vm; int error; - error = vm_inject_exception(vm, vcpuid, exception); + vm = vmarg; + + exception.vector = vector; + exception.error_code = errcode; + exception.error_code_valid = errcode_valid; + error = vm_inject_exception(vm, vcpuid, &exception); KASSERT(error == 0, ("vm_inject_exception error %d", error)); /* @@ -1710,69 +1718,19 @@ vm_inject_fault(struct vm *vm, int vcpui } void -vm_inject_pf(struct vm *vm, int vcpuid, int error_code, uint64_t cr2) +vm_inject_pf(void *vmarg, int vcpuid, int error_code, uint64_t cr2) { - struct vm_exception pf = { - .vector = IDT_PF, - .error_code_valid = 1, - .error_code = error_code - }; + struct vm *vm; int error; + vm = vmarg; VCPU_CTR2(vm, vcpuid, "Injecting page fault: error_code %#x, cr2 %#lx", error_code, cr2); error = vm_set_register(vm, vcpuid, VM_REG_GUEST_CR2, cr2); KASSERT(error == 0, ("vm_set_register(cr2) error %d", error)); - vm_inject_fault(vm, vcpuid, &pf); -} - -void -vm_inject_gp(struct vm *vm, int vcpuid) -{ - struct vm_exception gpf = { - .vector = IDT_GP, - .error_code_valid = 1, - .error_code = 0 - }; - - vm_inject_fault(vm, vcpuid, &gpf); -} - -void -vm_inject_ud(struct vm *vm, int vcpuid) -{ - struct vm_exception udf = { - .vector = IDT_UD, - .error_code_valid = 0 - }; - - vm_inject_fault(vm, vcpuid, &udf); -} - -void -vm_inject_ac(struct vm *vm, int vcpuid, int error_code) -{ - struct vm_exception acf = { - .vector = IDT_AC, - .error_code_valid = 1, - .error_code = error_code - }; - - vm_inject_fault(vm, vcpuid, &acf); -} - -void -vm_inject_ss(struct vm *vm, int vcpuid, int error_code) -{ - struct vm_exception ssf = { - .vector = IDT_SS, - .error_code_valid = 1, - .error_code = error_code - }; - - vm_inject_fault(vm, vcpuid, &ssf); + vm_inject_fault(vm, vcpuid, IDT_PF, 1, error_code); } static VMM_STAT(VCPU_NMI_COUNT, "number of NMIs delivered to vcpu"); Modified: head/usr.sbin/bhyve/bhyverun.c ============================================================================== --- head/usr.sbin/bhyve/bhyverun.c Thu Jul 24 01:35:41 2014 (r269041) +++ head/usr.sbin/bhyve/bhyverun.c Thu Jul 24 01:38:11 2014 (r269042) @@ -96,7 +96,7 @@ static cpuset_t cpumask; static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip); -struct vm_exit vmexit[VM_MAXCPU]; +static struct vm_exit vmexit[VM_MAXCPU]; struct bhyvestats { uint64_t vmexit_bogus; @@ -182,6 +182,27 @@ pincpu_parse(const char *opt) return (0); } +void +vm_inject_fault(void *arg, int vcpu, int vector, int errcode_valid, + int errcode) +{ + struct vmctx *ctx; + int error; + + ctx = arg; + if (errcode_valid) + error = vm_inject_exception2(ctx, vcpu, vector, errcode); + else + error = vm_inject_exception(ctx, vcpu, vector); + assert(error == 0); + + /* + * Set the instruction length to 0 to ensure that the instruction is + * restarted when the fault handler returns. + */ + vmexit[vcpu].inst_length = 0; +} + void * paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len) { @@ -347,7 +368,7 @@ vmexit_rdmsr(struct vmctx *ctx, struct v fprintf(stderr, "rdmsr to register %#x on vcpu %d\n", vme->u.msr.code, *pvcpu); if (strictmsr) { - vm_inject_gp(ctx, *pvcpu, 0); + vm_inject_gp(ctx, *pvcpu); return (VMEXIT_RESTART); } } @@ -373,7 +394,7 @@ vmexit_wrmsr(struct vmctx *ctx, struct v fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n", vme->u.msr.code, vme->u.msr.wval, *pvcpu); if (strictmsr) { - vm_inject_gp(ctx, *pvcpu, 0); + vm_inject_gp(ctx, *pvcpu); return (VMEXIT_RESTART); } } Modified: head/usr.sbin/bhyve/inout.c ============================================================================== --- head/usr.sbin/bhyve/inout.c Thu Jul 24 01:35:41 2014 (r269041) +++ head/usr.sbin/bhyve/inout.c Thu Jul 24 01:38:11 2014 (r269042) @@ -157,7 +157,7 @@ emulate_inout(struct vmctx *ctx, int vcp if (vie_calculate_gla(vis->paging.cpu_mode, vis->seg_name, &vis->seg_desc, index, bytes, addrsize, prot, &gla)) { - vm_inject_gp(ctx, vcpu, 0); + vm_inject_gp(ctx, vcpu); retval = INOUT_RESTART; break; } Modified: head/usr.sbin/bhyve/task_switch.c ============================================================================== --- head/usr.sbin/bhyve/task_switch.c Thu Jul 24 01:35:41 2014 (r269041) +++ head/usr.sbin/bhyve/task_switch.c Thu Jul 24 01:38:11 2014 (r269042) @@ -160,8 +160,6 @@ usd_to_seg_desc(struct user_segment_desc static void sel_exception(struct vmctx *ctx, int vcpu, int vector, uint16_t sel, int ext) { - int error; - /* * Bit 2 from the selector is retained as-is in the error code. * @@ -174,8 +172,7 @@ sel_exception(struct vmctx *ctx, int vcp sel &= ~0x3; if (ext) sel |= 0x1; - error = vm_inject_exception2(ctx, vcpu, vector, sel); - assert(error == 0); + vm_inject_fault(ctx, vcpu, vector, 1, sel); } static int @@ -508,7 +505,7 @@ tss32_restore(struct vmctx *ctx, int vcp */ reserved = ~maxphyaddr | 0x1E6; if (pdpte[i] & reserved) { - vm_inject_gp(ctx, vcpu, 0); + vm_inject_gp(ctx, vcpu); return (VMEXIT_RESTART); } }