summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bhyve
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-07-24 01:38:11 +0000
committerneel <neel@FreeBSD.org>2014-07-24 01:38:11 +0000
commit4535fa67c47e242c2d4c579630ebc12d8153d881 (patch)
treef10160daba1a9c8df5c059e74db7b03dcae6f007 /usr.sbin/bhyve
parent57fd2f85267f7e1a29e8cef251c560081842963b (diff)
downloadFreeBSD-src-4535fa67c47e242c2d4c579630ebc12d8153d881.zip
FreeBSD-src-4535fa67c47e242c2d4c579630ebc12d8153d881.tar.gz
Fix fault injection in bhyve.
The faulting instruction needs to be restarted when the exception handler is done handling the fault. bhyve now does this correctly by setting 'vmexit[vcpu].inst_length' to zero so the %rip is not advanced. A minor complication is that the fault injection APIs are used by instruction emulation code that is shared by vmm.ko and bhyve. Thus the argument that refers to 'struct vm *' in kernel or 'struct vmctx *' in userspace needs to be loosely typed as a 'void *'.
Diffstat (limited to 'usr.sbin/bhyve')
-rw-r--r--usr.sbin/bhyve/bhyverun.c27
-rw-r--r--usr.sbin/bhyve/inout.c2
-rw-r--r--usr.sbin/bhyve/task_switch.c7
3 files changed, 27 insertions, 9 deletions
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 26c6e53..e3d5994 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -96,7 +96,7 @@ static cpuset_t cpumask;
static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip);
-struct vm_exit vmexit[VM_MAXCPU];
+static struct vm_exit vmexit[VM_MAXCPU];
struct bhyvestats {
uint64_t vmexit_bogus;
@@ -182,6 +182,27 @@ pincpu_parse(const char *opt)
return (0);
}
+void
+vm_inject_fault(void *arg, int vcpu, int vector, int errcode_valid,
+ int errcode)
+{
+ struct vmctx *ctx;
+ int error;
+
+ ctx = arg;
+ if (errcode_valid)
+ error = vm_inject_exception2(ctx, vcpu, vector, errcode);
+ else
+ error = vm_inject_exception(ctx, vcpu, vector);
+ assert(error == 0);
+
+ /*
+ * Set the instruction length to 0 to ensure that the instruction is
+ * restarted when the fault handler returns.
+ */
+ vmexit[vcpu].inst_length = 0;
+}
+
void *
paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
{
@@ -347,7 +368,7 @@ vmexit_rdmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
fprintf(stderr, "rdmsr to register %#x on vcpu %d\n",
vme->u.msr.code, *pvcpu);
if (strictmsr) {
- vm_inject_gp(ctx, *pvcpu, 0);
+ vm_inject_gp(ctx, *pvcpu);
return (VMEXIT_RESTART);
}
}
@@ -373,7 +394,7 @@ vmexit_wrmsr(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
fprintf(stderr, "wrmsr to register %#x(%#lx) on vcpu %d\n",
vme->u.msr.code, vme->u.msr.wval, *pvcpu);
if (strictmsr) {
- vm_inject_gp(ctx, *pvcpu, 0);
+ vm_inject_gp(ctx, *pvcpu);
return (VMEXIT_RESTART);
}
}
diff --git a/usr.sbin/bhyve/inout.c b/usr.sbin/bhyve/inout.c
index 145ac1c..447f6c5 100644
--- a/usr.sbin/bhyve/inout.c
+++ b/usr.sbin/bhyve/inout.c
@@ -157,7 +157,7 @@ emulate_inout(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit, int strict)
if (vie_calculate_gla(vis->paging.cpu_mode,
vis->seg_name, &vis->seg_desc, index, bytes,
addrsize, prot, &gla)) {
- vm_inject_gp(ctx, vcpu, 0);
+ vm_inject_gp(ctx, vcpu);
retval = INOUT_RESTART;
break;
}
diff --git a/usr.sbin/bhyve/task_switch.c b/usr.sbin/bhyve/task_switch.c
index 6433982..543c01f 100644
--- a/usr.sbin/bhyve/task_switch.c
+++ b/usr.sbin/bhyve/task_switch.c
@@ -160,8 +160,6 @@ usd_to_seg_desc(struct user_segment_descriptor *usd)
static void
sel_exception(struct vmctx *ctx, int vcpu, int vector, uint16_t sel, int ext)
{
- int error;
-
/*
* Bit 2 from the selector is retained as-is in the error code.
*
@@ -174,8 +172,7 @@ sel_exception(struct vmctx *ctx, int vcpu, int vector, uint16_t sel, int ext)
sel &= ~0x3;
if (ext)
sel |= 0x1;
- error = vm_inject_exception2(ctx, vcpu, vector, sel);
- assert(error == 0);
+ vm_inject_fault(ctx, vcpu, vector, 1, sel);
}
static int
@@ -508,7 +505,7 @@ tss32_restore(struct vmctx *ctx, int vcpu, struct vm_task_switch *ts,
*/
reserved = ~maxphyaddr | 0x1E6;
if (pdpte[i] & reserved) {
- vm_inject_gp(ctx, vcpu, 0);
+ vm_inject_gp(ctx, vcpu);
return (VMEXIT_RESTART);
}
}
OpenPOWER on IntegriCloud