From owner-svn-src-head@FreeBSD.ORG Fri May 23 19:59:15 2014 Return-Path: Delivered-To: svn-src-head@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 836357BD; Fri, 23 May 2014 19:59:15 +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 6FA4320C2; Fri, 23 May 2014 19:59:15 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4NJxF1a021389; Fri, 23 May 2014 19:59:15 GMT (envelope-from neel@svn.freebsd.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4NJxEx3021385; Fri, 23 May 2014 19:59:14 GMT (envelope-from neel@svn.freebsd.org) Message-Id: <201405231959.s4NJxEx3021385@svn.freebsd.org> From: Neel Natu Date: Fri, 23 May 2014 19:59:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r266595 - in head: 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-head@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 May 2014 19:59:15 -0000 Author: neel Date: Fri May 23 19:59:14 2014 New Revision: 266595 URL: http://svnweb.freebsd.org/changeset/base/266595 Log: Check for alignment check violation when processing in/out string instructions. Modified: head/sys/amd64/include/vmm_instruction_emul.h head/sys/amd64/vmm/vmm_instruction_emul.c head/sys/amd64/vmm/vmm_ioport.c head/usr.sbin/bhyve/inout.c Modified: head/sys/amd64/include/vmm_instruction_emul.h ============================================================================== --- head/sys/amd64/include/vmm_instruction_emul.h Fri May 23 19:43:20 2014 (r266594) +++ head/sys/amd64/include/vmm_instruction_emul.h Fri May 23 19:59:14 2014 (r266595) @@ -116,6 +116,14 @@ int vmm_emulate_instruction(void *vm, in int vie_update_register(void *vm, int vcpuid, enum vm_reg_name reg, uint64_t val, int size); +/* + * Returns 1 if an alignment check exception should be injected and 0 otherwise. + */ +int vie_alignment_check(int cpl, int operand_size, uint64_t cr0, + uint64_t rflags, uint64_t gla); + +uint64_t vie_size2mask(int size); + #ifdef _KERNEL /* * APIs to fetch and decode the instruction from nested page fault handler. @@ -139,8 +147,6 @@ int vmm_gla2gpa(struct vm *vm, int vcpui void vie_init(struct vie *vie); -uint64_t vie_size2mask(int size); - uint64_t vie_segbase(enum vm_reg_name segment, enum vie_cpu_mode cpu_mode, const struct seg_desc *desc); Modified: head/sys/amd64/vmm/vmm_instruction_emul.c ============================================================================== --- head/sys/amd64/vmm/vmm_instruction_emul.c Fri May 23 19:43:20 2014 (r266594) +++ head/sys/amd64/vmm/vmm_instruction_emul.c Fri May 23 19:59:14 2014 (r266595) @@ -47,9 +47,14 @@ __FBSDID("$FreeBSD$"); #include +#include #include +#define KASSERT(exp,msg) assert((exp)) #endif /* _KERNEL */ +#include +#include + /* struct vie_op.op_type */ enum { VIE_OP_TYPE_NONE = 0, @@ -561,6 +566,27 @@ vmm_emulate_instruction(void *vm, int vc return (error); } +int +vie_alignment_check(int cpl, int size, uint64_t cr0, uint64_t rf, uint64_t gla) +{ + KASSERT(size == 1 || size == 2 || size == 4 || size == 8, + ("%s: invalid size %d", __func__, size)); + KASSERT(cpl >= 0 && cpl <= 3, ("%s: invalid cpl %d", __func__, cpl)); + + if (cpl != 3 || (cr0 & CR0_AM) == 0 || (rf & PSL_AC) == 0) + return (0); + + return ((gla & (size - 1)) ? 1 : 0); +} + +uint64_t +vie_size2mask(int size) +{ + KASSERT(size == 1 || size == 2 || size == 4 || size == 8, + ("vie_size2mask: invalid size %d", size)); + return (size2mask[size]); +} + #ifdef _KERNEL void vie_init(struct vie *vie) @@ -1220,14 +1246,6 @@ vmm_decode_instruction(struct vm *vm, in } uint64_t -vie_size2mask(int size) -{ - KASSERT(size == 1 || size == 2 || size == 4 || size == 8, - ("vie_size2mask: invalid size %d", size)); - return (size2mask[size]); -} - -uint64_t vie_segbase(enum vm_reg_name seg, enum vie_cpu_mode cpu_mode, const struct seg_desc *desc) { Modified: head/sys/amd64/vmm/vmm_ioport.c ============================================================================== --- head/sys/amd64/vmm/vmm_ioport.c Fri May 23 19:43:20 2014 (r266594) +++ head/sys/amd64/vmm/vmm_ioport.c Fri May 23 19:59:14 2014 (r266595) @@ -144,7 +144,7 @@ emulate_inout_str(struct vm *vm, int vcp { struct vm_inout_str *vis; uint64_t gla, index, segbase; - int bytes, error, in; + int error, in; vis = &vmexit->u.inout_str; in = vis->inout.in; @@ -162,14 +162,10 @@ emulate_inout_str(struct vm *vm, int vcp /* * XXX - * inout string emulation only supported in 64-bit mode and only - * for byte instructions. + * inout string emulation only supported in 64-bit mode. * * The #GP(0) fault conditions described above don't apply in * 64-bit mode. - * - * The #AC(0) fault condition described above does not apply - * because byte accesses don't have alignment constraints. */ if (vis->cpu_mode != CPU_MODE_64BIT) { VCPU_CTR1(vm, vcpuid, "ins/outs not emulated in cpu mode %d", @@ -177,13 +173,6 @@ emulate_inout_str(struct vm *vm, int vcp return (EINVAL); } - bytes = vis->inout.bytes; - if (bytes != 1) { - VCPU_CTR1(vm, vcpuid, "ins/outs operand size %d not supported", - bytes); - return (EINVAL); - } - /* * XXX insb/insw/insd instructions not emulated at this time. */ Modified: head/usr.sbin/bhyve/inout.c ============================================================================== --- head/usr.sbin/bhyve/inout.c Fri May 23 19:43:20 2014 (r266594) +++ head/usr.sbin/bhyve/inout.c Fri May 23 19:59:14 2014 (r266595) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -110,13 +111,6 @@ emulate_inout(struct vmctx *ctx, int vcp uint64_t index, count; struct vm_inout_str *vis; - static uint64_t size2mask[] = { - [1] = 0xff, - [2] = 0xffff, - [4] = 0xffffffff, - [8] = 0xffffffffffffffff, - }; - bytes = vmexit->u.inout.bytes; in = vmexit->u.inout.in; port = vmexit->u.inout.port; @@ -149,15 +143,22 @@ emulate_inout(struct vmctx *ctx, int vcp /* Index register */ idxreg = in ? VM_REG_GUEST_RDI : VM_REG_GUEST_RSI; - index = vis->index & size2mask[addrsize]; + index = vis->index & vie_size2mask(addrsize); /* Count register */ - count = vis->count & size2mask[addrsize]; + count = vis->count & vie_size2mask(addrsize); gpa = vis->gpa; gpaend = rounddown(gpa + PAGE_SIZE, PAGE_SIZE); gva = paddr_guest2host(ctx, gpa, gpaend - gpa); + if (vie_alignment_check(vis->cpl, bytes, vis->cr0, + vis->rflags, vis->gla)) { + error = vm_inject_exception2(ctx, vcpu, IDT_AC, 0); + assert(error == 0); + return (INOUT_RESTART); + } + while (count != 0 && gpa < gpaend) { /* * XXX this may not work for unaligned accesses because @@ -209,12 +210,12 @@ emulate_inout(struct vmctx *ctx, int vcp retval = INOUT_RESTART; } else { if (!in) { - val = vmexit->u.inout.eax & size2mask[bytes]; + val = vmexit->u.inout.eax & vie_size2mask(bytes); } retval = handler(ctx, vcpu, in, port, bytes, &val, arg); if (retval == 0 && in) { - vmexit->u.inout.eax &= ~size2mask[bytes]; - vmexit->u.inout.eax |= val & size2mask[bytes]; + vmexit->u.inout.eax &= ~vie_size2mask(bytes); + vmexit->u.inout.eax |= val & vie_size2mask(bytes); } } return (retval);