diff options
Diffstat (limited to 'usr.sbin/bhyve/bhyverun.c')
-rw-r--r-- | usr.sbin/bhyve/bhyverun.c | 127 |
1 files changed, 73 insertions, 54 deletions
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 1e5d3b3..7dcf6d0 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -69,16 +69,11 @@ __FBSDID("$FreeBSD$"); #define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */ -#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 */ - #define MB (1024UL * 1024) #define GB (1024UL * MB) typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu); +extern int vmexit_task_switch(struct vmctx *, struct vm_exit *, int *vcpu); char *vmname; @@ -101,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; @@ -112,8 +107,6 @@ struct bhyvestats { 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 { @@ -129,26 +122,26 @@ usage(int code) { fprintf(stderr, - "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>] [-c vcpus]\n" - " %*s [-p vcpu:hostcpu] [-m mem] [-l <lpc>] <vm>\n" + "Usage: %s [-abehwxACHPWY] [-c vcpus] [-g <gdb port>] [-l <lpc>]\n" + " %*s [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] <vm>\n" " -a: local apic is in xAPIC mode (deprecated)\n" - " -A: create an ACPI table\n" - " -g: gdb port\n" + " -A: create ACPI tables\n" " -c: # cpus (default 1)\n" " -C: include guest memory in core file\n" - " -p: pin 'vcpu' to 'hostcpu'\n" - " -H: vmexit from the guest on hlt\n" - " -P: vmexit from the guest on pause\n" - " -W: force virtio to use single-vector MSI\n" " -e: exit on unhandled I/O access\n" + " -g: gdb port\n" " -h: help\n" - " -s: <slot,driver,configinfo> PCI slot config\n" + " -H: vmexit from the guest on hlt\n" " -l: LPC device configuration\n" " -m: memory size in MB\n" + " -p: pin 'vcpu' to 'hostcpu'\n" + " -P: vmexit from the guest on pause\n" + " -s: <slot,driver,configinfo> PCI slot config\n" + " -U: uuid\n" " -w: ignore unimplemented MSRs\n" + " -W: force virtio to use single-vector MSI\n" " -x: local apic is in x2APIC mode\n" - " -Y: disable MPtable generation\n" - " -U: uuid\n", + " -Y: disable MPtable generation\n", progname, (int)strlen(progname), ""); exit(code); @@ -187,6 +180,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) { @@ -315,27 +329,18 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) } 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); } } @@ -352,8 +357,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) { - error = vm_inject_exception2(ctx, *pvcpu, IDT_GP, 0); - assert(error == 0); + vm_inject_gp(ctx, *pvcpu); return (VMEXIT_RESTART); } } @@ -379,8 +383,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) { - error = vm_inject_exception2(ctx, *pvcpu, IDT_GP, 0); - assert(error == 0); + vm_inject_gp(ctx, *pvcpu); return (VMEXIT_RESTART); } } @@ -399,6 +402,16 @@ vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) return (retval); } +#define DEBUG_EPT_MISCONFIG +#ifdef DEBUG_EPT_MISCONFIG +#define EXIT_REASON_EPT_MISCONFIG 49 +#define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400 +#define VMCS_IDENT(x) ((x) | 0x80000000) + +static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4]; +static int ept_misconfig_ptenum; +#endif + static int vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { @@ -413,7 +426,21 @@ vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) vmexit->u.vmx.exit_qualification); fprintf(stderr, "\tinst_type\t\t%d\n", vmexit->u.vmx.inst_type); fprintf(stderr, "\tinst_error\t\t%d\n", vmexit->u.vmx.inst_error); - +#ifdef DEBUG_EPT_MISCONFIG + if (vmexit->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) { + vm_get_register(ctx, *pvcpu, + VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS), + &ept_misconfig_gpa); + vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte, + &ept_misconfig_ptenum); + fprintf(stderr, "\tEPT misconfiguration:\n"); + fprintf(stderr, "\t\tGPA: %#lx\n", ept_misconfig_gpa); + fprintf(stderr, "\t\tPTE(%d): %#lx %#lx %#lx %#lx\n", + ept_misconfig_ptenum, ept_misconfig_pte[0], + ept_misconfig_pte[1], ept_misconfig_pte[2], + ept_misconfig_pte[3]); + } +#endif /* DEBUG_EPT_MISCONFIG */ return (VMEXIT_ABORT); } @@ -465,7 +492,7 @@ vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) stats.vmexit_inst_emul++; err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa, - &vmexit->u.inst_emul.vie); + &vmexit->u.inst_emul.vie, &vmexit->u.inst_emul.paging); if (err) { if (err == EINVAL) { @@ -515,6 +542,8 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) exit(1); case VM_SUSPEND_HALT: exit(2); + case VM_SUSPEND_TRIPLEFAULT: + exit(3); default: fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how); exit(100); @@ -532,7 +561,8 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = { [VM_EXITCODE_MTRAP] = vmexit_mtrap, [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul, [VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap, - [VM_EXITCODE_SUSPENDED] = vmexit_suspend + [VM_EXITCODE_SUSPENDED] = vmexit_suspend, + [VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch, }; static void @@ -540,7 +570,6 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) { int error, rc, prevcpu; enum vm_exitcode exitcode; - enum vm_suspend_how how; cpuset_t active_cpus; if (vcpumap[vcpu] != NULL) { @@ -575,16 +604,6 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) 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: |