Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyvectl/bhyvectl.c
Show First 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
#include <libutil.h> | #include <libutil.h> | ||||
#include <machine/cpufunc.h> | #include <machine/cpufunc.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <machine/vmm_dev.h> | #include <machine/vmm_dev.h> | ||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#include <sys/socket.h> | |||||
#include <sys/un.h> | |||||
#include "amd/vmcb.h" | #include "amd/vmcb.h" | ||||
#include "intel/vmcs.h" | #include "intel/vmcs.h" | ||||
#define MB (1UL << 20) | #define MB (1UL << 20) | ||||
#define GB (1UL << 30) | #define GB (1UL << 30) | ||||
#define REQ_ARG required_argument | #define REQ_ARG required_argument | ||||
#define NO_ARG no_argument | #define NO_ARG no_argument | ||||
#define OPT_ARG optional_argument | #define OPT_ARG optional_argument | ||||
#define CHECKPOINT_RUN_DIR "/var/run/bhyve/checkpoint" | |||||
#define MAX_VMNAME 100 | |||||
static const char *progname; | static const char *progname; | ||||
static void | static void | ||||
usage(bool cpu_intel) | usage(bool cpu_intel) | ||||
{ | { | ||||
(void)fprintf(stderr, | (void)fprintf(stderr, | ||||
"Usage: %s --vm=<vmname>\n" | "Usage: %s --vm=<vmname>\n" | ||||
" [--cpu=<vcpu_number>]\n" | " [--cpu=<vcpu_number>]\n" | ||||
" [--create]\n" | " [--create]\n" | ||||
" [--destroy]\n" | " [--destroy]\n" | ||||
#ifdef BHYVE_SNAPSHOT | |||||
" [--checkpoint=<filename>]\n" | |||||
" [--suspend=<filename>]\n" | |||||
#endif | |||||
" [--get-all]\n" | " [--get-all]\n" | ||||
" [--get-stats]\n" | " [--get-stats]\n" | ||||
" [--set-desc-ds]\n" | " [--set-desc-ds]\n" | ||||
" [--get-desc-ds]\n" | " [--get-desc-ds]\n" | ||||
" [--set-desc-es]\n" | " [--set-desc-es]\n" | ||||
" [--get-desc-es]\n" | " [--get-desc-es]\n" | ||||
" [--set-desc-gs]\n" | " [--set-desc-gs]\n" | ||||
" [--get-desc-gs]\n" | " [--get-desc-gs]\n" | ||||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Lines | |||||
static int set_desc_ldtr, get_desc_ldtr; | static int set_desc_ldtr, get_desc_ldtr; | ||||
static int set_cs, set_ds, set_es, set_fs, set_gs, set_ss, set_tr, set_ldtr; | static int set_cs, set_ds, set_es, set_fs, set_gs, set_ss, set_tr, set_ldtr; | ||||
static int get_cs, get_ds, get_es, get_fs, get_gs, get_ss, get_tr, get_ldtr; | static int get_cs, get_ds, get_es, get_fs, get_gs, get_ss, get_tr, get_ldtr; | ||||
static int set_x2apic_state, get_x2apic_state; | static int set_x2apic_state, get_x2apic_state; | ||||
enum x2apic_state x2apic_state; | enum x2apic_state x2apic_state; | ||||
static int unassign_pptdev, bus, slot, func; | static int unassign_pptdev, bus, slot, func; | ||||
static int run; | static int run; | ||||
static int get_cpu_topology; | static int get_cpu_topology; | ||||
#ifdef BHYVE_SNAPSHOT | |||||
static int vm_checkpoint_opt; | |||||
static int vm_suspend_opt; | |||||
#endif | |||||
/* | /* | ||||
* VMCB specific. | * VMCB specific. | ||||
*/ | */ | ||||
static int get_vmcb_intercept, get_vmcb_exit_details, get_vmcb_tlb_ctrl; | static int get_vmcb_intercept, get_vmcb_exit_details, get_vmcb_tlb_ctrl; | ||||
static int get_vmcb_virq, get_avic_table; | static int get_vmcb_virq, get_avic_table; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 288 Lines • ▼ Show 20 Lines | enum { | ||||
SET_CAP, | SET_CAP, | ||||
CAPNAME, | CAPNAME, | ||||
UNASSIGN_PPTDEV, | UNASSIGN_PPTDEV, | ||||
GET_GPA_PMAP, | GET_GPA_PMAP, | ||||
ASSERT_LAPIC_LVT, | ASSERT_LAPIC_LVT, | ||||
SET_RTC_TIME, | SET_RTC_TIME, | ||||
SET_RTC_NVRAM, | SET_RTC_NVRAM, | ||||
RTC_NVRAM_OFFSET, | RTC_NVRAM_OFFSET, | ||||
#ifdef BHYVE_SNAPSHOT | |||||
SET_CHECKPOINT_FILE, | |||||
SET_SUSPEND_FILE, | |||||
#endif | |||||
}; | }; | ||||
static void | static void | ||||
print_cpus(const char *banner, const cpuset_t *cpus) | print_cpus(const char *banner, const cpuset_t *cpus) | ||||
{ | { | ||||
int i, first; | int i, first; | ||||
first = 1; | first = 1; | ||||
▲ Show 20 Lines • Show All 854 Lines • ▼ Show 20 Lines | const struct option common_opts[] = { | ||||
{ "destroy", NO_ARG, &destroy, 1 }, | { "destroy", NO_ARG, &destroy, 1 }, | ||||
{ "inject-nmi", NO_ARG, &inject_nmi, 1 }, | { "inject-nmi", NO_ARG, &inject_nmi, 1 }, | ||||
{ "force-reset", NO_ARG, &force_reset, 1 }, | { "force-reset", NO_ARG, &force_reset, 1 }, | ||||
{ "force-poweroff", NO_ARG, &force_poweroff, 1 }, | { "force-poweroff", NO_ARG, &force_poweroff, 1 }, | ||||
{ "get-active-cpus", NO_ARG, &get_active_cpus, 1 }, | { "get-active-cpus", NO_ARG, &get_active_cpus, 1 }, | ||||
{ "get-suspended-cpus", NO_ARG, &get_suspended_cpus, 1 }, | { "get-suspended-cpus", NO_ARG, &get_suspended_cpus, 1 }, | ||||
{ "get-intinfo", NO_ARG, &get_intinfo, 1 }, | { "get-intinfo", NO_ARG, &get_intinfo, 1 }, | ||||
{ "get-cpu-topology", NO_ARG, &get_cpu_topology, 1 }, | { "get-cpu-topology", NO_ARG, &get_cpu_topology, 1 }, | ||||
#ifdef BHYVE_SNAPSHOT | |||||
{ "checkpoint", REQ_ARG, 0, SET_CHECKPOINT_FILE}, | |||||
{ "suspend", REQ_ARG, 0, SET_SUSPEND_FILE}, | |||||
#endif | |||||
}; | }; | ||||
const struct option intel_opts[] = { | const struct option intel_opts[] = { | ||||
{ "get-vmcs-pinbased-ctls", | { "get-vmcs-pinbased-ctls", | ||||
NO_ARG, &get_pinbased_ctls, 1 }, | NO_ARG, &get_pinbased_ctls, 1 }, | ||||
{ "get-vmcs-procbased-ctls", | { "get-vmcs-procbased-ctls", | ||||
NO_ARG, &get_procbased_ctls, 1 }, | NO_ARG, &get_procbased_ctls, 1 }, | ||||
{ "get-vmcs-procbased-ctls2", | { "get-vmcs-procbased-ctls2", | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | if (seglen) { | ||||
printf("%-12s", numbuf); | printf("%-12s", numbuf); | ||||
printf("%s", name[0] ? name : "sysmem"); | printf("%s", name[0] ? name : "sysmem"); | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
segid++; | segid++; | ||||
} | } | ||||
} | } | ||||
#ifdef BHYVE_SNAPSHOT | |||||
static int | |||||
send_checkpoint_op_req(struct vmctx *ctx, struct checkpoint_op *op) | |||||
{ | |||||
struct sockaddr_un addr; | |||||
int socket_fd, len, len_sent, total_sent; | |||||
int err = 0; | |||||
char vmname_buf[MAX_VMNAME]; | |||||
socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); | |||||
if (socket_fd < 0) { | |||||
perror("Error creating bhyvectl socket"); | |||||
err = -1; | |||||
goto done; | |||||
} | |||||
memset(&addr, 0, sizeof(struct sockaddr_un)); | |||||
addr.sun_family = AF_UNIX; | |||||
err = vm_get_name(ctx, vmname_buf, MAX_VMNAME - 1); | |||||
if (err != 0) { | |||||
perror("Failed to get VM name"); | |||||
goto done; | |||||
} | |||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", CHECKPOINT_RUN_DIR, vmname_buf); | |||||
if (connect(socket_fd, (struct sockaddr *)&addr, | |||||
sizeof(struct sockaddr_un)) != 0) { | |||||
perror("Connect to VM socket failed"); | |||||
err = -1; | |||||
goto done; | |||||
} | |||||
len = sizeof(*op); | |||||
total_sent = 0; | |||||
while ((len_sent = send(socket_fd, (char *)op + total_sent, len - total_sent, 0)) > 0) { | |||||
total_sent += len_sent; | |||||
} | |||||
if (len_sent < 0) { | |||||
perror("Failed to send checkpoint operation request"); | |||||
err = -1; | |||||
} | |||||
done: | |||||
if (socket_fd > 0) | |||||
close(socket_fd); | |||||
return (err); | |||||
} | |||||
static int | |||||
send_start_checkpoint(struct vmctx *ctx, const char *checkpoint_file) | |||||
{ | |||||
struct checkpoint_op op; | |||||
op.op = START_CHECKPOINT; | |||||
strncpy(op.snapshot_filename, checkpoint_file, MAX_SNAPSHOT_VMNAME); | |||||
op.snapshot_filename[MAX_SNAPSHOT_VMNAME - 1] = 0; | |||||
return (send_checkpoint_op_req(ctx, &op)); | |||||
} | |||||
static int | |||||
send_start_suspend(struct vmctx *ctx, const char *suspend_file) | |||||
{ | |||||
struct checkpoint_op op; | |||||
op.op = START_SUSPEND; | |||||
strncpy(op.snapshot_filename, suspend_file, MAX_SNAPSHOT_VMNAME); | |||||
op.snapshot_filename[MAX_SNAPSHOT_VMNAME - 1] = 0; | |||||
return (send_checkpoint_op_req(ctx, &op)); | |||||
} | |||||
#endif | |||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
char *vmname; | char *vmname; | ||||
int error, ch, vcpu, ptenum; | int error, ch, vcpu, ptenum; | ||||
vm_paddr_t gpa_pmap; | vm_paddr_t gpa_pmap; | ||||
struct vm_exit vmexit; | struct vm_exit vmexit; | ||||
uint64_t rax, cr0, cr2, cr3, cr4, dr0, dr1, dr2, dr3, dr6, dr7; | uint64_t rax, cr0, cr2, cr3, cr4, dr0, dr1, dr2, dr3, dr6, dr7; | ||||
uint64_t rsp, rip, rflags, efer, pat; | uint64_t rsp, rip, rflags, efer, pat; | ||||
uint64_t eptp, bm, addr, u64, pteval[4], *pte, info[2]; | uint64_t eptp, bm, addr, u64, pteval[4], *pte, info[2]; | ||||
struct vmctx *ctx; | struct vmctx *ctx; | ||||
cpuset_t cpus; | cpuset_t cpus; | ||||
bool cpu_intel; | bool cpu_intel; | ||||
uint64_t cs, ds, es, fs, gs, ss, tr, ldtr; | uint64_t cs, ds, es, fs, gs, ss, tr, ldtr; | ||||
struct tm tm; | struct tm tm; | ||||
struct option *opts; | struct option *opts; | ||||
#ifdef BHYVE_SNAPSHOT | |||||
char *checkpoint_file, *suspend_file; | |||||
#endif | |||||
cpu_intel = cpu_vendor_intel(); | cpu_intel = cpu_vendor_intel(); | ||||
opts = setup_options(cpu_intel); | opts = setup_options(cpu_intel); | ||||
vcpu = 0; | vcpu = 0; | ||||
vmname = NULL; | vmname = NULL; | ||||
assert_lapic_lvt = -1; | assert_lapic_lvt = -1; | ||||
progname = basename(argv[0]); | progname = basename(argv[0]); | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | while ((ch = getopt_long(argc, argv, "", opts, NULL)) != -1) { | ||||
case UNASSIGN_PPTDEV: | case UNASSIGN_PPTDEV: | ||||
unassign_pptdev = 1; | unassign_pptdev = 1; | ||||
if (sscanf(optarg, "%d/%d/%d", &bus, &slot, &func) != 3) | if (sscanf(optarg, "%d/%d/%d", &bus, &slot, &func) != 3) | ||||
usage(cpu_intel); | usage(cpu_intel); | ||||
break; | break; | ||||
case ASSERT_LAPIC_LVT: | case ASSERT_LAPIC_LVT: | ||||
assert_lapic_lvt = atoi(optarg); | assert_lapic_lvt = atoi(optarg); | ||||
break; | break; | ||||
#ifdef BHYVE_SNAPSHOT | |||||
case SET_CHECKPOINT_FILE: | |||||
vm_checkpoint_opt = 1; | |||||
checkpoint_file = optarg; | |||||
break; | |||||
case SET_SUSPEND_FILE: | |||||
vm_suspend_opt = 1; | |||||
suspend_file = optarg; | |||||
break; | |||||
#endif | |||||
default: | default: | ||||
usage(cpu_intel); | usage(cpu_intel); | ||||
} | } | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (vmname == NULL) | if (vmname == NULL) | ||||
▲ Show 20 Lines • Show All 468 Lines • ▼ Show 20 Lines | #endif | ||||
if (!error && force_poweroff) | if (!error && force_poweroff) | ||||
error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); | error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); | ||||
if (error) | if (error) | ||||
printf("errno = %d\n", errno); | printf("errno = %d\n", errno); | ||||
if (!error && destroy) | if (!error && destroy) | ||||
vm_destroy(ctx); | vm_destroy(ctx); | ||||
#ifdef BHYVE_SNAPSHOT | |||||
if (!error && vm_checkpoint_opt) | |||||
error = send_start_checkpoint(ctx, checkpoint_file); | |||||
if (!error && vm_suspend_opt) | |||||
error = send_start_suspend(ctx, suspend_file); | |||||
#endif | |||||
free (opts); | free (opts); | ||||
exit(error); | exit(error); | ||||
} | } |