Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h +++ sys/amd64/include/vmm.h @@ -546,6 +546,9 @@ struct vie { uint8_t inst[VIE_INST_SIZE]; /* instruction bytes */ uint8_t num_valid; /* size of the instruction */ + +/* The following fields are all zeroed upon restart. */ +#define vie_startzero num_processed uint8_t num_processed; uint8_t addrsize:4, opsize:4; /* address and operand sizes */ Index: sys/amd64/include/vmm_instruction_emul.h =================================================================== --- sys/amd64/include/vmm_instruction_emul.h +++ sys/amd64/include/vmm_instruction_emul.h @@ -105,6 +105,7 @@ uint64_t gla, int prot, uint64_t *gpa, int *is_fault); #endif /* _KERNEL */ +void vie_restart(struct vie *vie); void vie_init(struct vie *vie, const char *inst_bytes, int inst_length); /* Index: sys/amd64/vmm/vmm_instruction_emul.c =================================================================== --- sys/amd64/vmm/vmm_instruction_emul.c +++ sys/amd64/vmm/vmm_instruction_emul.c @@ -53,7 +53,9 @@ #include #include #include +#include #include +#include #include #include #define KASSERT(exp,msg) assert((exp)) @@ -1990,20 +1992,35 @@ return (0); } +/* + * Prepare a partially decoded vie for a 2nd attempt. + */ +void +vie_restart(struct vie *vie) +{ + _Static_assert( + offsetof(struct vie, inst) < offsetof(struct vie, vie_startzero) && + offsetof(struct vie, num_valid) < offsetof(struct vie, vie_startzero), + "restart should not erase instruction length or contents"); + + memset((char *)vie + offsetof(struct vie, vie_startzero), 0, + sizeof(*vie) - offsetof(struct vie, vie_startzero)); + + vie->base_register = VM_REG_LAST; + vie->index_register = VM_REG_LAST; + vie->segment_register = VM_REG_LAST; +} + void vie_init(struct vie *vie, const char *inst_bytes, int inst_length) { KASSERT(inst_length >= 0 && inst_length <= VIE_INST_SIZE, ("%s: invalid instruction length (%d)", __func__, inst_length)); - bzero(vie, sizeof(struct vie)); - - vie->base_register = VM_REG_LAST; - vie->index_register = VM_REG_LAST; - vie->segment_register = VM_REG_LAST; - + vie_restart(vie); + memset(vie->inst, 0, sizeof(vie->inst)); if (inst_length) { - bcopy(inst_bytes, vie->inst, inst_length); + memcpy(vie->inst, inst_bytes, inst_length); vie->num_valid = inst_length; } } Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c +++ usr.sbin/bhyve/bhyverun.c @@ -747,12 +747,26 @@ static int vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { - int err, i; + int err, i, cs_d; struct vie *vie; + enum vm_cpu_mode mode; stats.vmexit_inst_emul++; vie = &vmexit->u.inst_emul.vie; + if (!vie->decoded) { + /* + * Attempt to decode in userspace as a fallback. This allows + * updating instruction decode in bhyve without rebooting the + * kernel (rapid prototyping), albeit with much slower + * emulation. + */ + vie_restart(vie); + mode = vmexit->u.inst_emul.paging.cpu_mode; + cs_d = vmexit->u.inst_emul.cs_d; + (void)vmm_decode_instruction(mode, cs_d, vie); + } + err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa, vie, &vmexit->u.inst_emul.paging);