Page MenuHomeFreeBSD

D29262.diff
No OneTemporary

D29262.diff

Index: sys/amd64/conf/GENERIC
===================================================================
--- sys/amd64/conf/GENERIC
+++ sys/amd64/conf/GENERIC
@@ -398,3 +398,6 @@
options HID_DEBUG # enable debug msgs
device hid # Generic HID support
options IICHID_SAMPLING # Workaround missing GPIO INTR support
+
+# bhyve
+options BHYVE_SNAPSHOT
Index: sys/amd64/include/vmm_snapshot.h
===================================================================
--- sys/amd64/include/vmm_snapshot.h
+++ sys/amd64/include/vmm_snapshot.h
@@ -40,6 +40,7 @@
#include <sys/errno.h>
#include <sys/types.h>
+
#ifndef _KERNEL
#include <stdbool.h>
#endif
@@ -84,6 +85,365 @@
*/
};
+#ifndef JSON_SNAPSHOT_V2
+#define JSON_SNAPSHOT_V2
+
+#define JSON_V1 1
+#define JSON_V2 2
+
+#include <sys/time.h>
+#include <machine/vmm.h>
+
+#define IDENT_LEVEL 10
+
+#define JSON_V1 1
+#define JSON_V2 2
+
+#include <sys/time.h>
+#include <machine/vmm.h>
+
+#define IDENT_LEVEL 10
+
+/* ####################### kernel structs copies ######################### */
+
+#define VM_MAXCPU 16 /* maximum virtual cpus */
+
+/* vhpet */
+#define VHPET_NUM_TIMERS 8
+
+struct timer_userspace {
+ uint64_t cap_config; /* Configuration */
+ uint64_t msireg; /* FSB interrupt routing */
+ uint32_t compval; /* Comparator */
+ uint32_t comprate;
+ sbintime_t callout_sbt; /* time when counter==compval */
+};
+
+struct vhpet_userspace {
+ sbintime_t freq_sbt;
+
+ uint64_t config; /* Configuration */
+ uint64_t isr; /* Interrupt Status */
+ uint32_t countbase; /* HPET counter base value */
+ sbintime_t countbase_sbt; /* uptime corresponding to base value */
+
+ struct timer_userspace timer[VHPET_NUM_TIMERS];
+};
+
+/* vioapic */
+
+#define REDIR_ENTRIES 32
+
+struct rtbl_userspace {
+ uint64_t reg;
+ int acnt; /* sum of pin asserts (+1) and deasserts (-1) */
+};
+
+struct vioapic_userspace {
+ uint32_t id;
+ uint32_t ioregsel;
+ struct rtbl_userspace rtbl[REDIR_ENTRIES];
+};
+
+/* vm (vcpus) */
+/*
+ * Initialization:
+ * (a) allocated when vcpu is created
+ * (i) initialized when vcpu is created and when it is reinitialized
+ * (o) initialized the first time the vcpu is created
+ * (x) initialized before use
+ */
+struct vcpu_userspace {
+ enum x2apic_state x2apic_state; /* (i) APIC mode */
+ uint64_t exitintinfo; /* (i) events pending at VM exit */
+ int exc_vector; /* (x) exception collateral */
+ int exc_errcode_valid;
+ uint32_t exc_errcode;
+ uint64_t guest_xcr0; /* (i) guest %xcr0 register */
+ struct vm_exit exitinfo; /* (x) exit reason and collateral */
+ uint64_t nextrip; /* (x) next instruction to execute */
+ uint64_t tsc_offset; /* (o) TSC offsetting */
+};
+
+/*
+ * Initialization:
+ * (o) initialized the first time the VM is created
+ * (i) initialized when VM is created and when it is reinitialized
+ * (x) initialized before use
+ */
+struct vm_userspace {
+ struct vcpu_userspace vcpu[VM_MAXCPU]; /* (i) guest vcpus */
+};
+
+/* vlapic */
+#define APIC_LVT_CMCI 6
+#define APIC_LVT_MAX APIC_LVT_CMCI
+
+enum boot_state_userspace {
+ BS_INIT_USERSPACE,
+ BS_SIPI_USERSPACE,
+ BS_RUNNING_USERSPACE
+};
+
+/*
+ * 16 priority levels with at most one vector injected per level.
+ */
+#define ISRVEC_STK_SIZE (16 + 1)
+
+#define VLAPIC_MAXLVT_INDEX APIC_LVT_CMCI
+
+struct vlapic_userspace {
+ struct vm_userspace *vm;
+ int vcpuid;
+ struct LAPIC *apic_page;
+
+ uint32_t esr_pending;
+
+ struct bintime timer_fire_bt; /* callout expiry time */
+ struct bintime timer_freq_bt; /* timer frequency */
+ struct bintime timer_period_bt; /* timer period */
+
+ /*
+ * The 'isrvec_stk' is a stack of vectors injected by the local apic.
+ * A vector is popped from the stack when the processor does an EOI.
+ * The vector on the top of the stack is used to compute the
+ * Processor Priority in conjunction with the TPR.
+ */
+ uint8_t isrvec_stk[ISRVEC_STK_SIZE];
+ int isrvec_stk_top;
+
+ uint64_t msr_apicbase;
+ enum boot_state_userspace boot_state;
+
+ /*
+ * Copies of some registers in the virtual APIC page. We do this for
+ * a couple of different reasons:
+ * - to be able to detect what changed (e.g. svr_last)
+ * - to maintain a coherent snapshot of the register (e.g. lvt_last)
+ */
+ uint32_t svr_last;
+ uint32_t lvt_last[VLAPIC_MAXLVT_INDEX + 1];
+};
+
+/* vatpic */
+struct atpic_userspace {
+ bool ready;
+ int icw_num;
+ int rd_cmd_reg;
+
+ bool aeoi;
+ bool poll;
+ bool rotate;
+ bool sfn; /* special fully-nested mode */
+
+ int irq_base;
+ uint8_t request; /* Interrupt Request Register (IIR) */
+ uint8_t service; /* Interrupt Service (ISR) */
+ uint8_t mask; /* Interrupt Mask Register (IMR) */
+ uint8_t smm; /* special mask mode */
+
+ int acnt[8]; /* sum of pin asserts and deasserts */
+ int lowprio; /* lowest priority irq */
+
+ bool intr_raised;
+};
+
+struct vatpic_userspace {
+ struct atpic_userspace atpic[2];
+ uint8_t elc[2];
+};
+
+/* vatpit */
+struct vatpit_userspace;
+
+struct vatpit_callout_arg_userspace {
+ struct vatpit_userspace *vatpit;
+ int channel_num;
+};
+
+struct channel_userspace {
+ int mode;
+ uint16_t initial; /* initial counter value */
+ struct bintime now_bt; /* uptime when counter was loaded */
+ uint8_t cr[2];
+ uint8_t ol[2];
+ bool slatched; /* status latched */
+ uint8_t status;
+ int crbyte;
+ int olbyte;
+ int frbyte;
+ struct bintime callout_bt; /* target time */
+ struct vatpit_callout_arg_userspace callout_arg;
+};
+
+struct vatpit_userspace {
+ struct bintime freq_bt;
+ struct channel_userspace channel[3];
+};
+
+/* vmptmr */
+struct vpmtmr_userspace {
+ sbintime_t freq_sbt;
+ sbintime_t baseuptime;
+ uint32_t baseval;
+};
+
+/* vrtc */
+/* Register layout of the RTC */
+struct rtcdev_userspace {
+ uint8_t sec;
+ uint8_t alarm_sec;
+ uint8_t min;
+ uint8_t alarm_min;
+ uint8_t hour;
+ uint8_t alarm_hour;
+ uint8_t day_of_week;
+ uint8_t day_of_month;
+ uint8_t month;
+ uint8_t year;
+ uint8_t reg_a;
+ uint8_t reg_b;
+ uint8_t reg_c;
+ uint8_t reg_d;
+ uint8_t nvram[36];
+ uint8_t century;
+ uint8_t nvram2[128 - 51];
+} __packed;
+
+struct vrtc_userspace {
+ u_int addr; /* RTC register to read or write */
+ sbintime_t base_uptime;
+ time_t base_rtctime;
+ struct rtcdev_userspace rtcdev;
+};
+
+/* vmx */
+#define VMCS_GUEST_IA32_SYSENTER_CS 0x0000482A
+#define VMCS_GUEST_IA32_SYSENTER_ESP 0x00006824
+#define VMCS_GUEST_IA32_SYSENTER_EIP 0x00006826
+#define VMCS_GUEST_INTERRUPTIBILITY 0x00004824
+#define VMCS_GUEST_ACTIVITY 0x00004826
+#define VMCS_ENTRY_CTLS 0x00004012
+#define VMCS_EXIT_CTLS 0x0000400C
+
+struct vmxctx_userspace {
+ register_t guest_rdi; /* Guest state */
+ register_t guest_rsi;
+ register_t guest_rdx;
+ register_t guest_rcx;
+ register_t guest_r8;
+ register_t guest_r9;
+ register_t guest_rax;
+ register_t guest_rbx;
+ register_t guest_rbp;
+ register_t guest_r10;
+ register_t guest_r11;
+ register_t guest_r12;
+ register_t guest_r13;
+ register_t guest_r14;
+ register_t guest_r15;
+ register_t guest_cr2;
+ register_t guest_dr0;
+ register_t guest_dr1;
+ register_t guest_dr2;
+ register_t guest_dr3;
+ register_t guest_dr6;
+
+ register_t host_r15; /* Host state */
+ register_t host_r14;
+ register_t host_r13;
+ register_t host_r12;
+ register_t host_rbp;
+ register_t host_rsp;
+ register_t host_rbx;
+ register_t host_dr0;
+ register_t host_dr1;
+ register_t host_dr2;
+ register_t host_dr3;
+ register_t host_dr6;
+ register_t host_dr7;
+ uint64_t host_debugctl;
+ int host_tf;
+
+ int inst_fail_status;
+};
+
+struct vmxcap_userspace {
+ int set;
+ uint32_t proc_ctls;
+ uint32_t proc_ctls2;
+ uint32_t exc_bitmap;
+};
+
+struct vmxstate_userspace {
+ uint64_t nextrip; /* next instruction to be executed by guest */
+ int lastcpu; /* host cpu that this 'vcpu' last ran on */
+ uint16_t vpid;
+};
+
+struct apic_page_userspace {
+ uint32_t reg[PAGE_SIZE / 4];
+};
+
+/* Index into the 'guest_msrs[]' array */
+enum {
+ IDX_MSR_LSTAR_USERSPACE,
+ IDX_MSR_CSTAR_USERSPACE,
+ IDX_MSR_STAR_USERSPACE,
+ IDX_MSR_SF_MASK_USERSPACE,
+ IDX_MSR_KGSBASE_USERSPACE,
+ IDX_MSR_PAT_USERSPACE,
+ IDX_MSR_TSC_AUX_USERSPACE,
+ GUEST_MSR_NUM_USERSPACE /* must be the last enumeration */
+};
+
+struct vmcs_userspace {
+ uint32_t identifier;
+ uint32_t abort_code;
+ char _impl_specific[PAGE_SIZE - sizeof(uint32_t) * 2];
+};
+
+struct vmx_userspace {
+ struct vmcs_userspace vmcs[VM_MAXCPU]; /* one vmcs per virtual cpu */
+ struct apic_page_userspace apic_page[VM_MAXCPU]; /* one apic page per vcpu */
+ char msr_bitmap[PAGE_SIZE];
+ uint64_t guest_msrs[VM_MAXCPU][GUEST_MSR_NUM_USERSPACE];
+ struct vmxctx_userspace ctx[VM_MAXCPU];
+ struct vmxcap_userspace cap[VM_MAXCPU];
+ struct vmxstate_userspace state[VM_MAXCPU];
+ uint64_t eptp;
+ struct vm_userspace *vm;
+ long eptgen[MAXCPU]; /* cached pmap->pm_eptgen */
+};
+
+/* ####################### kernel structs copies ######################### */
+
+struct vm_snapshot_device_info {
+ unsigned char ident;
+ unsigned char create_instance;
+ char *field_name;
+ char *type;
+ int index;
+ char *intern_arr_name;
+ void *field_data;
+ size_t data_size;
+ struct vm_snapshot_device_info *next_field;
+};
+
+struct list_device_info {
+ unsigned char ident;
+ unsigned char create_instance;
+ char *type;
+ const char *intern_arr_names[IDENT_LEVEL];
+ int index;
+ int auto_index;
+
+ struct vm_snapshot_device_info *first;
+ struct vm_snapshot_device_info *last;
+};
+
+#endif
+
enum vm_snapshot_op {
VM_SNAPSHOT_SAVE,
VM_SNAPSHOT_RESTORE,
@@ -97,29 +457,126 @@
struct vm_snapshot_buffer buffer;
+#ifdef JSON_SNAPSHOT_V2
+ struct list_device_info dev_info_list;
+ unsigned char snapshot_kernel;
+#endif
+
enum vm_snapshot_op op;
+ unsigned char version;
};
+int vm_snapshot_save_fieldname(const char *fullname, volatile void *data,
+ char *type, size_t data_size, struct vm_snapshot_meta *meta);
+
+void vm_snapshot_add_intern_list(const char *arr_name,
+ struct vm_snapshot_meta *meta);
+void vm_snapshot_remove_intern_list(struct vm_snapshot_meta *meta);
+
+void vm_snapshot_set_intern_arr_index(struct vm_snapshot_meta *meta, int index);
+void vm_snapshot_clear_intern_arr_index(struct vm_snapshot_meta *meta);
+
+void vm_snapshot_activate_auto_index(struct vm_snapshot_meta *meta,
+ unsigned char create_instance);
+void vm_snapshot_deactivate_auto_index(struct vm_snapshot_meta *meta);
+
+int vm_snapshot_save_fieldname_cmp(const char *fullname, volatile void *data,
+ char *type, size_t data_size, struct vm_snapshot_meta *meta);
+
+
void vm_snapshot_buf_err(const char *bufname, const enum vm_snapshot_op op);
int vm_snapshot_buf(volatile void *data, size_t data_size,
struct vm_snapshot_meta *meta);
size_t vm_get_snapshot_size(struct vm_snapshot_meta *meta);
+
int vm_snapshot_guest2host_addr(void **addrp, size_t len, bool restore_null,
struct vm_snapshot_meta *meta);
int vm_snapshot_buf_cmp(volatile void *data, size_t data_size,
struct vm_snapshot_meta *meta);
-#define SNAPSHOT_BUF_OR_LEAVE(DATA, LEN, META, RES, LABEL) \
-do { \
- (RES) = vm_snapshot_buf((DATA), (LEN), (META)); \
- if ((RES) != 0) { \
- vm_snapshot_buf_err(#DATA, (META)->op); \
- goto LABEL; \
- } \
+void check_and_set_non_array_type(char *type, struct vm_snapshot_meta *meta);
+
+#ifdef JSON_SNAPSHOT_V2
+
+#define SNAPSHOT_ADD_INTERN_ARR(ARR_NAME, META) \
+do { \
+ vm_snapshot_add_intern_list(#ARR_NAME, (META)); \
+} while (0)
+
+#define SNAPSHOT_REMOVE_INTERN_ARR(ARR_NAME, META) \
+do { \
+ vm_snapshot_remove_intern_list((META)); \
+} while (0)
+
+
+#define SNAPSHOT_SET_INTERN_ARR_INDEX(META, IDX) \
+do { \
+ vm_snapshot_set_intern_arr_index((META), (IDX)); \
+} while (0)
+
+#define SNAPSHOT_CLEAR_INTERN_ARR_INDEX(META) \
+do { \
+ vm_snapshot_clear_intern_arr_index((META)); \
+} while (0)
+
+/*
+ * Second parameter tells if the index will be used to
+ * create a new instance or just use it with the name of
+ * the key of the element
+ * 1 - create a new instance
+ * 0 - do not create a new instance
+ */
+#define SNAPSHOT_ACTIVATE_AUTO_INDEXING(META, create_instance) \
+do { \
+ vm_snapshot_activate_auto_index((META), (create_instance)); \
} while (0)
-#define SNAPSHOT_VAR_OR_LEAVE(DATA, META, RES, LABEL) \
- SNAPSHOT_BUF_OR_LEAVE(&(DATA), sizeof(DATA), (META), (RES), LABEL)
+#define SNAPSHOT_DEACTIVATE_AUTO_INDEXING(META) \
+do { \
+ vm_snapshot_deactivate_auto_index((META)); \
+} while (0)
+
+#define GET_TYPE(X) _Generic((X), \
+ /* fixed sized types */ \
+ int8_t: "int8", \
+ uint8_t: "uint8", \
+ int16_t: "int16", \
+ uint16_t: "uint16", \
+ int32_t: "int32", \
+ uint32_t: "uint32", \
+ int64_t: "int64", \
+ uint64_t: "uint64", \
+ default: "b64" \
+)
+
+#endif
+
+#define SNAPSHOT_BUF_OR_LEAVE(DATA, LEN, META, RES, LABEL) \
+do { \
+ char *type; \
+ type = GET_TYPE(DATA); \
+ if ((META)->version == 2) { \
+ (RES) = vm_snapshot_save_fieldname(#DATA, (DATA), type, (LEN), (META)); \
+ if ((RES) != 0) { \
+ vm_snapshot_buf_err(#DATA, (META)->op); \
+ goto LABEL; \
+ } \
+ } else { \
+ (RES) = vm_snapshot_buf((DATA), (LEN), (META)); \
+ if ((RES) != 0) { \
+ vm_snapshot_buf_err(#DATA, (META)->op); \
+ goto LABEL; \
+ } \
+ } \
+} while (0)
+
+#define SNAPSHOT_VAR_OR_LEAVE(DATA, META, RES, LABEL) \
+do { \
+ char *type; \
+ type = GET_TYPE(DATA); \
+ check_and_set_non_array_type(type, (META)); \
+ SNAPSHOT_BUF_OR_LEAVE(&(DATA), sizeof(DATA), (META), (RES), LABEL); \
+} while (0)
/*
* Address variables are pointers to guest memory.
@@ -128,25 +585,35 @@
* pointer NULL at restore time.
*/
#define SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ADDR, LEN, RNULL, META, RES, LABEL) \
-do { \
- (RES) = vm_snapshot_guest2host_addr((void **)&(ADDR), (LEN), (RNULL), \
- (META)); \
- if ((RES) != 0) { \
- if ((RES) == EFAULT) \
- fprintf(stderr, "%s: invalid address: %s\r\n", \
- __func__, #ADDR); \
- goto LABEL; \
- } \
+do { \
+ (RES) = vm_snapshot_guest2host_addr((void **)&(ADDR), (LEN), \
+ (RNULL), (META)); \
+ if ((RES) != 0) { \
+ if ((RES) == EFAULT) \
+ fprintf(stderr, "%s: invalid address: %s\r\n", \
+ __func__, #ADDR); \
+ goto LABEL; \
+ } \
} while (0)
/* compare the value in the meta buffer with the data */
-#define SNAPSHOT_BUF_CMP_OR_LEAVE(DATA, LEN, META, RES, LABEL) \
-do { \
- (RES) = vm_snapshot_buf_cmp((DATA), (LEN), (META)); \
- if ((RES) != 0) { \
- vm_snapshot_buf_err(#DATA, (META)->op); \
- goto LABEL; \
- } \
+#define SNAPSHOT_BUF_CMP_OR_LEAVE(DATA, LEN, META, RES, LABEL) \
+do { \
+ char *type; \
+ type = GET_TYPE(DATA); \
+ if ((META)->version == 2) { \
+ (RES) = vm_snapshot_save_fieldname_cmp(#DATA, (DATA), type, (LEN), (META)); \
+ if ((RES) != 0) { \
+ vm_snapshot_buf_err(#DATA, (META)->op); \
+ goto LABEL; \
+ } \
+ } else { \
+ (RES) = vm_snapshot_buf_cmp((DATA), (LEN), (META)); \
+ if ((RES) != 0) { \
+ vm_snapshot_buf_err(#DATA, (META)->op); \
+ goto LABEL; \
+ } \
+ } \
} while (0)
#define SNAPSHOT_VAR_CMP_OR_LEAVE(DATA, META, RES, LABEL) \
Index: sys/amd64/vmm/vmm_snapshot.c
===================================================================
--- sys/amd64/vmm/vmm_snapshot.c
+++ sys/amd64/vmm/vmm_snapshot.c
@@ -41,6 +41,35 @@
#include <machine/vmm_snapshot.h>
+int
+vm_snapshot_save_fieldname(const char *fullname, volatile void *data,
+ char *type, size_t data_size, struct vm_snapshot_meta *meta)
+{
+ return vm_snapshot_buf(data, data_size, meta);
+}
+
+int
+vm_snapshot_save_fieldname_cmp(const char *fullname, volatile void *data,
+ char *type, size_t data_size, struct vm_snapshot_meta *meta)
+{
+ return vm_snapshot_buf_cmp(data, data_size, meta);
+}
+
+void
+vm_snapshot_add_intern_list(const char *arr_name, struct vm_snapshot_meta *meta)
+{
+}
+
+void
+vm_snapshot_remove_intern_list(struct vm_snapshot_meta *meta)
+{
+}
+
+void
+check_and_set_non_array_type(char *type, struct vm_snapshot_meta *meta)
+{
+}
+
void
vm_snapshot_buf_err(const char *bufname, const enum vm_snapshot_op op)
{
@@ -62,22 +91,39 @@
{
struct vm_snapshot_buffer *buffer;
int op;
+ int ds;
void *nv_data;
nv_data = __DEVOLATILE(void *, data);
buffer = &meta->buffer;
op = meta->op;
- if (buffer->buf_rem < data_size) {
+ if (buffer->buf_rem < data_size + sizeof(int32_t)) {
printf("%s: buffer too small\r\n", __func__);
return (E2BIG);
}
- if (op == VM_SNAPSHOT_SAVE)
+ if (op == VM_SNAPSHOT_SAVE) {
+ if (meta->version == JSON_V2) {
+ copyout(&data_size, buffer->buf, sizeof(int32_t));
+ buffer->buf += sizeof(int32_t);
+ buffer->buf_rem -= sizeof(int32_t);
+ }
copyout(nv_data, buffer->buf, data_size);
- else if (op == VM_SNAPSHOT_RESTORE)
+ } else if (op == VM_SNAPSHOT_RESTORE) {
+ if (meta->version == JSON_V2) {
+ ds = -1;
+ copyin(buffer->buf, &ds, sizeof(int32_t));
+ if (ds != data_size) {
+ printf("%s(line %d): Size mismatch, expected %ld but got %d\r\n",
+ __func__, __LINE__, data_size, ds);
+ return (-1);
+ }
+ buffer->buf += sizeof(int32_t);
+ buffer->buf_rem -= sizeof(int32_t);
+ }
copyin(buffer->buf, nv_data, data_size);
- else
+ } else
return (EINVAL);
buffer->buf += data_size;
@@ -112,12 +158,13 @@
struct vm_snapshot_buffer *buffer;
int op;
int ret;
+ int ds;
void *_data = *(void **)(void *)&data;
buffer = &meta->buffer;
op = meta->op;
- if (buffer->buf_rem < data_size) {
+ if (buffer->buf_rem < data_size + sizeof(int32_t)) {
printf("%s: buffer too small\r\n", __func__);
ret = E2BIG;
goto done;
@@ -125,8 +172,22 @@
if (op == VM_SNAPSHOT_SAVE) {
ret = 0;
+ copyout(&data_size, buffer->buf, sizeof(int32_t));
+ buffer->buf += sizeof(int32_t);
+ buffer->buf_rem -= sizeof(int32_t);
copyout(_data, buffer->buf, data_size);
} else if (op == VM_SNAPSHOT_RESTORE) {
+ if (meta->version == JSON_V2) {
+ ds = -1;
+ copyin(&ds, buffer->buf, sizeof(int32_t));
+ if (ds != data_size) {
+ printf("%s(line %d): Size mismatch, expected %ld but got %d\r\n",
+ __func__, __LINE__, data_size, ds);
+ return (-1);
+ }
+ buffer->buf += sizeof(int32_t);
+ buffer->buf_rem -= sizeof(int32_t);
+ }
ret = memcmp(_data, buffer->buf, data_size);
} else {
ret = EINVAL;
Index: usr.sbin/bhyve/Makefile
===================================================================
--- usr.sbin/bhyve/Makefile
+++ usr.sbin/bhyve/Makefile
@@ -78,6 +78,7 @@
.if ${MK_BHYVE_SNAPSHOT} != "no"
SRCS+= snapshot.c
+SRCS+= kern_snapshot.c
.endif
CFLAGS.kernemu_dev.c+= -I${SRCTOP}/sys/amd64
Index: usr.sbin/bhyve/atkbdc.c
===================================================================
--- usr.sbin/bhyve/atkbdc.c
+++ usr.sbin/bhyve/atkbdc.c
@@ -33,9 +33,9 @@
#include <sys/types.h>
#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
-#include <vmmapi.h>
#include <assert.h>
#include <errno.h>
@@ -585,12 +585,15 @@
SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->aux.irq_active, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->aux.irq, meta, ret, done);
+ SNAPSHOT_ADD_INTERN_ARR(ps2kbd, meta);
ret = ps2kbd_snapshot(atkbdc_sc->ps2kbd_sc, meta);
if (ret != 0)
goto done;
+ SNAPSHOT_REMOVE_INTERN_ARR(ps2kbd, meta);
+ SNAPSHOT_ADD_INTERN_ARR(ps2mouse, meta);
ret = ps2mouse_snapshot(atkbdc_sc->ps2mouse_sc, meta);
-
+ SNAPSHOT_REMOVE_INTERN_ARR(ps2kbd, meta);
done:
return (ret);
}
Index: usr.sbin/bhyve/kern_snapshot.c
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/kern_snapshot.c
@@ -0,0 +1,547 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2016 Flavius Anton
+ * Copyright (c) 2016 Mihai Tiganus
+ * Copyright (c) 2016-2019 Mihai Carabas
+ * Copyright (c) 2017-2019 Darius Mihai
+ * Copyright (c) 2017-2019 Elena Mihailescu
+ * Copyright (c) 2018-2019 Sergiu Weisz
+ * Copyright (c) 2020-2021 Ionut Mihalache
+ * The bhyve-snapshot feature was developed under sponsorships
+ * from Matthew Grooms.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <machine/atomic.h>
+#include <machine/segments.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <sysexits.h>
+#include <stdbool.h>
+#include <sys/ioctl.h>
+#include <machine/vmm.h>
+#include <machine/vmm_snapshot.h>
+#include <vmmapi.h>
+
+#ifdef JSON_SNAPSHOT_V2
+/* ################## kernel snapshot functions copies ##################### */
+
+/* vhpet */
+int
+vhpet_snapshot(struct vm_snapshot_meta *meta)
+{
+ struct vhpet_userspace *vhpet;
+ struct timer_userspace *timer;
+ int i, ret = 0;
+
+ SNAPSHOT_VAR_OR_LEAVE(vhpet->freq_sbt, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vhpet->config, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vhpet->isr, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(vhpet->countbase, meta, ret, done);
+
+ SNAPSHOT_ADD_INTERN_ARR(timers, meta);
+ for (i = 0; i < nitems(vhpet->timer); i++) {
+ timer = &vhpet->timer[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
+ SNAPSHOT_VAR_OR_LEAVE(timer->cap_config, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(timer->msireg, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(timer->compval, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(timer->comprate, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(timer->callout_sbt, meta, ret, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(timers, meta);
+
+done:
+ return (ret);
+}
+
+
+/* vioapic */
+int
+vioapic_snapshot(struct vm_snapshot_meta *meta)
+{
+ struct rtbl_userspace *rtbl;
+ struct vioapic_userspace *vioapic;
+ int ret;
+ int i;
+
+ SNAPSHOT_VAR_OR_LEAVE(vioapic->ioregsel, meta, ret, done);
+
+ SNAPSHOT_ADD_INTERN_ARR(rtbls, meta);
+ for (i = 0; i < nitems(vioapic->rtbl); i++) {
+ rtbl = &vioapic->rtbl[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
+ SNAPSHOT_VAR_OR_LEAVE(rtbl->reg, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(rtbl->acnt, meta, ret, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(rtbls, meta);
+
+done:
+ return (ret);
+}
+
+/* vm (vcpus) */
+static int
+vm_snapshot_vcpus(struct vm_userspace *vm, struct vm_snapshot_meta *meta)
+{
+ int ret;
+ int i;
+ struct vcpu_userspace *vcpu;
+
+ SNAPSHOT_ADD_INTERN_ARR(vcpus, meta);
+ for (i = 0; i < VM_MAXCPU; i++) {
+ vcpu = &vm->vcpu[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->x2apic_state, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->exitintinfo, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_vector, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_errcode_valid, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->exc_errcode, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->guest_xcr0, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->exitinfo, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->nextrip, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(vcpu->tsc_offset, meta, ret, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(vcpus, meta);
+
+done:
+ return (ret);
+}
+
+int
+vm_snapshot_vm(struct vm_snapshot_meta *meta)
+{
+ int ret;
+ struct vm_userspace *vm;
+
+ ret = 0;
+
+ ret = vm_snapshot_vcpus(vm, meta);
+ if (ret != 0) {
+ printf("%s: failed to copy vm data to user buffer", __func__);
+ goto done;
+ }
+
+done:
+ return (ret);
+}
+
+/* vlapic */
+int
+vlapic_snapshot(struct vm_snapshot_meta *meta)
+{
+ int i, ret;
+ struct vlapic_userspace *vlapic;
+ uint32_t ccr;
+
+ ret = 0;
+
+ SNAPSHOT_ADD_INTERN_ARR(vlapic, meta);
+ for (i = 0; i < VM_MAXCPU; i++) {
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
+ /* snapshot the page first; timer period depends on icr_timer */
+ SNAPSHOT_BUF_OR_LEAVE(vlapic->apic_page, PAGE_SIZE, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(vlapic->esr_pending, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(vlapic->timer_freq_bt.sec,
+ meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vlapic->timer_freq_bt.frac,
+ meta, ret, done);
+
+ SNAPSHOT_BUF_OR_LEAVE(vlapic->isrvec_stk,
+ sizeof(vlapic->isrvec_stk),
+ meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vlapic->isrvec_stk_top, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vlapic->boot_state, meta, ret, done);
+
+ SNAPSHOT_BUF_OR_LEAVE(vlapic->lvt_last,
+ sizeof(vlapic->lvt_last),
+ meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(ccr, meta, ret, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(vlapic, meta);
+
+done:
+ return (ret);
+}
+
+/* vatpic */
+int
+vatpic_snapshot(struct vm_snapshot_meta *meta)
+{
+ int ret;
+ int i;
+ struct atpic_userspace *atpic;
+ struct vatpic_userspace *vatpic;
+
+ SNAPSHOT_ADD_INTERN_ARR(atpic, meta);
+ for (i = 0; i < nitems(vatpic->atpic); i++) {
+ atpic = &vatpic->atpic[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
+ SNAPSHOT_VAR_OR_LEAVE(atpic->ready, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->icw_num, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->rd_cmd_reg, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(atpic->aeoi, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->poll, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->rotate, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->sfn, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->irq_base, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->request, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->service, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->mask, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->smm, meta, ret, done);
+
+ SNAPSHOT_BUF_OR_LEAVE(atpic->acnt, sizeof(atpic->acnt),
+ meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->lowprio, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(atpic->intr_raised, meta, ret, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(atpic, meta);
+
+ SNAPSHOT_BUF_OR_LEAVE(vatpic->elc, sizeof(vatpic->elc),
+ meta, ret, done);
+
+done:
+ return (ret);
+}
+
+/* vatpit */
+int
+vatpit_snapshot(struct vm_snapshot_meta *meta)
+{
+ int ret;
+ int i;
+ struct channel_userspace *channel;
+ struct vatpit_userspace *vatpit;
+
+ SNAPSHOT_VAR_OR_LEAVE(vatpit->freq_bt.sec, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vatpit->freq_bt.frac, meta, ret, done);
+
+ SNAPSHOT_ADD_INTERN_ARR(channels, meta);
+ for (i = 0; i < nitems(vatpit->channel); i++) {
+ channel = &vatpit->channel[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
+ SNAPSHOT_VAR_OR_LEAVE(channel->mode, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->initial, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->now_bt.sec, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->now_bt.frac, meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(channel->cr, sizeof(channel->cr),
+ meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(channel->ol, sizeof(channel->ol),
+ meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->slatched, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->status, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->crbyte, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->frbyte, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->callout_bt.sec, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(channel->callout_bt.frac, meta, ret,
+ done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(channels, meta);
+
+done:
+ return (ret);
+}
+
+/* vmptmr */
+int
+vpmtmr_snapshot(struct vm_snapshot_meta *meta)
+{
+ int ret;
+ struct vpmtmr_userspace *vpmtmr;
+
+ SNAPSHOT_VAR_OR_LEAVE(vpmtmr->baseval, meta, ret, done);
+
+done:
+ return (ret);
+}
+
+/* vrtc */
+int
+vrtc_snapshot(struct vm_snapshot_meta *meta)
+{
+ int ret;
+ struct vrtc_userspace *vrtc;
+
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->addr, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->base_rtctime, meta, ret, done);
+
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.sec, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.alarm_sec, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.min, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.alarm_min, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.hour, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.alarm_hour, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.day_of_week, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.day_of_month, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.month, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.year, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.reg_a, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.reg_b, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.reg_c, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.reg_d, meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(vrtc->rtcdev.nvram, sizeof(vrtc->rtcdev.nvram),
+ meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vrtc->rtcdev.century, meta, ret, done);
+ SNAPSHOT_BUF_OR_LEAVE(vrtc->rtcdev.nvram2, sizeof(vrtc->rtcdev.nvram2),
+ meta, ret, done);
+
+done:
+ return (ret);
+}
+
+/* vmx */
+int
+vmx_snapshot(struct vm_snapshot_meta *meta)
+{
+ struct vmx_userspace *vmx;
+ struct vmxctx_userspace *vmxctx;
+ int i;
+ uint64_t *guest_msrs;
+ int ret;
+
+ SNAPSHOT_ADD_INTERN_ARR(vmx, meta);
+ for (i = 0; i < VM_MAXCPU; i++) {
+ guest_msrs = vmx->guest_msrs[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+ SNAPSHOT_BUF_OR_LEAVE(guest_msrs,
+ sizeof(vmx->guest_msrs[i]), meta, ret, done);
+
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_ADD_INTERN_ARR(guest_registers, meta);
+ vmxctx = &vmx->ctx[i];
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rdi, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rsi, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rdx, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rcx, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r8, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r9, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rax, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rbx, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_rbp, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r10, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r11, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r12, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r13, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r14, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_r15, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_cr2, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_dr0, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_dr1, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_dr2, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_dr3, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmxctx->guest_dr6, meta, ret, done);
+ SNAPSHOT_REMOVE_INTERN_ARR(guest_registers, meta);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(vmx, meta);
+
+done:
+ return (ret);
+}
+
+/* vmcx */
+static int
+vmcs_snapshot_desc(struct vm_snapshot_meta *meta)
+{
+ int ret;
+ struct seg_desc desc;
+
+ SNAPSHOT_VAR_OR_LEAVE(desc.base, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(desc.limit, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(desc.access, meta, ret, done);
+
+done:
+ return (ret);
+}
+
+int
+vmx_vmcx_snapshot(struct vm_snapshot_meta *meta)
+{
+ struct vmcs_userspace *vmcs;
+ struct vmx_userspace *vmx;
+ int err, i;
+ uint64_t vm_reg_guest_cr0, vm_reg_guest_cr3, vm_reg_guest_cr4;
+ uint64_t vm_reg_guest_dr7, vm_reg_guest_rsp, vm_reg_guest_rip;
+ uint64_t vm_reg_guest_rflags;
+
+ uint64_t vm_reg_guest_es, vm_reg_guest_cs, vm_reg_guest_ss, vm_reg_guest_ds;
+ uint64_t vm_reg_guest_fs, vm_reg_guest_gs, vm_reg_guest_tr;
+ uint64_t vm_reg_guest_ldtr, vm_reg_guest_efer;
+
+ uint64_t vm_reg_guest_pdpte0, vm_reg_guest_pdpte1;
+ uint64_t vm_reg_guest_pdpte2, vm_reg_guest_pdpte3;
+
+ uint64_t vmcs_guest_ia32_sysenter_cs, vmcs_guest_ia32_sysenter_esp;
+ uint64_t vmcs_guest_ia32_sysenter_eip, vmcs_guest_interruptibility;
+ uint64_t vmcs_guest_activity, vmcs_entry_ctls, vmcs_exit_ctls;
+
+ SNAPSHOT_ADD_INTERN_ARR(vcpu, meta);
+ for (i = 0; i < VM_MAXCPU; i++) {
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+ err = 0;
+
+ vmcs = &vmx->vmcs[i];
+
+ vm_reg_guest_cr0 = VM_REG_GUEST_CR0;
+ vm_reg_guest_cr3 = VM_REG_GUEST_CR3;
+ vm_reg_guest_cr4 = VM_REG_GUEST_CR4;
+ vm_reg_guest_dr7 = VM_REG_GUEST_DR7;
+ vm_reg_guest_rsp = VM_REG_GUEST_RSP;
+ vm_reg_guest_rip = VM_REG_GUEST_RIP;
+ vm_reg_guest_rflags = VM_REG_GUEST_RFLAGS;
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_cr0, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_cr3, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_cr4, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_dr7, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_rsp, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_rip, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_rflags, meta, err, done);
+
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+
+ /* Guest segments */
+ SNAPSHOT_ADD_INTERN_ARR(guest_segments, meta);
+
+ vm_reg_guest_es = VM_REG_GUEST_ES;
+ vm_reg_guest_cs = VM_REG_GUEST_CS;
+ vm_reg_guest_ss = VM_REG_GUEST_SS;
+ vm_reg_guest_ds = VM_REG_GUEST_DS;
+ vm_reg_guest_fs = VM_REG_GUEST_FS;
+ vm_reg_guest_gs = VM_REG_GUEST_GS;
+ vm_reg_guest_tr = VM_REG_GUEST_TR;
+ vm_reg_guest_ldtr = VM_REG_GUEST_LDTR;
+ vm_reg_guest_efer = VM_REG_GUEST_EFER;
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_es, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(es_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(es_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_cs, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(cs_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(cs_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_ss, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(ss_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(ss_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_ds, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(ds_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(ds_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_fs, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(fs_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(fs_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_gs, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(gs_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(gs_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_tr, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(tr_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(tr_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_ldtr, meta, err, done);
+ SNAPSHOT_ADD_INTERN_ARR(ldtr_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(ldtr_desc, meta);
+
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_efer, meta, err, done);
+
+ SNAPSHOT_ADD_INTERN_ARR(efer_desc, meta);
+ err += vmcs_snapshot_desc(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(efer_desc, meta);
+
+ err += vmcs_snapshot_desc(meta);
+
+ SNAPSHOT_REMOVE_INTERN_ARR(guest_segments, meta);
+
+ /* Guest page tables */
+ vm_reg_guest_pdpte0 = VM_REG_GUEST_PDPTE0;
+ vm_reg_guest_pdpte1 = VM_REG_GUEST_PDPTE1;
+ vm_reg_guest_pdpte2 = VM_REG_GUEST_PDPTE2;
+ vm_reg_guest_pdpte3 = VM_REG_GUEST_PDPTE3;
+
+ SNAPSHOT_ADD_INTERN_ARR(guest_page_tables, meta);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_pdpte0, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_pdpte1, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_pdpte2, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vm_reg_guest_pdpte3, meta, err, done);
+ SNAPSHOT_REMOVE_INTERN_ARR(guest_page_tables, meta);
+
+ /* Other guest state */
+ vmcs_guest_ia32_sysenter_cs = VMCS_GUEST_IA32_SYSENTER_CS;
+ vmcs_guest_ia32_sysenter_esp = VMCS_GUEST_IA32_SYSENTER_ESP;
+ vmcs_guest_ia32_sysenter_eip = VMCS_GUEST_IA32_SYSENTER_EIP;
+ vmcs_guest_interruptibility = VMCS_GUEST_INTERRUPTIBILITY;
+ vmcs_guest_activity = VMCS_GUEST_ACTIVITY;
+ vmcs_entry_ctls = VMCS_ENTRY_CTLS;
+ vmcs_exit_ctls = VMCS_EXIT_CTLS;
+
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_guest_ia32_sysenter_cs, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_guest_ia32_sysenter_esp, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_guest_ia32_sysenter_eip, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_guest_interruptibility, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_guest_activity, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_entry_ctls, meta, err, done);
+ SNAPSHOT_VAR_OR_LEAVE(vmcs_exit_ctls, meta, err, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(vcpu, meta);
+
+done:
+ return (err);
+}
+
+/* ################## kernel snapshot functions copies ##################### */
+
+#endif
+
Index: usr.sbin/bhyve/pci_ahci.c
===================================================================
--- usr.sbin/bhyve/pci_ahci.c
+++ usr.sbin/bhyve/pci_ahci.c
@@ -1006,7 +1006,7 @@
ata_ident->capabilities1 = ATA_SUPPORT_LBA |
ATA_SUPPORT_DMA;
ata_ident->capabilities2 = (1 << 14 | 1);
- ata_ident->atavalid = ATA_FLAG_64_70 | ATA_FLAG_88;
+ ata_ident->atavalid = ATA_FLAG_54_58 | ATA_FLAG_64_70;
ata_ident->obsolete62 = 0x3f;
ata_ident->mwdmamodes = 7;
if (p->xfermode & ATA_WDMA0)
@@ -1055,7 +1055,8 @@
ata_ident->capabilities1 = ATA_SUPPORT_DMA |
ATA_SUPPORT_LBA | ATA_SUPPORT_IORDY;
ata_ident->capabilities2 = (1 << 14);
- ata_ident->atavalid = ATA_FLAG_64_70 | ATA_FLAG_88;
+ ata_ident->atavalid = ATA_FLAG_54_58 |
+ ATA_FLAG_64_70;
if (p->mult_sectors)
ata_ident->multi = (ATA_MULTI_VALID | p->mult_sectors);
if (sectors <= 0x0fffffff) {
@@ -2590,9 +2591,12 @@
SNAPSHOT_VAR_OR_LEAVE(sc->bohc, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->lintr, meta, ret, done);
+ SNAPSHOT_ADD_INTERN_ARR(ports, meta);
for (i = 0; i < MAX_PORTS; i++) {
port = &sc->port[i];
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
if (meta->op == VM_SNAPSHOT_SAVE)
bctx = port->bctx;
@@ -2618,11 +2622,17 @@
goto done;
}
+ SNAPSHOT_ADD_INTERN_ARR(port_cmd_lst_and_rfis, meta);
+ SNAPSHOT_ACTIVATE_AUTO_INDEXING(meta, 0);
+
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(port->cmd_lst,
AHCI_CL_SIZE * AHCI_MAX_SLOTS, false, meta, ret, done);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(port->rfis, 256, false, meta,
ret, done);
+ SNAPSHOT_DEACTIVATE_AUTO_INDEXING(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(port_cmd_lst_and_rfis, meta);
+
SNAPSHOT_VAR_OR_LEAVE(port->ata_ident, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->atapi, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->reset, meta, ret, done);
@@ -2652,9 +2662,8 @@
SNAPSHOT_VAR_OR_LEAVE(port->sntf, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->fbs, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->ioqsz, meta, ret, done);
-
- assert(TAILQ_EMPTY(&port->iobhd));
}
+ SNAPSHOT_REMOVE_INTERN_ARR(ports, meta);
done:
return (ret);
Index: usr.sbin/bhyve/pci_e82545.c
===================================================================
--- usr.sbin/bhyve/pci_e82545.c
+++ usr.sbin/bhyve/pci_e82545.c
@@ -46,6 +46,9 @@
#ifndef WITHOUT_CAPSICUM
#include <capsicum_helpers.h>
#endif
+
+#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
#include <err.h>
Index: usr.sbin/bhyve/pci_emul.c
===================================================================
--- usr.sbin/bhyve/pci_emul.c
+++ usr.sbin/bhyve/pci_emul.c
@@ -2274,6 +2274,8 @@
pci_snapshot_pci_dev(struct vm_snapshot_meta *meta)
{
struct pci_devinst *pi;
+ struct pcibar *pb;
+ struct msix_table_entry *mte;
int i;
int ret;
@@ -2296,21 +2298,28 @@
SNAPSHOT_BUF_OR_LEAVE(pi->pi_cfgdata, sizeof(pi->pi_cfgdata),
meta, ret, done);
+ SNAPSHOT_ADD_INTERN_ARR(pi_bars, meta);
for (i = 0; i < nitems(pi->pi_bar); i++) {
- SNAPSHOT_VAR_OR_LEAVE(pi->pi_bar[i].type, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(pi->pi_bar[i].size, meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(pi->pi_bar[i].addr, meta, ret, done);
+ pb = &(pi->pi_bar[i]);
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+ SNAPSHOT_VAR_OR_LEAVE(pb->type, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(pb->size, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(pb->addr, meta, ret, done);
}
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(pi_bars, meta);
/* Restore MSI-X table. */
+ SNAPSHOT_ADD_INTERN_ARR(pi_msix_table, meta);
for (i = 0; i < pi->pi_msix.table_count; i++) {
- SNAPSHOT_VAR_OR_LEAVE(pi->pi_msix.table[i].addr,
- meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(pi->pi_msix.table[i].msg_data,
- meta, ret, done);
- SNAPSHOT_VAR_OR_LEAVE(pi->pi_msix.table[i].vector_control,
- meta, ret, done);
- }
+ mte = &(pi->pi_msix.table[i]);
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+ SNAPSHOT_VAR_OR_LEAVE(mte->addr, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(mte->msg_data, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(mte->vector_control, meta, ret, done);
+ }
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(pi_msix_table, meta);
done:
return (ret);
Index: usr.sbin/bhyve/pci_fbuf.c
===================================================================
--- usr.sbin/bhyve/pci_fbuf.c
+++ usr.sbin/bhyve/pci_fbuf.c
@@ -35,8 +35,8 @@
#include <sys/mman.h>
#include <machine/vmm.h>
-#include <machine/vmm_snapshot.h>
#include <vmmapi.h>
+#include <machine/vmm_snapshot.h>
#include <stdio.h>
#include <stdlib.h>
Index: usr.sbin/bhyve/pci_lpc.c
===================================================================
--- usr.sbin/bhyve/pci_lpc.c
+++ usr.sbin/bhyve/pci_lpc.c
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
#include <err.h>
@@ -41,7 +42,6 @@
#include <stdlib.h>
#include <string.h>
-#include <vmmapi.h>
#include "acpi.h"
#include "debug.h"
@@ -150,7 +150,6 @@
printf("bootrom\n");
for (i = 0; i < LPC_UART_NUM; i++)
printf("%s\n", lpc_uart_names[i]);
- printf("%s\n", pctestdev_getname());
}
const char *
@@ -502,13 +501,17 @@
int unit, ret;
struct uart_softc *sc;
+ SNAPSHOT_ADD_INTERN_ARR(uart, meta);
for (unit = 0; unit < LPC_UART_NUM; unit++) {
sc = lpc_uart_softc[unit].uart_softc;
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, unit);
ret = uart_snapshot(sc, meta);
if (ret != 0)
goto done;
}
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(uart, meta);
done:
return (ret);
Index: usr.sbin/bhyve/pci_xhci.c
===================================================================
--- usr.sbin/bhyve/pci_xhci.c
+++ usr.sbin/bhyve/pci_xhci.c
@@ -3033,6 +3033,7 @@
SNAPSHOT_VAR_OR_LEAVE(sc->regsend, meta, ret, done);
/* opregs */
+ SNAPSHOT_ADD_INTERN_ARR(opregs, meta);
SNAPSHOT_VAR_OR_LEAVE(sc->opregs.usbcmd, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->opregs.usbsts, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->opregs.pgsz, meta, ret, done);
@@ -3073,8 +3074,10 @@
SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.er_enq_seg, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.er_events_cnt, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.event_pcs, meta, ret, done);
+ SNAPSHOT_REMOVE_INTERN_ARR(opregs, meta);
/* sanity checking */
+ SNAPSHOT_ADD_INTERN_ARR(sanity_checks, meta);
for (i = 1; i <= XHCI_MAX_DEVS; i++) {
dev = XHCI_DEVINST_PTR(sc, i);
if (dev == NULL)
@@ -3111,8 +3114,10 @@
}
}
}
+ SNAPSHOT_REMOVE_INTERN_ARR(sanity_checks, meta);
/* portregs */
+ SNAPSHOT_ADD_INTERN_ARR(portregs, meta);
for (i = 1; i <= XHCI_MAX_DEVS; i++) {
port = XHCI_PORTREG_PTR(sc, i);
dev = XHCI_DEVINST_PTR(sc, i);
@@ -3125,8 +3130,10 @@
SNAPSHOT_VAR_OR_LEAVE(port->portli, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(port->porthlpmc, meta, ret, done);
}
+ SNAPSHOT_REMOVE_INTERN_ARR(portregs, meta);
/* slots */
+ SNAPSHOT_ADD_INTERN_ARR(slots, meta);
if (meta->op == VM_SNAPSHOT_SAVE)
pci_xhci_map_devs_slots(sc, maps);
@@ -3171,6 +3178,7 @@
SNAPSHOT_VAR_OR_LEAVE(dev->hci.hci_address, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(dev->hci.hci_port, meta, ret, done);
}
+ SNAPSHOT_REMOVE_INTERN_ARR(slots, meta);
SNAPSHOT_VAR_OR_LEAVE(sc->usb2_port_start, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(sc->usb3_port_start, meta, ret, done);
Index: usr.sbin/bhyve/ps2kbd.c
===================================================================
--- usr.sbin/bhyve/ps2kbd.c
+++ usr.sbin/bhyve/ps2kbd.c
@@ -33,6 +33,8 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
#include <assert.h>
Index: usr.sbin/bhyve/ps2mouse.c
===================================================================
--- usr.sbin/bhyve/ps2mouse.c
+++ usr.sbin/bhyve/ps2mouse.c
@@ -32,6 +32,8 @@
#include <sys/types.h>
+#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
#include <assert.h>
Index: usr.sbin/bhyve/snapshot.h
===================================================================
--- usr.sbin/bhyve/snapshot.h
+++ usr.sbin/bhyve/snapshot.h
@@ -45,6 +45,12 @@
#define BHYVE_RUN_DIR "/var/run/bhyve/"
#define MAX_SNAPSHOT_FILENAME PATH_MAX
+#ifndef JSON_SNAPSHPT_V2
+
+#define JSON_SNAPSHOT_V2
+
+#endif
+
struct vmctx;
struct restore_state {
@@ -76,11 +82,23 @@
vm_resume_dev_cb resume_cb; /* callback for device resume */
};
+#ifdef JSON_SNAPSHOT_V2
+
struct vm_snapshot_kern_info {
const char *struct_name; /* kernel structure name*/
enum snapshot_req req; /* request type */
+ vm_snapshot_dev_cb snapshot_cb; /* callback for device snapshot */
};
+#else
+
+struct vm_snapshot_kern_info {
+ const char *struct_name; /* kernel structure name*/
+ enum snapshot_req req; /* request type */
+};
+
+#endif
+
void destroy_restore_state(struct restore_state *rstate);
const char *lookup_vmname(struct restore_state *rstate);
Index: usr.sbin/bhyve/snapshot.c
===================================================================
--- usr.sbin/bhyve/snapshot.c
+++ usr.sbin/bhyve/snapshot.c
@@ -68,7 +68,6 @@
#include <sysexits.h>
#include <stdbool.h>
#include <sys/ioctl.h>
-
#include <machine/vmm.h>
#ifndef WITHOUT_CAPSICUM
#include <machine/vmm_dev.h>
@@ -99,6 +98,14 @@
#include <libxo/xo.h>
#include <ucl.h>
+#ifdef JSON_SNAPSHOT_V2
+
+#include <openssl/evp.h>
+
+#include "../lib/libc/stdlib/hsearch.h"
+
+#endif
+
struct spinner_info {
const size_t *crtval;
const size_t maxval;
@@ -110,6 +117,18 @@
static struct winsize winsize;
static sig_t old_winch_handler;
+#ifdef JSON_SNAPSHOT_V2
+
+struct type_info {
+ char type_name[24];
+ char fmt_str[24];
+ unsigned char size;
+};
+
+static struct hsearch_data *types_htable;
+
+#endif
+
#define KB (1024UL)
#define MB (1024UL * KB)
#define GB (1024UL * MB)
@@ -131,6 +150,18 @@
#define JSON_MEMSIZE_KEY "memsize"
#define JSON_MEMFLAGS_KEY "memflags"
+#define JSON_VERSION_KEY "version"
+#define JSON_PARAMS_KEY "device_params"
+#define JSON_PARAM_KEY "param_name"
+#define JSON_PARAM_DATA_KEY "param_data"
+#define JSON_PARAM_DATA_SIZE_KEY "data_size"
+
+#define JSON_VERSION_KEY "version"
+#define JSON_PARAMS_KEY "device_params"
+#define JSON_PARAM_KEY "param_name"
+#define JSON_PARAM_DATA_KEY "param_data"
+#define JSON_PARAM_DATA_SIZE_KEY "data_size"
+
#define min(a,b) \
({ \
__typeof__ (a) _a = (a); \
@@ -142,38 +173,202 @@
{ "atkbdc", atkbdc_snapshot, NULL, NULL },
{ "virtio-net", pci_snapshot, pci_pause, pci_resume },
{ "virtio-blk", pci_snapshot, pci_pause, pci_resume },
- { "virtio-rnd", pci_snapshot, NULL, NULL },
{ "lpc", pci_snapshot, NULL, NULL },
{ "fbuf", pci_snapshot, NULL, NULL },
{ "xhci", pci_snapshot, NULL, NULL },
{ "e1000", pci_snapshot, NULL, NULL },
{ "ahci", pci_snapshot, pci_pause, pci_resume },
{ "ahci-hd", pci_snapshot, pci_pause, pci_resume },
- { "ahci-cd", pci_snapshot, pci_pause, pci_resume },
+ { "ahci-cd", pci_snapshot, NULL, NULL },
+};
+
+#ifdef JSON_SNAPSHOT_V2
+
+int vhpet_snapshot(struct vm_snapshot_meta *meta);
+int vm_snapshot_vm(struct vm_snapshot_meta *meta);
+int vmx_snapshot(struct vm_snapshot_meta *meta);
+int vioapic_snapshot(struct vm_snapshot_meta *meta);
+int vlapic_snapshot(struct vm_snapshot_meta *meta);
+int vmx_vmcx_snapshot(struct vm_snapshot_meta *meta);
+int vatpit_snapshot(struct vm_snapshot_meta *meta);
+int vatpic_snapshot(struct vm_snapshot_meta *meta);
+int vpmtmr_snapshot(struct vm_snapshot_meta *meta);
+int vrtc_snapshot(struct vm_snapshot_meta *meta);
+
+const struct vm_snapshot_kern_info snapshot_kern_structs[] = {
+ { "vhpet", STRUCT_VHPET, vhpet_snapshot },
+ { "vm", STRUCT_VM, vm_snapshot_vm },
+ { "vmx", STRUCT_VMX, vmx_snapshot },
+ { "vioapic", STRUCT_VIOAPIC, vioapic_snapshot },
+ { "vlapic", STRUCT_VLAPIC, vlapic_snapshot },
+ { "vmcx", STRUCT_VMCX, vmx_vmcx_snapshot },
+ { "vatpit", STRUCT_VATPIT, vatpit_snapshot },
+ { "vatpic", STRUCT_VATPIC, vatpic_snapshot },
+ { "vpmtmr", STRUCT_VPMTMR, vpmtmr_snapshot },
+ { "vrtc", STRUCT_VRTC, vrtc_snapshot },
};
+#else
+
const struct vm_snapshot_kern_info snapshot_kern_structs[] = {
- { "vhpet", STRUCT_VHPET },
- { "vm", STRUCT_VM },
- { "vmx", STRUCT_VMX },
- { "vioapic", STRUCT_VIOAPIC },
- { "vlapic", STRUCT_VLAPIC },
- { "vmcx", STRUCT_VMCX },
- { "vatpit", STRUCT_VATPIT },
- { "vatpic", STRUCT_VATPIC },
- { "vpmtmr", STRUCT_VPMTMR },
- { "vrtc", STRUCT_VRTC },
+ { "vhpet", STRUCT_VHPET, vhpet_snapshot },
+ { "vm", STRUCT_VM, vm_snapshot_vm },
+ { "vmx", STRUCT_VMX, vmx_snapshot },
+ { "vioapic", STRUCT_VIOAPIC, vioapic_snapshot },
+ { "vlapic", STRUCT_VLAPIC, vlapic_snapshot },
+ { "vmcx", STRUCT_VMCX, vmx_vmcx_snapshot },
+ { "vatpit", STRUCT_VATPIT, vatpit_snapshot },
+ { "vatpic", STRUCT_VATPIC, vatpic_snapshot },
+ { "vpmtmr", STRUCT_VPMTMR, vpmtmr_snapshot },
+ { "vrtc", STRUCT_VRTC, vrtc_snapshot },
};
+#endif
+
static cpuset_t vcpus_active, vcpus_suspended;
static pthread_mutex_t vcpu_lock;
static pthread_cond_t vcpus_idle, vcpus_can_run;
static bool checkpoint_active;
-/*
- * TODO: Harden this function and all of its callers since 'base_str' is a user
- * provided string.
- */
+#ifdef JSON_SNAPSHOT_V2
+
+static void
+write_param_array(struct vm_snapshot_meta *meta, xo_handle_t *xop);
+
+static int
+vm_snapshot_dev_intern_arr(xo_handle_t *xop, int ident, int index,
+ struct vm_snapshot_device_info **curr_el);
+
+static int
+emit_data(xo_handle_t *xop, struct vm_snapshot_device_info *elem);
+
+static int
+create_types_hashtable();
+
+static int
+add_device_info(struct vm_snapshot_device_info *field_info, char *field_name,
+ const char *arr_name, int index, volatile void *data,
+ char *type, size_t data_size)
+{
+ if (arr_name != NULL) {
+ field_info->intern_arr_name = strdup(arr_name);
+ if (field_info->intern_arr_name == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ return (-1);
+ }
+ } else
+ field_info->intern_arr_name = NULL;
+
+ field_info->field_name = strdup(field_name);
+ if (field_info->field_name == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ return (-1);
+ }
+
+ field_info->index = index;
+
+ if (data_size != 0 && data != NULL) {
+ field_info->field_data = calloc(data_size + 1, sizeof(char));
+ if (field_info->field_data == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ return (-1);
+ }
+ memcpy(field_info->field_data, (uint8_t *)data, data_size);
+ field_info->data_size = data_size;
+ }
+
+ if (type != NULL) {
+ field_info->type = strdup(type);
+ if (field_info->type == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+alloc_device_info_elem(struct list_device_info *list, char *field_name,
+ volatile void *data, char *type, size_t data_size)
+{
+ const char *arr_name = NULL;
+ char *t;
+ struct vm_snapshot_device_info *aux;
+ int index;
+ int ret;
+
+ ret = 0;
+
+ aux = calloc(1, sizeof(struct vm_snapshot_device_info));
+ if (aux == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ return (-1);
+ }
+ aux->ident = list->ident;
+ aux->create_instance = list->create_instance;
+ if (aux->ident > 0)
+ arr_name = list->intern_arr_names[aux->ident - 1];
+ if (list->auto_index != -1)
+ index = list->auto_index;
+ else
+ index = list->index;
+
+ t = type;
+ if (list->type != NULL)
+ t = list->type;
+
+ ret = add_device_info(aux, field_name, arr_name, index, data, t, data_size);
+ if (ret != 0)
+ return (ret);
+ list->type = NULL;
+ if (list->first == NULL) {
+ list->first = aux;
+ list->last = list->first;
+ } else if (list->first == list->last) {
+ list->first->next_field = aux;
+ list->last = aux;
+ } else {
+ list->last->next_field = aux;
+ list->last = list->last->next_field;
+ }
+
+ return (ret);
+}
+
+void
+remove_first_elem(struct list_device_info *list)
+{
+ struct vm_snapshot_device_info *aux;
+
+ aux = list->first;
+ list->first = aux->next_field;
+ free(aux);
+}
+
+void
+free_device_info_list(struct list_device_info *list)
+{
+ struct vm_snapshot_device_info *curr_el, *aux;
+
+ curr_el = list->first;
+ while (curr_el != NULL) {
+ free(curr_el->intern_arr_name);
+ free(curr_el->field_name);
+ free(curr_el->field_data);
+
+ aux = curr_el->next_field;
+ free(curr_el);
+ curr_el = aux;
+ }
+ list->ident = 0;
+ memset(list->intern_arr_names, 0, IDENT_LEVEL * sizeof(char *));
+ list->type = NULL;
+ list->first = NULL;
+ list->last = NULL;
+}
+
+#endif
static char *
strcat_extension(const char *base_str, const char *ext)
{
@@ -256,6 +451,8 @@
return (-1);
}
+#ifndef JSON_SNAPSHOT_V2
+
static int
load_kdata_file(const char *filename, struct restore_state *rstate)
{
@@ -295,6 +492,8 @@
return (-1);
}
+#endif
+
static int
load_metadata_file(const char *filename, struct restore_state *rstate)
{
@@ -352,6 +551,7 @@
goto err_restore;
}
+#ifndef JSON_SNAPSHOT_V2
kdata_filename = strcat_extension(filename, ".kern");
if (kdata_filename == NULL) {
fprintf(stderr, "Failed to construct kernel data filename.\n");
@@ -363,7 +563,8 @@
fprintf(stderr, "Failed to load guest kernel data file.\n");
goto err_restore;
}
-
+#endif
+
meta_filename = strcat_extension(filename, ".meta");
if (meta_filename == NULL) {
fprintf(stderr, "Failed to construct kernel metadata filename.\n");
@@ -415,6 +616,282 @@
} \
} while(0)
+#define JSON_GET_STRING_VALUE_OR_RETURN(key, obj, result_ptr, ret) \
+do { \
+ const ucl_object_t *obj__; \
+ obj__ = ucl_object_lookup(obj, (key)); \
+ if (obj__ == NULL) { \
+ fprintf(stderr, "Missing key: '%s'", (key)); \
+ return (ret); \
+ } \
+ if (!ucl_object_tostring_safe(obj__, result_ptr)) { \
+ fprintf(stderr, "Cannot convert '%s' value to string.", (key)); \
+ return (ret); \
+ } \
+} while(0)
+
+
+#ifdef JSON_SNAPSHOT_V2
+
+int
+extract_type(char **type, const ucl_object_t *obj)
+{
+ char *key_copy = NULL;
+ char *aux = NULL;
+ const char delim[2] = "$";
+
+ key_copy = strdup(obj->key);
+ assert(key_copy != NULL);
+
+ /* Param name */
+ strtok(key_copy, delim);
+
+ aux = strtok(NULL, delim);
+ assert(aux != NULL);
+
+ *type = strdup(aux);
+ assert(*type != NULL);
+
+ free(key_copy);
+
+ return (0);
+}
+
+int
+restore_data(const ucl_object_t *obj, struct list_device_info *list)
+{
+ int ret;
+ const char *enc_data;
+ const char *str_data;
+ char *dec_data;
+ int enc_bytes;
+ int dec_bytes;
+ int64_t data_size;
+ int64_t int_data;
+ char *type;
+ char *endptr;
+
+ ret = 0;
+
+ extract_type(&type, obj);
+ if (!strcmp(type, "int8") ||
+ !strcmp(type, "uint8") ||
+ !strcmp(type, "int16") ||
+ !strcmp(type, "uint16") ||
+ !strcmp(type, "int32") ||
+ !strcmp(type, "uint32")) {
+
+ int_data = 0;
+ if (!ucl_object_toint_safe(obj, &int_data)) {
+ fprintf(stderr, "%s: Cannot convert '%s' value to int_t at line %d.\r\n",
+ __func__, obj->key, __LINE__);
+ ret = -1;
+ goto done;
+ }
+
+ alloc_device_info_elem(list, (char *)obj->key, &int_data, NULL, sizeof(int_data));
+ } else if (!strcmp(type, "int64") ||
+ !strcmp(type, "uint64")) {
+ str_data = NULL;
+ if (!ucl_object_tostring_safe(obj, &str_data)) {
+ fprintf(stderr, "%s: Cannot convert '%s' value to string.\r\n",
+ __func__, obj->key);
+ ret = -1;
+ goto done;
+ }
+ assert(str_data != NULL);
+
+ errno = 0;
+ int_data = (int64_t)strtoul(str_data, &endptr, 10);
+ if ((errno != 0) || (endptr == str_data)) {
+ fprintf(stderr, "%s: Cannot convert '%s' value to int.\r\n",
+ __func__, str_data);
+ ret = ((errno == 0) ? -1 : errno);
+ goto done;
+ }
+
+ alloc_device_info_elem(list, (char *)obj->key, &int_data, NULL, sizeof(int_data));
+ } else if (!strcmp(type, "int64") ||
+ !strcmp(type, "uint64")) {
+ sscanf(obj->value.sv, "%lx", &int_data);
+
+ alloc_device_info_elem(list, (char *)obj->key, &int_data, NULL, sizeof(int_data));
+ } else {
+ enc_data = NULL;
+ if (!ucl_object_tostring_safe(obj, &enc_data)) {
+ fprintf(stderr, "Cannot convert '%s' value to string.\r\n", obj->key);
+ ret = -1;
+ goto done;
+ }
+ assert(enc_data != NULL);
+
+ data_size = strlen(enc_data);
+ enc_bytes = (data_size >> 2) * 3;
+ dec_data = NULL;
+ dec_data = malloc((enc_bytes + 2) * sizeof(char));
+ assert(dec_data != NULL);
+
+ dec_bytes = EVP_DecodeBlock(dec_data, enc_data, data_size);
+ assert(dec_bytes > 0);
+
+ alloc_device_info_elem(list, (char *)obj->key, dec_data, NULL, (size_t)data_size);
+ }
+
+done:
+ free(type);
+ return (ret);
+}
+
+int
+intern_arr_restore(const char *intern_arr_name, struct list_device_info *list,
+ const ucl_object_t *obj)
+{
+ const ucl_object_t *param = NULL, *intern_obj = NULL;
+ ucl_object_iter_t it = NULL, iit = NULL;
+ int is_list;
+ int ret = 0;
+
+ /* Check if the received instance contains an array */
+ while ((param = ucl_object_iterate(obj, &it, true)) != NULL) {
+ while ((intern_obj = ucl_object_iterate(param, &iit, true)) != NULL) {
+ is_list = (ucl_object_type(intern_obj) == UCL_ARRAY);
+
+ if (!is_list)
+ ret = restore_data(intern_obj, list);
+ else
+ ret = intern_arr_restore(intern_obj->key, list, intern_obj);
+
+ if (ret != 0)
+ goto done;
+ }
+ }
+
+done:
+ return (ret);
+}
+
+static int
+lookup_struct(enum snapshot_req struct_id, struct restore_state *rstate,
+ struct list_device_info *list)
+{
+ const ucl_object_t *structs = NULL, *obj = NULL;
+ const ucl_object_t *dev_params = NULL;
+ ucl_object_iter_t it = NULL;
+ int64_t snapshot_req;
+
+ structs = ucl_object_lookup(rstate->meta_root_obj, JSON_STRUCT_ARR_KEY);
+ if (structs == NULL) {
+ fprintf(stderr, "Failed to find '%s' object.\r\n",
+ JSON_STRUCT_ARR_KEY);
+ return (-1);
+ }
+
+ if (ucl_object_type((ucl_object_t *)structs) != UCL_ARRAY) {
+ fprintf(stderr, "Object '%s' is not an array.\r\n",
+ JSON_STRUCT_ARR_KEY);
+ return (-1);
+ }
+
+ while ((obj = ucl_object_iterate(structs, &it, true)) != NULL) {
+ snapshot_req = -1;
+ JSON_GET_INT_OR_RETURN(JSON_SNAPSHOT_REQ_KEY, obj,
+ &snapshot_req, -1);
+ assert(snapshot_req >= 0);
+ if ((enum snapshot_req) snapshot_req == struct_id) {
+ dev_params = ucl_object_lookup(obj, JSON_PARAMS_KEY);
+ if (dev_params == NULL) {
+ fprintf(stderr, "Failed to find '%s' object.\r\n",
+ JSON_PARAMS_KEY);
+ return(-EINVAL);
+ }
+
+ if (ucl_object_type((ucl_object_t *)dev_params) != UCL_ARRAY) {
+ fprintf(stderr, "Object '%s' is not an array.\r\n",
+ JSON_PARAMS_KEY);
+ return (-EINVAL);
+ }
+
+ /* Iterate through device parameters */
+ intern_arr_restore(JSON_PARAMS_KEY, list, dev_params);
+
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+int
+lookup_check_dev(const char *dev_name, struct restore_state *rstate,
+ const ucl_object_t *obj,
+ struct list_device_info *list)
+{
+ const ucl_object_t *dev_params = NULL;
+ const char *snapshot_req;
+
+ snapshot_req = NULL;
+ JSON_GET_STRING_OR_RETURN(JSON_SNAPSHOT_REQ_KEY, obj,
+ &snapshot_req, -EINVAL);
+ if (snapshot_req == NULL) {
+ fprintf(stderr, "%s: Could not extract device name\r\n", __func__);
+ return (-1);
+ }
+
+ if (!strcmp(snapshot_req, dev_name)) {
+ dev_params = ucl_object_lookup(obj, JSON_PARAMS_KEY);
+ if (dev_params == NULL) {
+ fprintf(stderr, "Failed to find '%s' object.\n",
+ JSON_PARAMS_KEY);
+ return(-EINVAL);
+ }
+
+ if (ucl_object_type((ucl_object_t *)dev_params) != UCL_ARRAY) {
+ fprintf(stderr, "Object '%s' is not an array.\n",
+ JSON_PARAMS_KEY);
+ return (-EINVAL);
+ }
+
+ /* Iterate through device parameters */
+ intern_arr_restore(JSON_PARAMS_KEY, list, dev_params);
+
+ return (0);
+ }
+
+ return (-1);
+}
+
+int
+lookup_dev(const char *dev_name, struct restore_state *rstate,
+ struct list_device_info *list)
+{
+ const ucl_object_t *devs = NULL, *obj = NULL;
+ ucl_object_iter_t it = NULL;
+ int ret;
+
+ devs = ucl_object_lookup(rstate->meta_root_obj, JSON_DEV_ARR_KEY);
+ if (devs == NULL) {
+ fprintf(stderr, "Failed to find '%s' object.\n",
+ JSON_DEV_ARR_KEY);
+ return (-EINVAL);
+ }
+
+ if (ucl_object_type((ucl_object_t *)devs) != UCL_ARRAY) {
+ fprintf(stderr, "Object '%s' is not an array.\n",
+ JSON_DEV_ARR_KEY);
+ return (-EINVAL);
+ }
+
+ while ((obj = ucl_object_iterate(devs, &it, true)) != NULL) {
+ ret = lookup_check_dev(dev_name, rstate, obj, list);
+ if (ret == 0)
+ return (ret);
+ }
+
+ return (-1);
+}
+
+#else
+
static void *
lookup_struct(enum snapshot_req struct_id, struct restore_state *rstate,
size_t *struct_size)
@@ -517,6 +994,8 @@
return (NULL);
}
+#endif
+
static const ucl_object_t *
lookup_basic_metadata_object(struct restore_state *rstate)
{
@@ -590,9 +1069,7 @@
lookup_guest_ncpus(struct restore_state *rstate)
{
int64_t ncpus;
- const ucl_object_t *obj;
-
- obj = lookup_basic_metadata_object(rstate);
+ const ucl_object_t *obj; obj = lookup_basic_metadata_object(rstate);
if (obj == NULL)
return (0);
@@ -860,24 +1337,39 @@
return (0);
}
+#ifdef JSON_SNAPSHOT_V2
+
static int
vm_restore_kern_struct(struct vmctx *ctx, struct restore_state *rstate,
const struct vm_snapshot_kern_info *info)
{
- void *struct_ptr;
- size_t struct_size;
int ret;
+ struct list_device_info list;
struct vm_snapshot_meta *meta;
+ void *buffer;
+ size_t buf_size;
+
+ buf_size = SNAPSHOT_BUFFER_SIZE;
+
+ buffer = calloc(1, buf_size);
+ if (buffer == NULL) {
+ perror("Failed to allocate memory for snapshot buffer");
+ ret = ENOSPC;
+ goto done;
+ }
+
+ memset(&list, 0, sizeof(list));
+ list.first = NULL;
+ list.last = NULL;
- struct_ptr = lookup_struct(info->req, rstate, &struct_size);
- if (struct_ptr == NULL) {
+ ret = lookup_struct(info->req, rstate, &list);
+ if (ret != 0) {
fprintf(stderr, "%s: Failed to lookup struct %s\r\n",
__func__, info->struct_name);
- ret = -1;
goto done;
}
- if (struct_size == 0) {
+ if (list.first == NULL) {
fprintf(stderr, "%s: Kernel struct size was 0 for: %s\r\n",
__func__, info->struct_name);
ret = -1;
@@ -889,15 +1381,28 @@
.dev_name = info->struct_name,
.dev_req = info->req,
- .buffer.buf_start = struct_ptr,
- .buffer.buf_size = struct_size,
-
- .buffer.buf = struct_ptr,
- .buffer.buf_rem = struct_size,
+ .buffer.buf_start = buffer,
+ .buffer.buf_size = buf_size,
+ .buffer.buf = buffer,
+ .buffer.buf_rem = buf_size,
.op = VM_SNAPSHOT_RESTORE,
+ .version = JSON_V2,
+ .dev_info_list.ident = 0,
+ .dev_info_list.first = list.first,
+ .dev_info_list.last = list.last,
+ .snapshot_kernel = 1,
};
+ ret = (*info->snapshot_cb)(meta);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to restore dev: %s\r\n",
+ info->struct_name);
+ return (-1);
+ }
+
+ meta->buffer.buf = meta->buffer.buf_start;
+
ret = vm_snapshot_req(meta);
if (ret != 0) {
fprintf(stderr, "%s: Failed to restore struct: %s\r\n",
@@ -909,10 +1414,76 @@
return (ret);
}
-int
-vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate)
-{
- int ret;
+#else
+
+static int
+vm_restore_kern_struct(struct vmctx *ctx, struct restore_state *rstate,
+ const struct vm_snapshot_kern_info *info)
+{
+ int ret;
+ struct list_device_info list;
+ struct vm_snapshot_meta *meta;
+ void *buffer;
+ size_t buf_size;
+
+ buf_size = SNAPSHOT_BUFFER_SIZE;
+
+ buffer = calloc(1, buf_size);
+ if (buffer == NULL) {
+ perror("Failed to allocate memory for snapshot buffer");
+ ret = ENOSPC;
+ goto done;
+ }
+
+ memset(&list, 0, sizeof(list));
+ list.first = NULL;
+ list.last = NULL;
+
+ ret = lookup_struct(info->req, rstate, &list);
+ if (ret != 0) {
+ fprintf(stderr, "%s: Failed to lookup struct %s\r\n",
+ __func__, info->struct_name);
+ goto done;
+ }
+
+ if (list.first == 0) {
+ fprintf(stderr, "%s: Kernel struct size was 0 for: %s\r\n",
+ __func__, info->struct_name);
+ ret = -1;
+ goto done;
+ }
+
+ meta = &(struct vm_snapshot_meta) {
+ .ctx = ctx,
+ .dev_name = info->struct_name,
+ .dev_req = info->req,
+
+ .buffer.buf_start = buffer,
+ .buffer.buf_size = buf_size,
+ .buffer.buf = buffer,
+ .buffer.buf_rem = buf_size,
+
+ .op = VM_SNAPSHOT_RESTORE,
+ .version = JSON_V1,
+ };
+
+ ret = vm_snapshot_req(meta);
+ if (ret != 0) {
+ fprintf(stderr, "%s: Failed to restore struct: %s\r\n",
+ __func__, info->struct_name);
+ goto done;
+ }
+
+done:
+ return (ret);
+}
+
+#endif
+
+int
+vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate)
+{
+ int ret;
int i;
for (i = 0; i < nitems(snapshot_kern_structs); i++) {
@@ -925,6 +1496,50 @@
return (0);
}
+#ifdef JSON_SNAPSHOT_V2
+
+int
+vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate,
+ const struct vm_snapshot_dev_info *info)
+{
+ int ret;
+ struct list_device_info list;
+ struct vm_snapshot_meta *meta;
+
+ memset(&list, 0, sizeof(list));
+ list.first = NULL;
+ list.last = NULL;
+
+ ret = lookup_dev(info->dev_name, rstate, &list);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to lookup dev: %s\r\n", info->dev_name);
+ fprintf(stderr, "Continuing the restore/migration process\r\n");
+ return (0);
+ }
+
+ meta = &(struct vm_snapshot_meta) {
+ .ctx = ctx,
+ .dev_name = info->dev_name,
+
+ .op = VM_SNAPSHOT_RESTORE,
+
+ .version = JSON_V2,
+ .dev_info_list.ident = 0,
+ .dev_info_list.first = list.first,
+ .dev_info_list.last = list.last,
+ };
+
+ ret = (*info->snapshot_cb)(meta);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to restore dev: %s\r\n",
+ info->dev_name);
+ return (-1);
+ }
+
+ return (0);
+}
+
+#else
int
vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate,
const struct vm_snapshot_dev_info *info)
@@ -946,7 +1561,7 @@
"Assuming %s is not used\r\n",
__func__, info->dev_name);
return (0);
- }
+ }
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
@@ -959,6 +1574,7 @@
.buffer.buf_rem = dev_size,
.op = VM_SNAPSHOT_RESTORE,
+ .version = JSON_V1,
};
ret = (*info->snapshot_cb)(meta);
@@ -971,6 +1587,7 @@
return (0);
}
+#endif
int
vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate)
@@ -982,6 +1599,7 @@
ret = vm_restore_user_dev(ctx, rstate, &snapshot_devs[i]);
if (ret != 0)
return (ret);
+ fprintf(stderr, "%s restored successfully\r\n", snapshot_devs[i].dev_name);
}
return 0;
@@ -1028,7 +1646,8 @@
}
static int
-vm_snapshot_kern_struct(int data_fd, xo_handle_t *xop, const char *array_key,
+vm_snapshot_kern_struct(const struct vm_snapshot_kern_info *info,
+ int data_fd, xo_handle_t *xop, const char *array_key,
struct vm_snapshot_meta *meta, off_t *offset)
{
int ret;
@@ -1043,25 +1662,69 @@
goto done;
}
- data_size = vm_get_snapshot_size(meta);
+ if (meta->version == JSON_V1) {
+ data_size = vm_get_snapshot_size(meta);
- write_cnt = write(data_fd, meta->buffer.buf_start, data_size);
- if (write_cnt != data_size) {
- perror("Failed to write all snapshotted data.");
- ret = -1;
- goto done;
+ write_cnt = write(data_fd, meta->buffer.buf_start, data_size);
+ if (write_cnt != data_size) {
+ perror("Failed to write all snapshotted data.");
+ ret = -1;
+ goto done;
+ }
+ }
+ meta->buffer.buf = meta->buffer.buf_start;
+ fprintf(stderr, "%s: %s has size %ld\r\n", __func__, meta->dev_name, data_size);
+
+ if (!strcmp(meta->dev_name, "vhpet"))
+ vhpet_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vm"))
+ vm_snapshot_vm(meta);
+ else if (!strcmp(meta->dev_name, "vlapic"))
+ vlapic_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vioapic"))
+ vioapic_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vatpit"))
+ vatpit_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vatpic"))
+ vatpic_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vpmtmr"))
+ vpmtmr_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vrtc"))
+ vrtc_snapshot(meta);
+ else if (!strcmp(meta->dev_name, "vmx"))
+ vmx_snapshot(meta);
+
+ if (meta->version == JSON_V1) {
+ data_size = vm_get_snapshot_size(meta);
+
+ write_cnt = write(data_fd, meta->buffer.buf_start, data_size);
+ if (write_cnt != data_size) {
+ perror("Failed to write all snapshotted data.");
+ ret = -1;
+ goto done;
+ }
}
+ meta->buffer.buf = meta->buffer.buf_start;
/* Write metadata. */
xo_open_instance_h(xop, array_key);
xo_emit_h(xop, "{:debug_name/%s}\n", meta->dev_name);
- xo_emit_h(xop, "{:" JSON_SNAPSHOT_REQ_KEY "/%d}\n",
- meta->dev_req);
- xo_emit_h(xop, "{:" JSON_SIZE_KEY "/%lu}\n", data_size);
- xo_emit_h(xop, "{:" JSON_FILE_OFFSET_KEY "/%lu}\n", *offset);
- xo_close_instance_h(xop, JSON_STRUCT_ARR_KEY);
+ xo_emit_h(xop, "{:" JSON_SNAPSHOT_REQ_KEY "/%d}\n", meta->dev_req);
+ if (meta->version == JSON_V1) {
+ xo_emit_h(xop, "{:" JSON_SIZE_KEY "/%lu}\n", data_size);
+ xo_emit_h(xop, "{:" JSON_FILE_OFFSET_KEY "/%lu}\n", *offset);
+ *offset += data_size;
+ } else if (meta->version == JSON_V2) {
+ ret = (*info->snapshot_cb)(meta);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to restore dev: %s\r\n",
+ info->struct_name);
+ return (-1);
+ }
- *offset += data_size;
+ write_param_array(meta, xop);
+ }
+ xo_close_instance_h(xop, array_key);
done:
return (ret);
@@ -1093,8 +1756,35 @@
.buffer.buf_size = buf_size,
.op = VM_SNAPSHOT_SAVE,
+#ifdef JSON_SNAPSHOT_V2
+ .version = JSON_V2,
+ .dev_info_list.ident = 0,
+ .dev_info_list.index = -1,
+ .dev_info_list.type = NULL,
+ .dev_info_list.create_instance = 1,
+ .dev_info_list.auto_index = -1,
+ .dev_info_list.first = NULL,
+ .dev_info_list.last = NULL,
+ .snapshot_kernel = 1,
+#else
+ .version = JSON_V1,
+#endif
};
+ /* Prepare types hashtable */
+ ret = create_types_hashtable();
+ if (ret != 0) {
+ error = -1;
+ goto err_vm_snapshot_kern_data;
+ }
+
+ /* Prepare types hashtable */
+ ret = create_types_hashtable();
+ if (ret != 0) {
+ error = -1;
+ goto err_vm_snapshot_kern_data;
+ }
+
xo_open_list_h(xop, JSON_STRUCT_ARR_KEY);
for (i = 0; i < nitems(snapshot_kern_structs); i++) {
meta->dev_name = snapshot_kern_structs[i].struct_name;
@@ -1104,8 +1794,13 @@
meta->buffer.buf = meta->buffer.buf_start;
meta->buffer.buf_rem = meta->buffer.buf_size;
- ret = vm_snapshot_kern_struct(data_fd, xop, JSON_DEV_ARR_KEY,
- meta, &offset);
+ if (meta->version == JSON_V2) {
+ free_device_info_list(&meta->dev_info_list);
+ meta->snapshot_kernel = 1;
+ }
+
+ ret = vm_snapshot_kern_struct(&snapshot_kern_structs[i], data_fd,
+ xop, JSON_STRUCT_ARR_KEY, meta, &offset);
if (ret != 0) {
error = -1;
goto err_vm_snapshot_kern_data;
@@ -1128,11 +1823,358 @@
xo_emit_h(xop, "{:" JSON_VMNAME_KEY "/%s}\n", vm_get_name(ctx));
xo_emit_h(xop, "{:" JSON_MEMSIZE_KEY "/%lu}\n", memsz);
xo_emit_h(xop, "{:" JSON_MEMFLAGS_KEY "/%d}\n", vm_get_memflags(ctx));
+#ifndef JSON_SNAPSHOT_V2
+ xo_emit_h(xop, "{:" JSON_VERSION_KEY "/%d}\n", JSON_V1);
+#else
+ xo_emit_h(xop, "{:" JSON_VERSION_KEY "/%d}\n", JSON_V2);
+#endif
xo_close_container_h(xop, JSON_BASIC_METADATA_KEY);
return (0);
}
+#ifdef JSON_SNAPSHOT_V2
+
+static int
+create_indexed_arr_name(char *intern_arr, int number, char **indexed_name)
+{
+ int ret;
+
+ ret = asprintf(indexed_name, "%s@%d", intern_arr, number);
+
+ if (ret < 0)
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+
+ return (ret);
+}
+
+static int
+create_type_info(struct type_info **ti, const char *name,
+ const char *fmt_str, unsigned char size)
+{
+ int ret;
+
+ ret = 0;
+
+ *ti = calloc(1, sizeof(struct type_info));
+ if (*ti == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ ret = ENOMEM;
+ }
+
+ strcpy((*ti)->type_name, name);
+ strcpy((*ti)->fmt_str, fmt_str);
+ (*ti)->size = size;
+
+ return (ret);
+}
+
+static int
+create_types_hashtable()
+{
+ int ret, i, j;
+ struct type_info *ti;
+ ENTRY item;
+ ENTRY *res = NULL;
+ const char *types[] = { "int8", "uint8", "int16", "uint16",
+ "int32", "uint32", "int64", "uint64" };
+
+ const char *fmt_strs[] = { "/%%hhd}\\n", "/%%hhu}\\n", "/%%hd}\\n",
+ "/%%hu}\\n", "/%%d}\\n", "/%%u}\\n", "/%%s}\\n", "/%%s}\\n" };
+
+ const unsigned char type_sizes[] = { sizeof(int8_t), sizeof(uint8_t),
+ sizeof(int16_t), sizeof(uint16_t),
+ sizeof(int32_t), sizeof(uint32_t),
+ sizeof(int64_t), sizeof(uint64_t) };
+ ret = 0;
+
+ types_htable = calloc(1, sizeof(*types_htable));
+ if (types_htable == NULL) {
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (!hcreate_r(32, types_htable)) {
+ ret = errno;
+ goto done;
+ }
+
+ for (i = 0; i < 8; ++i) {
+ ret = create_type_info(&ti, types[i], fmt_strs[i], type_sizes[i]);
+
+ if (ret != 0) {
+ j = i;
+ goto done;
+ }
+
+ item.key = (char *)ti->type_name;
+ item.data = ti;
+ if (!hsearch_r(item, ENTER, &res, types_htable)) {
+ j = i;
+ fprintf(stderr, "%s: Could not add data into hashtable(line %d)\r\n",
+ __func__, __LINE__);
+ ret = errno;
+ goto done;
+ }
+ }
+
+ return (ret);
+
+done:
+ free(types_htable);
+ types_htable = NULL;
+
+ for (i = 0; i < j; ++i) {
+ item.key = (char *)types[i];
+ if (!hsearch_r(item, FIND, &res, types_htable)) {
+ fprintf(stderr,
+ "%s: Could not find key %s in hashtable(line %d)\r\n",
+ __func__, item.key, __LINE__);
+ continue;
+ }
+ free(res->data);
+ }
+ hdestroy_r(types_htable);
+
+ return (ret);
+}
+
+static void
+destroy_types_hashtable()
+{
+ int i;
+ ENTRY item;
+ ENTRY *res = NULL;
+ const char *types[] = { "int8", "uint8", "int16", "uint16",
+ "int32", "uint32", "int64", "uint64" };
+
+ for (i = 0; i < 8; ++i) {
+ item.key = (char *)types[i];
+ if (!hsearch_r(item, FIND, &res, types_htable)) {
+ fprintf(stderr,
+ "%s: Could not find key %s in hashtable(line %d)\r\n",
+ __func__, item.key, __LINE__);
+ continue;
+ }
+
+ free(res->data);
+ }
+
+ hdestroy_r(types_htable);
+}
+
+static int
+get_type_format_string(char **res, char *key_part, char *type)
+{
+ int ret;
+ struct type_info *ti;
+ ENTRY item;
+ ENTRY *ires = NULL;
+
+ item.key = type;
+ if (hsearch_r(item, FIND, &ires, types_htable)) {
+ ti = (struct type_info *)(ires->data);
+ ret = asprintf(res, "%s%s", key_part, ti->fmt_str);
+ } else
+ ret = asprintf(res, "%s%s", key_part, "/%%s}\\n");
+
+ if (ret < 0)
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", __func__, __LINE__);
+
+ return (ret);
+}
+
+static int
+create_key_string(struct vm_snapshot_device_info *elem, char **res_str)
+{
+ int ret;
+ char *fmt = NULL;
+
+ ret = 0;
+ if (!elem->create_instance && (elem->index != -1)) {
+ ret = get_type_format_string(&fmt, "{:%s%d$%s", elem->type);
+ ret = asprintf(res_str, fmt, elem->field_name, elem->index, elem->type);
+ } else {
+ ret = get_type_format_string(&fmt, "{:%s$%s", elem->type);
+ ret = asprintf(res_str, fmt, elem->field_name, elem->type);
+ }
+
+ free(fmt);
+ return (ret);
+}
+
+static int
+emit_data(xo_handle_t *xop, struct vm_snapshot_device_info *elem)
+{
+ int ret;
+ char *enc_data = NULL;
+ char *fmt;
+ char *lv_str;
+ int enc_bytes = 0;
+ uint64_t int_data;
+
+ unsigned long ds;
+
+ ENTRY item;
+ ENTRY *res = NULL;
+
+ ret = 0;
+ create_key_string(elem, &fmt);
+
+ item.key = elem->type;
+ if (hsearch_r(item, FIND, &res, types_htable)) {
+ memcpy(&int_data, elem->field_data,
+ ((struct type_info *)res->data)->size);
+ lv_str = NULL;
+ if (!strcmp(elem->type, "int64"))
+ ret = asprintf(&lv_str, "%ld", int_data);
+ else if (!strcmp(elem->type, "uint64"))
+ ret = asprintf(&lv_str, "%lu", int_data);
+
+ if (ret < 0)
+ goto done;
+
+ if (lv_str != NULL)
+ xo_emit_h(xop, fmt, lv_str);
+ else
+ xo_emit_h(xop, fmt, int_data);
+ } else {
+ ds = elem->data_size;
+ enc_data = malloc(4 * (ds + 2) / 3);
+ assert(enc_data != NULL);
+
+ enc_bytes = EVP_EncodeBlock(enc_data, (const char *)elem->field_data, ds);
+ assert(enc_bytes != 0);
+
+ xo_emit_h(xop, fmt, enc_data);
+
+ free(enc_data);
+ }
+
+done:
+ free(fmt);
+ return (ret);
+}
+
+
+static int
+vm_snapshot_dev_intern_arr_index(xo_handle_t *xop, int ident, int index,
+ struct vm_snapshot_device_info **curr_el)
+{
+ char *intern_arr = NULL;
+ char *indexed_name = NULL;
+ int ret = 0;
+
+ intern_arr = (*curr_el)->intern_arr_name;
+
+ create_indexed_arr_name(intern_arr, index, &indexed_name);
+ xo_open_list_h(xop, indexed_name);
+
+ xo_open_instance_h(xop, indexed_name);
+ while (*curr_el != NULL) {
+ /* Check if there is an internal array */
+ if ((*curr_el)->ident > ident) {
+ ret = vm_snapshot_dev_intern_arr(xop, (*curr_el)->ident, (*curr_el)->index, curr_el);
+ continue;
+ }
+
+ /* Check if index changed and if there is no array at the same
+ * indentation level as the current one for this index */
+ if ((index != (*curr_el)->index) && (ret == 0))
+ break;
+
+ /* Reset the return value for the first branch inside the loop */
+ ret = 0;
+
+ /* Write data */
+ emit_data(xop, *curr_el);
+
+ *curr_el = (*curr_el)->next_field;
+ }
+
+ xo_close_instance_h(xop, indexed_name);
+ xo_close_list_h(xop, indexed_name);
+ free(indexed_name);
+ indexed_name = NULL;
+
+ return (ret);
+}
+
+static int
+vm_snapshot_dev_intern_arr(xo_handle_t *xop, int ident, int index,
+ struct vm_snapshot_device_info **curr_el)
+{
+ char *intern_arr = NULL;
+ int ret = 0;
+
+ intern_arr = (*curr_el)->intern_arr_name;
+ xo_open_list_h(xop, intern_arr);
+
+ xo_open_instance_h(xop, intern_arr);
+ while (*curr_el != NULL) {
+ /* Check if the current array has no more elements */
+ if ((*curr_el)->ident < ident)
+ break;
+
+ /* Check if there is an array on the same indentation level */
+ if (strcmp((*curr_el)->intern_arr_name, intern_arr) &&
+ (*curr_el)->ident == ident &&
+ ret == 0) {
+ ret = 1;
+ break;
+ }
+
+ /* Check if there is an internal array */
+ if ((*curr_el)->ident > ident) {
+ ret = vm_snapshot_dev_intern_arr(xop, (*curr_el)->ident, (*curr_el)->index, curr_el);
+ continue;
+ }
+
+ /* Check if for the current array indexing is present */
+ if (((*curr_el)->index != -1) && ((*curr_el)->create_instance == 1)) {
+ vm_snapshot_dev_intern_arr_index(xop, (*curr_el)->ident, (*curr_el)->index, curr_el);
+ continue;
+ }
+
+ ret = 0;
+ /* Write data inside the array */
+ emit_data(xop, *curr_el);
+
+ *curr_el = (*curr_el)->next_field;
+ }
+ xo_close_instance_h(xop, intern_arr);
+ xo_close_list_h(xop, intern_arr);
+
+ return (ret);
+}
+
+static void
+write_param_array(struct vm_snapshot_meta *meta, xo_handle_t *xop)
+{
+ struct vm_snapshot_device_info *curr_el;
+
+ curr_el = meta->dev_info_list.first;
+ meta->dev_info_list.ident = 0;
+
+ xo_open_list_h(xop, JSON_PARAMS_KEY);
+ xo_open_instance_h(xop, JSON_PARAMS_KEY);
+ while (curr_el != NULL) {
+ if (curr_el->ident > meta->dev_info_list.ident) {
+ vm_snapshot_dev_intern_arr(xop, curr_el->ident, curr_el->index, &curr_el);
+ continue;
+ }
+
+ emit_data(xop, curr_el);
+
+ curr_el = curr_el->next_field;
+ }
+ xo_close_instance_h(xop, JSON_PARAMS_KEY);
+ xo_close_list_h(xop, JSON_PARAMS_KEY);
+}
+
+#endif
+
static int
vm_snapshot_dev_write_data(int data_fd, xo_handle_t *xop, const char *array_key,
struct vm_snapshot_meta *meta, off_t *offset)
@@ -1140,23 +2182,26 @@
int ret;
size_t data_size;
- data_size = vm_get_snapshot_size(meta);
-
- ret = write(data_fd, meta->buffer.buf_start, data_size);
- if (ret != data_size) {
- perror("Failed to write all snapshotted data.");
- return (-1);
+ if (meta->version == JSON_V1) {
+ data_size = vm_get_snapshot_size(meta);
+ ret = write(data_fd, meta->buffer.buf_start, data_size);
+ if (ret != data_size) {
+ perror("Failed to write all snapshotted data.");
+ return (-1);
+ }
+ *offset += data_size;
}
-
+
/* Write metadata. */
xo_open_instance_h(xop, array_key);
xo_emit_h(xop, "{:" JSON_SNAPSHOT_REQ_KEY "/%s}\n", meta->dev_name);
- xo_emit_h(xop, "{:" JSON_SIZE_KEY "/%lu}\n", data_size);
- xo_emit_h(xop, "{:" JSON_FILE_OFFSET_KEY "/%lu}\n", *offset);
- xo_close_instance_h(xop, array_key);
-
- *offset += data_size;
+ if (meta->version == JSON_V1) {
+ xo_emit_h(xop, "{:" JSON_SIZE_KEY "/%lu}\n", data_size);
+ xo_emit_h(xop, "{:" JSON_FILE_OFFSET_KEY "/%lu}\n", *offset);
+ } else if (meta->version == JSON_V2)
+ write_param_array(meta, xop);
+ xo_close_instance_h(xop, array_key);
return (0);
}
@@ -1174,6 +2219,10 @@
return (ret);
}
+ if (meta->version == JSON_V2)
+ if (meta->dev_info_list.first == NULL)
+ return (0);
+
ret = vm_snapshot_dev_write_data(data_fd, xop, JSON_DEV_ARR_KEY, meta,
offset);
if (ret != 0)
@@ -1186,11 +2235,16 @@
vm_snapshot_user_devs(struct vmctx *ctx, int data_fd, xo_handle_t *xop)
{
int ret, i;
+
off_t offset;
+#ifndef JSON_SNAPSHOT_V2
void *buffer;
size_t buf_size;
+#endif
+
struct vm_snapshot_meta *meta;
+#ifndef JSON_SNAPSHOT_V2
buf_size = SNAPSHOT_BUFFER_SIZE;
offset = lseek(data_fd, 0, SEEK_CUR);
@@ -1205,25 +2259,49 @@
ret = ENOSPC;
goto snapshot_err;
}
-
+#endif
+ offset = 0;
meta = &(struct vm_snapshot_meta) {
.ctx = ctx,
+ .op = VM_SNAPSHOT_SAVE,
+
+#ifndef JSON_SNAPSHOT_V2
.buffer.buf_start = buffer,
.buffer.buf_size = buf_size,
-
- .op = VM_SNAPSHOT_SAVE,
+ .version = JSON_V1,
+#else
+ .version = JSON_V2,
+ .dev_info_list.ident = 0,
+ .dev_info_list.index = -1,
+ .dev_info_list.create_instance = 1,
+ .dev_info_list.auto_index = -1,
+ .dev_info_list.first = NULL,
+ .dev_info_list.last = NULL,
+#endif
};
+ /* Prepare the hashtable for types */
+ ret = create_types_hashtable();
+ if (ret != 0)
+ goto snapshot_err;
+
xo_open_list_h(xop, JSON_DEV_ARR_KEY);
/* Restore other devices that support this feature */
for (i = 0; i < nitems(snapshot_devs); i++) {
+ fprintf(stderr, "Creating snapshot for %s device\r\n", snapshot_devs[i].dev_name);
meta->dev_name = snapshot_devs[i].dev_name;
- memset(meta->buffer.buf_start, 0, meta->buffer.buf_size);
- meta->buffer.buf = meta->buffer.buf_start;
- meta->buffer.buf_rem = meta->buffer.buf_size;
+ if (meta->version == JSON_V1) {
+ memset(meta->buffer.buf_start, 0, meta->buffer.buf_size);
+ meta->buffer.buf = meta->buffer.buf_start;
+ meta->buffer.buf_rem = meta->buffer.buf_size;
+ } else if (meta->version == JSON_V2)
+ free_device_info_list(&meta->dev_info_list);
+
+ if (meta->version == JSON_V2)
+ free_device_info_list(&meta->dev_info_list);
ret = vm_snapshot_user_dev(&snapshot_devs[i], data_fd, xop,
meta, &offset);
@@ -1233,9 +2311,15 @@
xo_close_list_h(xop, JSON_DEV_ARR_KEY);
+ /* Clear types hashtable */
+ destroy_types_hashtable();
+
snapshot_err:
+#ifndef JSON_SNAPSHOT_V2
if (buffer != NULL)
free(buffer);
+#endif
+
return (ret);
}
@@ -1319,9 +2403,12 @@
size_t memsz;
xo_handle_t *xop = NULL;
char *meta_filename = NULL;
+#ifndef JSON_SNAPSHOT_V2
char *kdata_filename = NULL;
+#endif
FILE *meta_file = NULL;
+#ifndef JSON_SNAPSHOT_V2
kdata_filename = strcat_extension(checkpoint_file, ".kern");
if (kdata_filename == NULL) {
fprintf(stderr, "Failed to construct kernel data filename.\n");
@@ -1334,7 +2421,7 @@
error = -1;
goto done;
}
-
+#endif
fd_checkpoint = open(checkpoint_file, O_RDWR | O_CREAT | O_TRUNC, 0700);
if (fd_checkpoint < 0) {
@@ -1384,7 +2471,6 @@
goto done;
}
-
ret = vm_snapshot_kern_structs(ctx, kdata_fd, xop);
if (ret != 0) {
fprintf(stderr, "Failed to snapshot vm kernel data.\n");
@@ -1415,8 +2501,10 @@
close(fd_checkpoint);
if (meta_filename != NULL)
free(meta_filename);
+#ifndef JSON_SNAPSHOT_V2
if (kdata_filename != NULL)
free(kdata_filename);
+#endif
if (xop != NULL)
xo_destroy(xop);
if (meta_file != NULL)
@@ -1563,6 +2651,222 @@
return (err);
}
+#define BUFFER_SUB_REM(buffer, size) \
+do { \
+ buffer->buf += (size); \
+ buffer->buf_rem -= (size); \
+} while(0)
+
+#define CHK_SIZE_AND_ADD_ELEM(list, buffer, data_size, field_name, type, RET, LABEL) \
+do { \
+ int32_t ds; \
+ void *kdata = NULL; \
+ \
+ memcpy((uint8_t *) &ds, (buffer)->buf, sizeof(int32_t)); \
+ if (ds != data_size) { \
+ fprintf(stderr, \
+ "%s: Size mismatch for parameter %s, expected %d but got %ld\r\n", \
+ __func__, field_name, ds, data_size); \
+ (RET) = -1; \
+ goto LABEL; \
+ } \
+ BUFFER_SUB_REM(buffer, sizeof(int32_t)); \
+ kdata = calloc(1, data_size); \
+ if (kdata == NULL) { \
+ fprintf(stderr, "%s: Could not alloc memory at line %d\r\n", \
+ __func__, __LINE__); \
+ (RET) = ENOMEM; \
+ goto LABEL; \
+ } \
+ memcpy((uint8_t *) kdata, (buffer)->buf, data_size); \
+ \
+ alloc_device_info_elem(list, field_name, kdata, type, data_size); \
+ \
+ BUFFER_SUB_REM(buffer, data_size); \
+ free(kdata); \
+} while(0)
+
+#define ADD_SIZE_AND_DATA_TO_BUFFER(buffer, data_size, field_data) \
+do { \
+ memcpy(buffer->buf, (uint8_t *)&data_size, sizeof(int32_t)); \
+ BUFFER_SUB_REM(buffer, sizeof(int32_t)); \
+ memcpy(buffer->buf, (field_data), data_size); \
+ BUFFER_SUB_REM(buffer, data_size); \
+} while(0)
+
+int
+vm_snapshot_save_fieldname(const char *fullname, volatile void *data,
+ char *type, size_t data_size, struct vm_snapshot_meta *meta)
+{
+ int ret;
+ size_t len;
+ char *ffield_name;
+ char *aux;
+ char *field_name;
+ int op;
+ struct vm_snapshot_buffer *buffer;
+ struct list_device_info *list;
+ struct vm_snapshot_device_info *aux_elem;
+ const char delim[5] = "&(>)";
+
+ buffer = &meta->buffer;
+ if (meta->snapshot_kernel)
+ if (buffer->buf_rem < data_size + sizeof(int)) {
+ fprintf(stderr, "%s: buffer too small\r\n", __func__);
+ return (E2BIG);
+ }
+
+ ret = 0;
+ op = meta->op;
+
+ len = strlen(fullname);
+ ffield_name = calloc(len + 1, sizeof(char));
+ assert(ffield_name != NULL);
+
+ memcpy(ffield_name, fullname, len);
+ aux = strtok(ffield_name, delim);
+ field_name = strtok(NULL, delim);
+
+ if (field_name == NULL)
+ field_name = aux;
+
+ list = &meta->dev_info_list;
+ if (op == VM_SNAPSHOT_SAVE) {
+ if (meta->snapshot_kernel)
+ CHK_SIZE_AND_ADD_ELEM(list, buffer, data_size, field_name, type, ret, done);
+ else
+ alloc_device_info_elem(list, field_name, data, type, data_size);
+
+ if (list->auto_index >= 0)
+ list->auto_index++;
+ } else if (op == VM_SNAPSHOT_RESTORE) {
+ aux_elem = list->first;
+ if (aux_elem != NULL) {
+ if (meta->snapshot_kernel) {
+ ADD_SIZE_AND_DATA_TO_BUFFER(buffer, data_size,
+ (uint8_t *) aux_elem->field_data);
+ } else
+ memcpy((uint8_t *)data, (uint8_t *)aux_elem->field_data, data_size);
+ }
+ remove_first_elem(list);
+ } else {
+ ret = EINVAL;
+ goto done;
+ }
+
+done:
+ free(ffield_name);
+ return (ret);
+}
+
+int
+vm_snapshot_save_fieldname_cmp(const char *fullname, volatile void *data,
+ char *type, size_t data_size, struct vm_snapshot_meta *meta)
+{
+ size_t len;
+ char *ffield_name;
+ char *aux;
+ char *field_name;
+ int op;
+ int ret;
+ struct vm_snapshot_buffer *buffer;
+ struct list_device_info *list;
+ struct vm_snapshot_device_info *aux_elem;
+ const char delim[5] = "&(>)";
+
+ buffer = &meta->buffer;
+ if (meta->snapshot_kernel)
+ if (buffer->buf_rem < data_size + sizeof(int32_t)) {
+ fprintf(stderr, "%s: buffer too small\r\n", __func__);
+ return (E2BIG);
+ }
+
+ op = meta->op;
+
+ len = strlen(fullname);
+ ffield_name = calloc(len + 1, sizeof(char));
+ assert(ffield_name != NULL);
+
+ memcpy(ffield_name, fullname, len);
+ aux = strtok(ffield_name, delim);
+ field_name = strtok(NULL, delim);
+
+ if (field_name == NULL)
+ field_name = aux;
+
+ list = &meta->dev_info_list;
+ if (op == VM_SNAPSHOT_SAVE) {
+ ret = 0;
+ if (meta->snapshot_kernel)
+ CHK_SIZE_AND_ADD_ELEM(list, buffer, data_size, field_name, type, ret, done);
+ else
+ alloc_device_info_elem(list, field_name, data, type, data_size);
+
+ if (list->auto_index >= 0)
+ list->auto_index++;
+ } else if (op == VM_SNAPSHOT_RESTORE) {
+ aux_elem = list->first;
+ if (aux_elem != NULL) {
+ if (meta->snapshot_kernel) {
+ ADD_SIZE_AND_DATA_TO_BUFFER(buffer, data_size,
+ (uint8_t *) aux_elem->field_data);
+ } else
+ ret = memcmp((uint8_t *)data, (uint8_t *)aux_elem->field_data, data_size);
+ }
+ remove_first_elem(list);
+ } else {
+ ret = EINVAL;
+ goto done;
+ }
+
+done:
+ free(ffield_name);
+ return (ret);
+}
+
+void
+vm_snapshot_add_intern_list(const char *arr_name, struct vm_snapshot_meta *meta)
+{
+ meta->dev_info_list.intern_arr_names[meta->dev_info_list.ident++] = arr_name;
+}
+
+void
+vm_snapshot_remove_intern_list(struct vm_snapshot_meta *meta)
+{
+ meta->dev_info_list.intern_arr_names[--meta->dev_info_list.ident] = NULL;
+}
+
+void
+vm_snapshot_set_intern_arr_index(struct vm_snapshot_meta *meta, int index)
+{
+ meta->dev_info_list.index = index;
+}
+
+void
+vm_snapshot_clear_intern_arr_index(struct vm_snapshot_meta *meta)
+{
+ meta->dev_info_list.index = -1;
+}
+
+void vm_snapshot_activate_auto_index(struct vm_snapshot_meta *meta,
+ unsigned char create_instance)
+{
+ meta->dev_info_list.create_instance = create_instance;
+ meta->dev_info_list.auto_index = 0;
+}
+
+void vm_snapshot_deactivate_auto_index(struct vm_snapshot_meta *meta)
+{
+ meta->dev_info_list.create_instance = 1;
+ meta->dev_info_list.auto_index = -1;
+}
+
+void check_and_set_non_array_type(char *type, struct vm_snapshot_meta *meta)
+{
+ if ((type != NULL) && strcmp(type, "b64"))
+ meta->dev_info_list.type = type;
+}
+
void
vm_snapshot_buf_err(const char *bufname, const enum vm_snapshot_op op)
{
@@ -1601,8 +2905,7 @@
else
return (EINVAL);
- buffer->buf += data_size;
- buffer->buf_rem -= data_size;
+ BUFFER_SUB_REM(buffer, data_size);
return (0);
}
@@ -1689,8 +2992,7 @@
goto done;
}
- buffer->buf += data_size;
- buffer->buf_rem -= data_size;
+ BUFFER_SUB_REM(buffer, data_size);
done:
return (ret);
Index: usr.sbin/bhyve/uart_emul.c
===================================================================
--- usr.sbin/bhyve/uart_emul.c
+++ usr.sbin/bhyve/uart_emul.c
@@ -39,6 +39,8 @@
#include <capsicum_helpers.h>
#endif
+#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
#include <stdio.h>
Index: usr.sbin/bhyve/usb_mouse.c
===================================================================
--- usr.sbin/bhyve/usb_mouse.c
+++ usr.sbin/bhyve/usb_mouse.c
@@ -31,6 +31,8 @@
#include <sys/time.h>
+#include <machine/vmm.h>
+#include <vmmapi.h>
#include <machine/vmm_snapshot.h>
#include <pthread.h>
Index: usr.sbin/bhyve/virtio.c
===================================================================
--- usr.sbin/bhyve/virtio.c
+++ usr.sbin/bhyve/virtio.c
@@ -890,6 +890,9 @@
for (i = 0; i < vc->vc_nvq; i++) {
vq = &vs->vs_queues[i];
+ /* Set index */
+ SNAPSHOT_SET_INTERN_ARR_INDEX(meta, i);
+
SNAPSHOT_VAR_CMP_OR_LEAVE(vq->vq_qsize, meta, ret, done);
SNAPSHOT_VAR_CMP_OR_LEAVE(vq->vq_num, meta, ret, done);
@@ -904,6 +907,9 @@
if (!vq_ring_ready(vq))
continue;
+ SNAPSHOT_ADD_INTERN_ARR(h2g_addrs, meta);
+ SNAPSHOT_ACTIVATE_AUTO_INDEXING(meta, 0);
+
addr_size = vq->vq_qsize * sizeof(struct vring_desc);
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_desc, addr_size,
false, meta, ret, done);
@@ -916,10 +922,16 @@
SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_used, addr_size,
false, meta, ret, done);
- SNAPSHOT_BUF_OR_LEAVE(vq->vq_desc,
- vring_size_aligned(vq->vq_qsize), meta, ret, done);
+ SNAPSHOT_DEACTIVATE_AUTO_INDEXING(meta);
+ SNAPSHOT_REMOVE_INTERN_ARR(h2g_addrs, meta);
+
+ SNAPSHOT_BUF_OR_LEAVE(vq->vq_desc, vring_size_aligned(vq->vq_qsize),
+ meta, ret, done);
}
+ /* Reset index */
+ SNAPSHOT_CLEAR_INTERN_ARR_INDEX(meta);
+
done:
return (ret);
}
@@ -937,19 +949,25 @@
vc = vs->vs_vc;
/* Save virtio softc */
+ SNAPSHOT_ADD_INTERN_ARR(softc, meta);
ret = vi_pci_snapshot_softc(vs, meta);
if (ret != 0)
goto done;
+ SNAPSHOT_REMOVE_INTERN_ARR(softc, meta);
/* Save virtio consts */
+ SNAPSHOT_ADD_INTERN_ARR(consts, meta);
ret = vi_pci_snapshot_consts(vc, meta);
if (ret != 0)
goto done;
+ SNAPSHOT_REMOVE_INTERN_ARR(consts, meta);
/* Save virtio queue info */
+ SNAPSHOT_ADD_INTERN_ARR(queues, meta);
ret = vi_pci_snapshot_queues(vs, meta);
if (ret != 0)
goto done;
+ SNAPSHOT_REMOVE_INTERN_ARR(queues, meta);
/* Save device softc, if needed */
if (vc->vc_snapshot != NULL) {

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 31, 10:08 AM (1 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30598030
Default Alt Text
D29262.diff (95 KB)

Event Timeline