diff options
author | neel <neel@FreeBSD.org> | 2014-07-24 01:38:11 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2014-07-24 01:38:11 +0000 |
commit | 4535fa67c47e242c2d4c579630ebc12d8153d881 (patch) | |
tree | f10160daba1a9c8df5c059e74db7b03dcae6f007 /usr.sbin/bhyve | |
parent | 57fd2f85267f7e1a29e8cef251c560081842963b (diff) | |
download | FreeBSD-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.c | 27 | ||||
-rw-r--r-- | usr.sbin/bhyve/inout.c | 2 | ||||
-rw-r--r-- | usr.sbin/bhyve/task_switch.c | 7 |
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); } } |