diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -265,7 +265,7 @@ /* * Save and restore */ -int vm_snapshot_req(struct vm_snapshot_meta *meta); +int vm_snapshot_req(struct vmctx *ctx, struct vm_snapshot_meta *meta); int vm_restore_time(struct vmctx *ctx); /* diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -1712,10 +1712,10 @@ } int -vm_snapshot_req(struct vm_snapshot_meta *meta) +vm_snapshot_req(struct vmctx *ctx, struct vm_snapshot_meta *meta) { - if (ioctl(meta->ctx->fd, VM_SNAPSHOT_REQ, meta) == -1) { + if (ioctl(ctx->fd, VM_SNAPSHOT_REQ, meta) == -1) { #ifdef SNAPSHOT_DEBUG fprintf(stderr, "%s: snapshot failed for %s: %d\r\n", __func__, meta->dev_name, errno); diff --git a/sys/amd64/include/vmm_snapshot.h b/sys/amd64/include/vmm_snapshot.h --- a/sys/amd64/include/vmm_snapshot.h +++ b/sys/amd64/include/vmm_snapshot.h @@ -44,8 +44,6 @@ #include #endif -struct vmctx; - enum snapshot_req { STRUCT_VIOAPIC = 1, STRUCT_VM, @@ -89,7 +87,6 @@ }; struct vm_snapshot_meta { - struct vmctx *ctx; void *dev_data; const char *dev_name; /* identify userspace devices */ enum snapshot_req dev_req; /* identify kernel structs */ @@ -103,8 +100,6 @@ int vm_snapshot_buf(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(void *data, size_t data_size, struct vm_snapshot_meta *meta); @@ -120,24 +115,6 @@ #define SNAPSHOT_VAR_OR_LEAVE(DATA, META, RES, LABEL) \ SNAPSHOT_BUF_OR_LEAVE(&(DATA), sizeof(DATA), (META), (RES), LABEL) -/* - * Address variables are pointers to guest memory. - * - * When RNULL != 0, do not enforce invalid address checks; instead, make the - * 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; \ - } \ -} while (0) - /* compare the value in the meta buffer with the data */ #define SNAPSHOT_BUF_CMP_OR_LEAVE(DATA, LEN, META, RES, LABEL) \ do { \ diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -79,6 +79,20 @@ #define VM_STATS_OLD \ _IOWR('v', IOCNUM_VM_STATS, struct vm_stats_old) + +struct vm_snapshot_meta_old { + void *ctx; /* unused */ + void *dev_data; + const char *dev_name; /* identify userspace devices */ + enum snapshot_req dev_req; /* identify kernel structs */ + + struct vm_snapshot_buffer buffer; + + enum vm_snapshot_op op; +}; + +#define VM_SNAPSHOT_REQ_OLD \ + _IOWR('v', IOCNUM_SNAPSHOT_REQ, struct vm_snapshot_meta_old) #endif struct devmem_softc { @@ -416,6 +430,9 @@ bool memsegs_locked; #ifdef BHYVE_SNAPSHOT struct vm_snapshot_meta *snapshot_meta; +#ifdef COMPAT_FREEBSD13 + struct vm_snapshot_meta_old *snapshot_old; +#endif #endif error = vmm_priv_check(curthread->td_ucred); @@ -495,6 +512,9 @@ case VM_UNMAP_PPTDEV_MMIO: #ifdef BHYVE_SNAPSHOT case VM_SNAPSHOT_REQ: +#ifdef COMPAT_FREEBSD13 + case VM_SNAPSHOT_REQ_OLD: +#endif case VM_RESTORE_TIME: #endif /* @@ -951,6 +971,18 @@ snapshot_meta = (struct vm_snapshot_meta *)data; error = vm_snapshot_req(sc->vm, snapshot_meta); break; +#ifdef COMPAT_FREEBSD13 + case VM_SNAPSHOT_REQ_OLD: + /* + * The old structure just has an additional pointer at + * the start that is ignored. + */ + snapshot_old = (struct vm_snapshot_meta_old *)data; + snapshot_meta = + (struct vm_snapshot_meta *)&snapshot_old->dev_data; + error = vm_snapshot_req(sc->vm, snapshot_meta); + break; +#endif case VM_RESTORE_TIME: error = vm_restore_time(sc->vm); break; diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -1534,7 +1534,7 @@ } fprintf(stdout, "Restoring pci devs...\r\n"); - if (vm_restore_user_devs(ctx, &rstate) != 0) { + if (vm_restore_user_devs(&rstate) != 0) { fprintf(stderr, "Failed to restore PCI device state.\n"); exit(1); } diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -41,8 +41,6 @@ #include #include -#include - #include #include #include @@ -61,6 +59,9 @@ #include "config.h" #include "debug.h" #include "pci_emul.h" +#ifdef BHYVE_SNAPSHOT +#include "snapshot.h" +#endif #include "ahci.h" #include "block_if.h" @@ -2623,10 +2624,10 @@ goto done; } - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(port->cmd_lst, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, 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_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, port->rfis, 256, + false, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(port->ata_ident, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(port->atapi, meta, ret, done); diff --git a/usr.sbin/bhyve/pci_e82545.c b/usr.sbin/bhyve/pci_e82545.c --- a/usr.sbin/bhyve/pci_e82545.c +++ b/usr.sbin/bhyve/pci_e82545.c @@ -46,7 +46,6 @@ #ifndef WITHOUT_CAPSICUM #include #endif -#include #include #include @@ -68,6 +67,9 @@ #include "config.h" #include "debug.h" #include "pci_emul.h" +#ifdef BHYVE_SNAPSHOT +#include "snapshot.h" +#endif #include "mevent.h" #include "net_utils.h" #include "net_backends.h" @@ -2436,8 +2438,8 @@ SNAPSHOT_VAR_OR_LEAVE(sc->esc_TADV, meta, ret, done); /* Has dependency on esc_TDLEN; reoreder of fields from struct. */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->esc_txdesc, sc->esc_TDLEN, - true, meta, ret, done); + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_txdesc, + sc->esc_TDLEN, true, meta, ret, done); /* L2 frame acceptance */ for (i = 0; i < (int)nitems(sc->esc_uni); i++) { @@ -2471,8 +2473,8 @@ SNAPSHOT_VAR_OR_LEAVE(sc->esc_RXCSUM, meta, ret, done); /* Has dependency on esc_RDLEN; reoreder of fields from struct. */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->esc_rxdesc, sc->esc_TDLEN, - true, meta, ret, done); + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->esc_rxdesc, + sc->esc_TDLEN, true, meta, ret, done); /* IO Port register access */ SNAPSHOT_VAR_OR_LEAVE(sc->io_addr, meta, ret, done); diff --git a/usr.sbin/bhyve/pci_xhci.c b/usr.sbin/bhyve/pci_xhci.c --- a/usr.sbin/bhyve/pci_xhci.c +++ b/usr.sbin/bhyve/pci_xhci.c @@ -48,8 +48,6 @@ #include #include -#include - #include #include #include @@ -60,6 +58,9 @@ #include "debug.h" #include "pci_emul.h" #include "pci_xhci.h" +#ifdef BHYVE_SNAPSHOT +#include "snapshot.h" +#endif #include "usb_emul.h" @@ -2965,8 +2966,8 @@ } static int -pci_xhci_snapshot_ep(struct pci_xhci_softc *sc __unused, - struct pci_xhci_dev_emu *dev, int idx, struct vm_snapshot_meta *meta) +pci_xhci_snapshot_ep(struct pci_xhci_softc *sc, struct pci_xhci_dev_emu *dev, + int idx, struct vm_snapshot_meta *meta) { int k; int ret; @@ -2992,9 +2993,9 @@ for (k = 0; k < USB_MAX_XFER_BLOCKS; k++) { xfer_block = &xfer->data[k]; - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(xfer_block->buf, - XHCI_GADDR_SIZE(xfer_block->buf), true, meta, ret, - done); + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->xsc_pi->pi_vmctx, + xfer_block->buf, XHCI_GADDR_SIZE(xfer_block->buf), true, + meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(xfer_block->blen, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(xfer_block->bdone, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(xfer_block->processed, meta, ret, done); @@ -3059,11 +3060,11 @@ SNAPSHOT_VAR_OR_LEAVE(sc->opregs.config, meta, ret, done); /* opregs.cr_p */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->opregs.cr_p, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->opregs.cr_p, XHCI_GADDR_SIZE(sc->opregs.cr_p), true, meta, ret, done); /* opregs.dcbaa_p */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->opregs.dcbaa_p, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->opregs.dcbaa_p, XHCI_GADDR_SIZE(sc->opregs.dcbaa_p), true, meta, ret, done); /* rtsregs */ @@ -3078,11 +3079,11 @@ SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.intrreg.erdp, meta, ret, done); /* rtsregs.erstba_p */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->rtsregs.erstba_p, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->rtsregs.erstba_p, XHCI_GADDR_SIZE(sc->rtsregs.erstba_p), true, meta, ret, done); /* rtsregs.erst_p */ - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(sc->rtsregs.erst_p, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, sc->rtsregs.erst_p, XHCI_GADDR_SIZE(sc->rtsregs.erst_p), true, meta, ret, done); SNAPSHOT_VAR_OR_LEAVE(sc->rtsregs.er_deq_seg, meta, ret, done); @@ -3168,7 +3169,7 @@ if (dev == NULL) continue; - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(dev->dev_ctx, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(pi->pi_vmctx, dev->dev_ctx, XHCI_GADDR_SIZE(dev->dev_ctx), true, meta, ret, done); if (dev->dev_ctx != NULL) { diff --git a/usr.sbin/bhyve/snapshot.h b/usr.sbin/bhyve/snapshot.h --- a/usr.sbin/bhyve/snapshot.h +++ b/usr.sbin/bhyve/snapshot.h @@ -95,7 +95,7 @@ int restore_vm_mem(struct vmctx *ctx, struct restore_state *rstate); int vm_restore_kern_structs(struct vmctx *ctx, struct restore_state *rstate); -int vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate); +int vm_restore_user_devs(struct restore_state *rstate); int vm_pause_user_devs(void); int vm_resume_user_devs(void); @@ -106,4 +106,25 @@ int load_restore_file(const char *filename, struct restore_state *rstate); +int vm_snapshot_guest2host_addr(struct vmctx *ctx, void **addrp, size_t len, + bool restore_null, struct vm_snapshot_meta *meta); + +/* + * Address variables are pointers to guest memory. + * + * When RNULL != 0, do not enforce invalid address checks; instead, make the + * pointer NULL at restore time. + */ +#define SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(CTX, ADDR, LEN, RNULL, META, RES, LABEL) \ +do { \ + (RES) = vm_snapshot_guest2host_addr((CTX), (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) + #endif diff --git a/usr.sbin/bhyve/snapshot.c b/usr.sbin/bhyve/snapshot.c --- a/usr.sbin/bhyve/snapshot.c +++ b/usr.sbin/bhyve/snapshot.c @@ -886,7 +886,6 @@ } meta = &(struct vm_snapshot_meta) { - .ctx = ctx, .dev_name = info->struct_name, .dev_req = info->req, @@ -899,7 +898,7 @@ .op = VM_SNAPSHOT_RESTORE, }; - ret = vm_snapshot_req(meta); + ret = vm_snapshot_req(ctx, meta); if (ret != 0) { fprintf(stderr, "%s: Failed to restore struct: %s\r\n", __func__, info->struct_name); @@ -927,7 +926,7 @@ } static int -vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate, +vm_restore_user_dev(struct restore_state *rstate, const struct vm_snapshot_dev_info *info) { void *dev_ptr; @@ -950,7 +949,6 @@ } meta = &(struct vm_snapshot_meta) { - .ctx = ctx, .dev_name = info->dev_name, .buffer.buf_start = dev_ptr, @@ -974,13 +972,13 @@ int -vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate) +vm_restore_user_devs(struct restore_state *rstate) { size_t i; int ret; for (i = 0; i < nitems(snapshot_devs); i++) { - ret = vm_restore_user_dev(ctx, rstate, &snapshot_devs[i]); + ret = vm_restore_user_dev(rstate, &snapshot_devs[i]); if (ret != 0) return (ret); } @@ -1029,14 +1027,14 @@ } static int -vm_snapshot_kern_struct(int data_fd, xo_handle_t *xop, const char *array_key, - struct vm_snapshot_meta *meta, off_t *offset) +vm_snapshot_kern_struct(struct vmctx *ctx, int data_fd, xo_handle_t *xop, + const char *array_key, struct vm_snapshot_meta *meta, off_t *offset) { int ret; size_t data_size; ssize_t write_cnt; - ret = vm_snapshot_req(meta); + ret = vm_snapshot_req(ctx, meta); if (ret != 0) { fprintf(stderr, "%s: Failed to snapshot struct %s\r\n", __func__, meta->dev_name); @@ -1089,8 +1087,6 @@ } meta = &(struct vm_snapshot_meta) { - .ctx = ctx, - .buffer.buf_start = buffer, .buffer.buf_size = buf_size, @@ -1106,8 +1102,8 @@ 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); + ret = vm_snapshot_kern_struct(ctx, data_fd, xop, + JSON_DEV_ARR_KEY, meta, &offset); if (ret != 0) { error = -1; goto err_vm_snapshot_kern_data; @@ -1186,7 +1182,7 @@ } static int -vm_snapshot_user_devs(struct vmctx *ctx, int data_fd, xo_handle_t *xop) +vm_snapshot_user_devs(int data_fd, xo_handle_t *xop) { int ret; off_t offset; @@ -1210,8 +1206,6 @@ } meta = &(struct vm_snapshot_meta) { - .ctx = ctx, - .buffer.buf_start = buffer, .buffer.buf_size = buf_size, @@ -1395,7 +1389,7 @@ goto done; } - ret = vm_snapshot_user_devs(ctx, kdata_fd, xop); + ret = vm_snapshot_user_devs(kdata_fd, xop); if (ret != 0) { fprintf(stderr, "Failed to snapshot device state.\n"); error = -1; @@ -1639,14 +1633,14 @@ } int -vm_snapshot_guest2host_addr(void **addrp, size_t len, bool restore_null, - struct vm_snapshot_meta *meta) +vm_snapshot_guest2host_addr(struct vmctx *ctx, void **addrp, size_t len, + bool restore_null, struct vm_snapshot_meta *meta) { int ret; vm_paddr_t gaddr; if (meta->op == VM_SNAPSHOT_SAVE) { - gaddr = paddr_host2guest(meta->ctx, *addrp); + gaddr = paddr_host2guest(ctx, *addrp); if (gaddr == (vm_paddr_t) -1) { if (!restore_null || (restore_null && (*addrp != NULL))) { @@ -1665,7 +1659,7 @@ } } - *addrp = paddr_guest2host(meta->ctx, gaddr, len); + *addrp = paddr_guest2host(ctx, gaddr, len); } else { ret = EINVAL; } diff --git a/usr.sbin/bhyve/virtio.c b/usr.sbin/bhyve/virtio.c --- a/usr.sbin/bhyve/virtio.c +++ b/usr.sbin/bhyve/virtio.c @@ -34,7 +34,6 @@ #include #include -#include #include @@ -47,6 +46,9 @@ #include "bhyverun.h" #include "debug.h" #include "pci_emul.h" +#ifdef BHYVE_SNAPSHOT +#include "snapshot.h" +#endif #include "virtio.h" /* @@ -880,8 +882,10 @@ int ret; struct virtio_consts *vc; struct vqueue_info *vq; + struct vmctx *ctx; uint64_t addr_size; + ctx = vs->vs_pi->pi_vmctx; vc = vs->vs_vc; /* Save virtio queue info */ @@ -903,15 +907,15 @@ continue; addr_size = vq->vq_qsize * sizeof(struct vring_desc); - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_desc, addr_size, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_desc, addr_size, false, meta, ret, done); addr_size = (2 + vq->vq_qsize + 1) * sizeof(uint16_t); - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_avail, addr_size, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_avail, addr_size, false, meta, ret, done); addr_size = (2 + 2 * vq->vq_qsize + 1) * sizeof(uint16_t); - SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(vq->vq_used, addr_size, + SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_used, addr_size, false, meta, ret, done); SNAPSHOT_BUF_OR_LEAVE(vq->vq_desc,