Index: usr.sbin/bhyve/atkbdc.c =================================================================== --- usr.sbin/bhyve/atkbdc.c +++ usr.sbin/bhyve/atkbdc.c @@ -31,6 +31,10 @@ #include +#include + +#include +#include #include #include "inout.h" @@ -48,29 +52,30 @@ uint32_t *eax, void *arg) { if (bytes != 1) - return (INOUT_ERROR); + return (-1); *eax = 0; - return (INOUT_OK); + return (0); } static int atkbdc_sts_ctl_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { - int retval; + int error, retval; if (bytes != 1) - return (INOUT_ERROR); + return (-1); - retval = INOUT_OK; + retval = 0; if (in) { *eax = KBD_SYS_FLAG; /* system passed POST */ } else { switch (*eax) { case KBDC_RESET: /* Pulse "reset" line. */ - retval = INOUT_RESET; + error = vm_suspend(ctx, VM_SUSPEND_RESET); + assert(error == 0 || errno == EALREADY); break; } } Index: usr.sbin/bhyve/bhyverun.h =================================================================== --- usr.sbin/bhyve/bhyverun.h +++ usr.sbin/bhyve/bhyverun.h @@ -38,8 +38,6 @@ #define VMEXIT_CONTINUE 1 /* continue from next instruction */ #define VMEXIT_RESTART 2 /* restart current instruction */ #define VMEXIT_ABORT 3 /* abort the vm run loop */ -#define VMEXIT_RESET 4 /* guest machine has reset */ -#define VMEXIT_POWEROFF 5 /* guest machine has powered off */ struct vmctx; extern int guest_ncpus; Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c +++ usr.sbin/bhyve/bhyverun.c @@ -107,8 +107,6 @@ uint64_t vmexit_inst_emul; uint64_t cpu_switch_rotate; uint64_t cpu_switch_direct; - int io_reset; - int io_poweroff; } stats; struct mt_vmm_info { @@ -331,27 +329,18 @@ } error = emulate_inout(ctx, vcpu, vme, strictio); - if (error == INOUT_OK && in && !string) { + if (!error && in && !string) { error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, vme->u.inout.eax); + assert(error == 0); } - switch (error) { - case INOUT_OK: - return (VMEXIT_CONTINUE); - case INOUT_RESTART: - return (VMEXIT_RESTART); - case INOUT_RESET: - stats.io_reset++; - return (VMEXIT_RESET); - case INOUT_POWEROFF: - stats.io_poweroff++; - return (VMEXIT_POWEROFF); - default: - fprintf(stderr, "Unhandled %s%c 0x%04x\n", - in ? "in" : "out", - bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port); + if (error) { + fprintf(stderr, "Unhandled %s%c 0x%04x\n", in ? "in" : "out", + bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port); return (VMEXIT_ABORT); + } else { + return (VMEXIT_CONTINUE); } } @@ -581,7 +570,6 @@ { int error, rc, prevcpu; enum vm_exitcode exitcode; - enum vm_suspend_how how; cpuset_t active_cpus; if (vcpumap[vcpu] != NULL) { @@ -616,16 +604,6 @@ case VMEXIT_RESTART: rip = vmexit[vcpu].rip; break; - case VMEXIT_RESET: - case VMEXIT_POWEROFF: - if (rc == VMEXIT_RESET) - how = VM_SUSPEND_RESET; - else - how = VM_SUSPEND_POWEROFF; - error = vm_suspend(ctx, how); - assert(error == 0 || errno == EALREADY); - rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length; - break; case VMEXIT_ABORT: abort(); default: Index: usr.sbin/bhyve/inout.h =================================================================== --- usr.sbin/bhyve/inout.h +++ usr.sbin/bhyve/inout.h @@ -34,13 +34,9 @@ struct vmctx; struct vm_exit; -/* Handler return values. */ -#define INOUT_ERROR -1 -#define INOUT_OK 0 -#define INOUT_RESTART 1 -#define INOUT_RESET 2 -#define INOUT_POWEROFF 3 - +/* + * inout emulation handlers return 0 on success and -1 on failure. + */ typedef int (*inout_func_t)(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg); Index: usr.sbin/bhyve/inout.c =================================================================== --- usr.sbin/bhyve/inout.c +++ usr.sbin/bhyve/inout.c @@ -154,27 +154,28 @@ /* Limit number of back-to-back in/out emulations to 16 */ iterations = MIN(count, 16); while (iterations > 0) { + assert(retval == 0); if (vie_calculate_gla(vis->paging.cpu_mode, vis->seg_name, &vis->seg_desc, index, bytes, addrsize, prot, &gla)) { vm_inject_gp(ctx, vcpu); - retval = INOUT_RESTART; break; } error = vm_copy_setup(ctx, vcpu, &vis->paging, gla, bytes, prot, iov, nitems(iov)); - assert(error == 0 || error == 1 || error == -1); - if (error) { - retval = (error == 1) ? INOUT_RESTART : - INOUT_ERROR; + if (error == -1) { + retval = -1; /* Unrecoverable error */ + break; + } else if (error == 1) { + retval = 0; /* Resume guest to handle fault */ break; } if (vie_alignment_check(vis->paging.cpl, bytes, vis->cr0, vis->rflags, gla)) { vm_inject_ac(ctx, vcpu, 0); - return (INOUT_RESTART); + break; } val = 0; @@ -213,8 +214,8 @@ } /* Restart the instruction if more iterations remain */ - if (retval == INOUT_OK && count != 0) - retval = INOUT_RESTART; + if (retval == 0 && count != 0) + vmexit->inst_length = 0; } else { if (!in) { val = vmexit->u.inout.eax & vie_size2mask(bytes); Index: usr.sbin/bhyve/pm.c =================================================================== --- usr.sbin/bhyve/pm.c +++ usr.sbin/bhyve/pm.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,8 @@ reset_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { + int error; + static uint8_t reset_control; if (bytes != 1) @@ -66,8 +69,10 @@ reset_control = *eax; /* Treat hard and soft resets the same. */ - if (reset_control & 0x4) - return (INOUT_RESET); + if (reset_control & 0x4) { + error = vm_suspend(ctx, VM_SUSPEND_RESET); + assert(error == 0 || errno == EALREADY); + } } return (0); } @@ -224,6 +229,7 @@ pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { + int error; if (bytes != 2) return (-1); @@ -243,8 +249,10 @@ * says that '5' should be stored in SLP_TYP for S5. */ if (*eax & PM1_SLP_EN) { - if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) - return (INOUT_POWEROFF); + if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) { + error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); + assert(error == 0 || errno == EALREADY); + } } } return (0);