summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bhyve/bhyverun.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bhyve/bhyverun.c')
-rw-r--r--usr.sbin/bhyve/bhyverun.c128
1 files changed, 85 insertions, 43 deletions
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index e8010e6..e662ca3 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -85,7 +85,6 @@ char *vmname;
int guest_ncpus;
char *guest_uuid_str;
-static int pincpu = -1;
static int guest_vmexit_on_hlt, guest_vmexit_on_pause;
static int virtio_msix = 1;
static int x2apic_mode = 0; /* default is xAPIC */
@@ -114,6 +113,7 @@ struct bhyvestats {
uint64_t cpu_switch_rotate;
uint64_t cpu_switch_direct;
int io_reset;
+ int io_poweroff;
} stats;
struct mt_vmm_info {
@@ -122,18 +122,20 @@ struct mt_vmm_info {
int mt_vcpu;
} mt_vmm_info[VM_MAXCPU];
+static cpuset_t *vcpumap[VM_MAXCPU] = { NULL };
+
static void
usage(int code)
{
fprintf(stderr,
- "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>]\n"
- " %*s [-c vcpus] [-p pincpu] [-m mem] [-l <lpc>] <vm>\n"
+ "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>] [-c vcpus]\n"
+ " %*s [-p vcpu:hostcpu] [-m mem] [-l <lpc>] <vm>\n"
" -a: local apic is in xAPIC mode (deprecated)\n"
" -A: create an ACPI table\n"
" -g: gdb port\n"
" -c: # cpus (default 1)\n"
- " -p: pin vcpu 'n' to host cpu 'pincpu + n'\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"
@@ -144,12 +146,46 @@ usage(int code)
" -m: memory size in MB\n"
" -w: ignore unimplemented MSRs\n"
" -x: local apic is in x2APIC mode\n"
+ " -Y: disable MPtable generation\n"
" -U: uuid\n",
progname, (int)strlen(progname), "");
exit(code);
}
+static int
+pincpu_parse(const char *opt)
+{
+ int vcpu, pcpu;
+
+ if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) {
+ fprintf(stderr, "invalid format: %s\n", opt);
+ return (-1);
+ }
+
+ if (vcpu < 0 || vcpu >= VM_MAXCPU) {
+ fprintf(stderr, "vcpu '%d' outside valid range from 0 to %d\n",
+ vcpu, VM_MAXCPU - 1);
+ return (-1);
+ }
+
+ if (pcpu < 0 || pcpu >= CPU_SETSIZE) {
+ fprintf(stderr, "hostcpu '%d' outside valid range from "
+ "0 to %d\n", pcpu, CPU_SETSIZE - 1);
+ return (-1);
+ }
+
+ if (vcpumap[vcpu] == NULL) {
+ if ((vcpumap[vcpu] = malloc(sizeof(cpuset_t))) == NULL) {
+ perror("malloc");
+ return (-1);
+ }
+ CPU_ZERO(vcpumap[vcpu]);
+ }
+ CPU_SET(pcpu, vcpumap[vcpu]);
+ return (0);
+}
+
void *
paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
{
@@ -227,8 +263,7 @@ fbsdrun_deletecpu(struct vmctx *ctx, int vcpu)
{
if (!CPU_ISSET(vcpu, &cpumask)) {
- fprintf(stderr, "addcpu: attempting to delete unknown cpu %d\n",
- vcpu);
+ fprintf(stderr, "Attempting to delete unknown cpu %d\n", vcpu);
exit(1);
}
@@ -237,13 +272,6 @@ fbsdrun_deletecpu(struct vmctx *ctx, int vcpu)
}
static int
-vmexit_catch_reset(void)
-{
- stats.io_reset++;
- return (VMEXIT_RESET);
-}
-
-static int
vmexit_catch_inout(void)
{
return (VMEXIT_ABORT);
@@ -293,8 +321,10 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
case INOUT_OK:
return (VMEXIT_CONTINUE);
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",
@@ -365,17 +395,6 @@ vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
}
static int
-vmexit_spindown_cpu(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
-{
- int lastcpu;
-
- lastcpu = fbsdrun_deletecpu(ctx, *pvcpu);
- if (!lastcpu)
- pthread_exit(NULL);
- return (vmexit_catch_reset());
-}
-
-static int
vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
{
@@ -461,17 +480,17 @@ vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
-static int resetcpu = -1;
static int
vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
{
-
- assert(resetcpu != -1);
+ enum vm_suspend_how how;
+
+ how = vmexit->u.suspended.how;
fbsdrun_deletecpu(ctx, *pvcpu);
- if (*pvcpu != resetcpu) {
+ if (*pvcpu != BSP) {
pthread_mutex_lock(&resetcpu_mtx);
pthread_cond_signal(&resetcpu_cond);
pthread_mutex_unlock(&resetcpu_mtx);
@@ -483,7 +502,19 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
}
pthread_mutex_unlock(&resetcpu_mtx);
- exit(0);
+
+ switch (how) {
+ case VM_SUSPEND_RESET:
+ exit(0);
+ case VM_SUSPEND_POWEROFF:
+ exit(1);
+ case VM_SUSPEND_HALT:
+ exit(2);
+ default:
+ fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
+ exit(100);
+ }
+ return (0); /* NOTREACHED */
}
static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
@@ -495,22 +526,19 @@ 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_SPINDOWN_CPU] = vmexit_spindown_cpu,
[VM_EXITCODE_SUSPENDED] = vmexit_suspend
};
static void
vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
{
- cpuset_t mask;
int error, rc, prevcpu;
enum vm_exitcode exitcode;
+ enum vm_suspend_how how;
- if (pincpu >= 0) {
- CPU_ZERO(&mask);
- CPU_SET(pincpu + vcpu, &mask);
+ if (vcpumap[vcpu] != NULL) {
error = pthread_setaffinity_np(pthread_self(),
- sizeof(mask), &mask);
+ sizeof(cpuset_t), vcpumap[vcpu]);
assert(error == 0);
}
@@ -538,10 +566,13 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
rip = vmexit[vcpu].rip;
break;
case VMEXIT_RESET:
- if (vm_suspend(ctx) == 0) {
- assert(resetcpu == -1);
- resetcpu = vcpu;
- }
+ 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;
default:
@@ -616,7 +647,7 @@ int
main(int argc, char *argv[])
{
int c, error, gdb_port, err, bvmcons;
- int max_vcpus;
+ int max_vcpus, mptgen;
struct vmctx *ctx;
uint64_t rip;
size_t memsize;
@@ -626,8 +657,9 @@ main(int argc, char *argv[])
gdb_port = 0;
guest_ncpus = 1;
memsize = 256 * MB;
+ mptgen = 1;
- while ((c = getopt(argc, argv, "abehwxAHIPWp:g:c:s:m:l:U:")) != -1) {
+ while ((c = getopt(argc, argv, "abehwxAHIPWYp:g:c:s:m:l:U:")) != -1) {
switch (c) {
case 'a':
x2apic_mode = 0;
@@ -639,7 +671,10 @@ main(int argc, char *argv[])
bvmcons = 1;
break;
case 'p':
- pincpu = atoi(optarg);
+ if (pincpu_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid vcpu pinning "
+ "configuration '%s'", optarg);
+ }
break;
case 'c':
guest_ncpus = atoi(optarg);
@@ -693,6 +728,9 @@ main(int argc, char *argv[])
case 'x':
x2apic_mode = 1;
break;
+ case 'Y':
+ mptgen = 0;
+ break;
case 'h':
usage(0);
default:
@@ -752,7 +790,11 @@ main(int argc, char *argv[])
/*
* build the guest tables, MP etc.
*/
- mptable_build(ctx, guest_ncpus);
+ if (mptgen) {
+ error = mptable_build(ctx, guest_ncpus);
+ if (error)
+ exit(1);
+ }
error = smbios_build(ctx);
assert(error == 0);
OpenPOWER on IntegriCloud