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-all
mailing list