Date: Fri, 23 May 2014 19:59:14 +0000 (UTC) From: Neel Natu <neel@FreeBSD.org> 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 Message-ID: <201405231959.s4NJxEx3021385@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 <machine/vmm.h> +#include <assert.h> #include <vmmapi.h> +#define KASSERT(exp,msg) assert((exp)) #endif /* _KERNEL */ +#include <x86/psl.h> +#include <x86/specialreg.h> + /* 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 <sys/linker_set.h> #include <x86/psl.h> +#include <x86/segments.h> #include <machine/vmm.h> #include <vmmapi.h> @@ -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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405231959.s4NJxEx3021385>