static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) { VirtIOSerial *s = opaque; VirtIOSerialPort *port; uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; int ret; if (version_id > 3) { return -EINVAL; } /* The virtio device */ ret = virtio_load(&s->vdev, f); if (ret) { return ret; } if (version_id < 2) { return 0; } /* The config space */ qemu_get_be16s(f, &s->config.cols); qemu_get_be16s(f, &s->config.rows); qemu_get_be32s(f, &max_nr_ports); tswap32s(&max_nr_ports); if (max_nr_ports > tswap32(s->config.max_nr_ports)) { /* Source could have had more ports than us. Fail migration. */ return -EINVAL; } for (i = 0; i < (max_nr_ports + 31) / 32; i++) { qemu_get_be32s(f, &ports_map); if (ports_map != s->ports_map[i]) { /* * Ports active on source and destination don't * match. Fail migration. */ return -EINVAL; } } qemu_get_be32s(f, &nr_active_ports); /* Items in struct VirtIOSerialPort */ for (i = 0; i < nr_active_ports; i++) { uint32_t id; bool host_connected; id = qemu_get_be32(f); port = find_port_by_id(s, id); if (!port) { return -EINVAL; } port->guest_connected = qemu_get_byte(f); host_connected = qemu_get_byte(f); if (host_connected != port->host_connected) { /* * We have to let the guest know of the host connection * status change */ send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, port->host_connected); } if (version_id > 2) { uint32_t elem_popped; qemu_get_be32s(f, &elem_popped); if (elem_popped) { qemu_get_be32s(f, &port->iov_idx); qemu_get_be64s(f, &port->iov_offset); qemu_get_buffer(f, (unsigned char *)&port->elem, sizeof(port->elem)); virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr, port->elem.in_num, 1); virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr, port->elem.out_num, 1); /* * Port was throttled on source machine. Let's * unthrottle it here so data starts flowing again. */ virtio_serial_throttle_port(port, false); } } } return 0; }