From owner-svn-src-all@FreeBSD.ORG Mon May 26 18:21:10 2014 Return-Path: Delivered-To: svn-src-all@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 F2022455; Mon, 26 May 2014 18:21:09 +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 DE60C2DCB; Mon, 26 May 2014 18:21:09 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4QIL9ip092685; Mon, 26 May 2014 18:21:09 GMT (envelope-from neel@svn.freebsd.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4QIL9Cs092682; Mon, 26 May 2014 18:21:09 GMT (envelope-from neel@svn.freebsd.org) Message-Id: <201405261821.s4QIL9Cs092682@svn.freebsd.org> From: Neel Natu Date: Mon, 26 May 2014 18:21:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r266708 - in head: lib/libvmmapi 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: Mon, 26 May 2014 18:21:10 -0000 Author: neel Date: Mon May 26 18:21:08 2014 New Revision: 266708 URL: http://svnweb.freebsd.org/changeset/base/266708 Log: Fix issue with restarting an "insb/insw/insl" instruction because of a page fault on the destination buffer. Prior to this change a page fault would be detected in vm_copyout(). This was done after the I/O port access was done. If the I/O port access had side-effects (e.g. reading the uart FIFO) then restarting the instruction would result in incorrect behavior. Fix this by validating the guest linear address before doing the I/O port emulation. If the validation results in a page fault exception being injected into the guest then the instruction can now be restarted without any side-effects. Modified: head/lib/libvmmapi/vmmapi.c head/lib/libvmmapi/vmmapi.h head/usr.sbin/bhyve/inout.c Modified: head/lib/libvmmapi/vmmapi.c ============================================================================== --- head/lib/libvmmapi/vmmapi.c Mon May 26 18:02:36 2014 (r266707) +++ head/lib/libvmmapi/vmmapi.c Mon May 26 18:21:08 2014 (r266708) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -940,7 +941,7 @@ vm_get_hpet_capabilities(struct vmctx *c } static int -vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, +gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, uint64_t gla, int prot, int *fault, uint64_t *gpa) { struct vm_gla2gpa gg; @@ -965,18 +966,20 @@ vm_gla2gpa(struct vmctx *ctx, int vcpu, #endif int -vm_copyin(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - uint64_t gla, void *vp, size_t len) +vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, + uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt) { - char *dst; - const char *src; uint64_t gpa; - int error, fault, n, off; + int error, fault, i, n, off; + + for (i = 0; i < iovcnt; i++) { + iov[i].iov_base = 0; + iov[i].iov_len = 0; + } - dst = vp; while (len) { - error = vm_gla2gpa(ctx, vcpu, paging, gla, PROT_READ, - &fault, &gpa); + assert(iovcnt > 0); + error = gla2gpa(ctx, vcpu, paging, gla, prot, &fault, &gpa); if (error) return (-1); if (fault) @@ -984,42 +987,59 @@ vm_copyin(struct vmctx *ctx, int vcpu, s off = gpa & PAGE_MASK; n = min(len, PAGE_SIZE - off); - src = vm_map_gpa(ctx, gpa, n); - bcopy(src, dst, n); + + iov->iov_base = (void *)gpa; + iov->iov_len = n; + iov++; + iovcnt--; gla += n; - dst += n; len -= n; } return (0); } -int -vm_copyout(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - const void *vp, uint64_t gla, size_t len) +void +vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *iov, void *vp, size_t len) { - uint64_t gpa; + const char *src; char *dst; + uint64_t gpa; + size_t n; + + dst = vp; + while (len) { + assert(iov->iov_len); + gpa = (uint64_t)iov->iov_base; + n = min(len, iov->iov_len); + src = vm_map_gpa(ctx, gpa, n); + bcopy(src, dst, n); + + iov++; + dst += n; + len -= n; + } +} + +void +vm_copyout(struct vmctx *ctx, int vcpu, const void *vp, struct iovec *iov, + size_t len) +{ const char *src; - int error, fault, n, off; + char *dst; + uint64_t gpa; + size_t n; src = vp; while (len) { - error = vm_gla2gpa(ctx, vcpu, paging, gla, PROT_WRITE, - &fault, &gpa); - if (error) - return (-1); - if (fault) - return (1); - - off = gpa & PAGE_MASK; - n = min(len, PAGE_SIZE - off); + assert(iov->iov_len); + gpa = (uint64_t)iov->iov_base; + n = min(len, iov->iov_len); dst = vm_map_gpa(ctx, gpa, n); bcopy(src, dst, n); - gla += n; + iov++; src += n; len -= n; } - return (0); } Modified: head/lib/libvmmapi/vmmapi.h ============================================================================== --- head/lib/libvmmapi/vmmapi.h Mon May 26 18:02:36 2014 (r266707) +++ head/lib/libvmmapi/vmmapi.h Mon May 26 18:21:08 2014 (r266708) @@ -29,6 +29,7 @@ #ifndef _VMMAPI_H_ #define _VMMAPI_H_ +struct iovec; struct vmctx; enum x2apic_state; @@ -109,10 +110,17 @@ int vm_set_x2apic_state(struct vmctx *ct int vm_get_hpet_capabilities(struct vmctx *ctx, uint32_t *capabilities); -int vm_copyin(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - uint64_t gla_src, void *dst, size_t len); -int vm_copyout(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, - const void *src, uint64_t gla_dst, size_t len); +/* + * Translate the GLA range [gla,gla+len) into GPA segments in 'iov'. + * The 'iovcnt' should be big enough to accomodate all GPA segments. + * Returns 0 on success, 1 on a guest fault condition and -1 otherwise. + */ +int vm_gla2gpa(struct vmctx *ctx, int vcpu, struct vm_guest_paging *paging, + uint64_t gla, size_t len, int prot, struct iovec *iov, int iovcnt); +void vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *guest_iov, + void *host_dst, size_t len); +void vm_copyout(struct vmctx *ctx, int vcpu, const void *host_src, + struct iovec *guest_iov, size_t len); /* Reset vcpu register state */ int vcpu_reset(struct vmctx *ctx, int vcpu); Modified: head/usr.sbin/bhyve/inout.c ============================================================================== --- head/usr.sbin/bhyve/inout.c Mon May 26 18:02:36 2014 (r266707) +++ head/usr.sbin/bhyve/inout.c Mon May 26 18:21:08 2014 (r266708) @@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include #include #include @@ -109,6 +111,7 @@ emulate_inout(struct vmctx *ctx, int vcp enum vm_reg_name idxreg; uint64_t gla, index, count; struct vm_inout_str *vis; + struct iovec iov[2]; bytes = vmexit->u.inout.bytes; in = vmexit->u.inout.in; @@ -157,6 +160,15 @@ emulate_inout(struct vmctx *ctx, int vcp return (INOUT_RESTART); } + error = vm_gla2gpa(ctx, vcpu, &vis->paging, gla, bytes, + in ? PROT_WRITE : PROT_READ, iov, nitems(iov)); + assert(error == 0 || error == 1 || error == -1); + if (error) { + retval = (error == 1) ? INOUT_RESTART : + INOUT_ERROR; + break; + } + if (vie_alignment_check(vis->paging.cpl, bytes, vis->cr0, vis->rflags, gla)) { error = vm_inject_exception2(ctx, vcpu, @@ -165,33 +177,16 @@ emulate_inout(struct vmctx *ctx, int vcp return (INOUT_RESTART); } - val = 0; - if (!in) { - error = vm_copyin(ctx, vcpu, &vis->paging, - gla, &val, bytes); - assert(error == 0 || error == 1 || error == -1); - if (error) { - retval = (error == 1) ? INOUT_RESTART : - INOUT_ERROR; - break; - } - } + if (!in) + vm_copyin(ctx, vcpu, iov, &val, bytes); retval = handler(ctx, vcpu, in, port, bytes, &val, arg); if (retval != 0) break; - if (in) { - error = vm_copyout(ctx, vcpu, &vis->paging, - &val, gla, bytes); - assert(error == 0 || error == 1 || error == -1); - if (error) { - retval = (error == 1) ? INOUT_RESTART : - INOUT_ERROR; - break; - } - } + if (in) + vm_copyout(ctx, vcpu, &val, iov, bytes); /* Update index */ if (vis->rflags & PSL_D)