svn commit: r266595 - in head: sys/amd64/include sys/amd64/vmm usr.sbin/bhyve

Neel Natu neel at FreeBSD.org
Fri May 23 19:59:15 UTC 2014


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);


More information about the svn-src-head mailing list