Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc,vhost,virtio fixes, enhancements
virtio bi-endian support
new command to resync RTC
misc bugfixes and cleanups
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Sun 29 Jun 2014 17:41:13 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>"
* remotes/mst/tags/for_upstream: (37 commits)
tests: add human format test for string output visitor
vhost-net: disable when cross-endian
target-ppc: enable virtio endian ambivalent support
virtio-9p: use virtio wrappers to access headers
virtio-serial-bus: use virtio wrappers to access headers
virtio-scsi: use virtio wrappers to access headers
virtio-blk: use virtio wrappers to access headers
virtio-balloon: use virtio wrappers to access page frame numbers
virtio-net: use virtio wrappers to access headers
virtio: allow byte swapping for vring
virtio: memory accessors for endian-ambivalent targets
virtio: add endian-ambivalent support to VirtIODevice
cpu: introduce CPUClass::virtio_is_big_endian()
exec: introduce target_words_bigendian() helper
virtio: add subsections to the migration stream
virtio-rng: implement per-device migration calls
virtio-balloon: implement per-device migration calls
virtio-serial: implement per-device migration calls
virtio-blk: implement per-device migration calls
virtio-net: implement per-device migration calls
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/docs/specs/vhost-user.txt b/docs/specs/vhost-user.txt
index 0ea767e..650bb18 100644
--- a/docs/specs/vhost-user.txt
+++ b/docs/specs/vhost-user.txt
@@ -78,14 +78,14 @@
Padding: 32-bit
A region is:
- ---------------------------------------
- | guest address | size | user address |
- ---------------------------------------
+ -----------------------------------------------------
+ | guest address | size | user address | mmap offset |
+ -----------------------------------------------------
Guest address: a 64-bit guest address of the region
Size: a 64-bit size
User address: a 64-bit user address
-
+ mmap offset: 64-bit offset where region starts in the mapped memory
In QEMU the vhost-user message is implemented with the following struct:
@@ -132,7 +132,7 @@
* VHOST_USER_GET_FEATURES
- Id: 2
+ Id: 1
Equivalent ioctl: VHOST_GET_FEATURES
Master payload: N/A
Slave payload: u64
@@ -141,7 +141,7 @@
* VHOST_USER_SET_FEATURES
- Id: 3
+ Id: 2
Ioctl: VHOST_SET_FEATURES
Master payload: u64
@@ -149,7 +149,7 @@
* VHOST_USER_SET_OWNER
- Id: 4
+ Id: 3
Equivalent ioctl: VHOST_SET_OWNER
Master payload: N/A
@@ -159,7 +159,7 @@
* VHOST_USER_RESET_OWNER
- Id: 5
+ Id: 4
Equivalent ioctl: VHOST_RESET_OWNER
Master payload: N/A
@@ -168,7 +168,7 @@
* VHOST_USER_SET_MEM_TABLE
- Id: 6
+ Id: 5
Equivalent ioctl: VHOST_SET_MEM_TABLE
Master payload: memory regions description
@@ -179,7 +179,7 @@
* VHOST_USER_SET_LOG_BASE
- Id: 7
+ Id: 6
Equivalent ioctl: VHOST_SET_LOG_BASE
Master payload: u64
@@ -187,7 +187,7 @@
* VHOST_USER_SET_LOG_FD
- Id: 8
+ Id: 7
Equivalent ioctl: VHOST_SET_LOG_FD
Master payload: N/A
@@ -195,7 +195,7 @@
* VHOST_USER_SET_VRING_NUM
- Id: 9
+ Id: 8
Equivalent ioctl: VHOST_SET_VRING_NUM
Master payload: vring state description
@@ -203,7 +203,7 @@
* VHOST_USER_SET_VRING_ADDR
- Id: 10
+ Id: 9
Equivalent ioctl: VHOST_SET_VRING_ADDR
Master payload: vring address description
Slave payload: N/A
@@ -212,7 +212,7 @@
* VHOST_USER_SET_VRING_BASE
- Id: 11
+ Id: 10
Equivalent ioctl: VHOST_SET_VRING_BASE
Master payload: vring state description
@@ -220,7 +220,7 @@
* VHOST_USER_GET_VRING_BASE
- Id: 12
+ Id: 11
Equivalent ioctl: VHOST_USER_GET_VRING_BASE
Master payload: vring state description
Slave payload: vring state description
@@ -229,7 +229,7 @@
* VHOST_USER_SET_VRING_KICK
- Id: 13
+ Id: 12
Equivalent ioctl: VHOST_SET_VRING_KICK
Master payload: u64
@@ -242,7 +242,7 @@
* VHOST_USER_SET_VRING_CALL
- Id: 14
+ Id: 13
Equivalent ioctl: VHOST_SET_VRING_CALL
Master payload: u64
@@ -255,7 +255,7 @@
* VHOST_USER_SET_VRING_ERR
- Id: 15
+ Id: 14
Equivalent ioctl: VHOST_SET_VRING_ERR
Master payload: u64
diff --git a/exec.c b/exec.c
index c849405..18d6c35 100644
--- a/exec.c
+++ b/exec.c
@@ -1456,6 +1456,13 @@
return block->fd;
}
+void *qemu_get_ram_block_host_ptr(ram_addr_t addr)
+{
+ RAMBlock *block = qemu_get_ram_block(addr);
+
+ return block->host;
+}
+
/* Return a host pointer to ram allocated with qemu_ram_alloc.
With the exception of the softmmu code in this file, this should
only be used for local memory (e.g. video ram) that the device owns,
@@ -2752,14 +2759,12 @@
}
#endif
-#if !defined(CONFIG_USER_ONLY)
-
/*
* A helper function for the _utterly broken_ virtio device model to find out if
* it's running on a big endian machine. Don't do this at home kids!
*/
-bool virtio_is_big_endian(void);
-bool virtio_is_big_endian(void)
+bool target_words_bigendian(void);
+bool target_words_bigendian(void)
{
#if defined(TARGET_WORDS_BIGENDIAN)
return true;
@@ -2768,8 +2773,6 @@
#endif
}
-#endif
-
#ifndef CONFIG_USER_ONLY
bool cpu_physical_memory_is_io(hwaddr phys_addr)
{
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 653762a..2572747 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -19,6 +19,7 @@
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-xattr.h"
#include "virtio-9p-coth.h"
+#include "hw/virtio/virtio-access.h"
static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
{
@@ -34,7 +35,7 @@
len = strlen(s->tag);
cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
- stw_p(&cfg->tag_len, len);
+ virtio_stw_p(vdev, &cfg->tag_len, len);
/* We don't copy the terminating null to config space */
memcpy(cfg->tag, s->tag, len);
memcpy(config, cfg, s->config_size);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index a222e3f..e59ebc9 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -27,6 +27,7 @@
# include <scsi/sg.h>
#endif
#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-access.h"
static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
{
@@ -88,7 +89,8 @@
trace_virtio_blk_rw_complete(req, ret);
if (ret) {
- bool is_read = !(ldl_p(&req->out.type) & VIRTIO_BLK_T_OUT);
+ int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
+ bool is_read = !(p & VIRTIO_BLK_T_OUT);
if (virtio_blk_handle_rw_error(req, -ret, is_read))
return;
}
@@ -130,6 +132,8 @@
{
int status = VIRTIO_BLK_S_OK;
struct virtio_scsi_inhdr *scsi = NULL;
+ VirtIODevice *vdev = VIRTIO_DEVICE(blk);
+
#ifdef __linux__
int i;
struct sg_io_hdr hdr;
@@ -224,12 +228,12 @@
hdr.status = CHECK_CONDITION;
}
- stl_p(&scsi->errors,
- hdr.status | (hdr.msg_status << 8) |
- (hdr.host_status << 16) | (hdr.driver_status << 24));
- stl_p(&scsi->residual, hdr.resid);
- stl_p(&scsi->sense_len, hdr.sb_len_wr);
- stl_p(&scsi->data_len, hdr.dxfer_len);
+ virtio_stl_p(vdev, &scsi->errors,
+ hdr.status | (hdr.msg_status << 8) |
+ (hdr.host_status << 16) | (hdr.driver_status << 24));
+ virtio_stl_p(vdev, &scsi->residual, hdr.resid);
+ virtio_stl_p(vdev, &scsi->sense_len, hdr.sb_len_wr);
+ virtio_stl_p(vdev, &scsi->data_len, hdr.dxfer_len);
return status;
#else
@@ -239,7 +243,7 @@
fail:
/* Just put anything nonzero so that the ioctl fails in the guest. */
if (scsi) {
- stl_p(&scsi->errors, 255);
+ virtio_stl_p(vdev, &scsi->errors, 255);
}
return status;
}
@@ -289,7 +293,7 @@
BlockRequest *blkreq;
uint64_t sector;
- sector = ldq_p(&req->out.sector);
+ sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector);
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
@@ -323,7 +327,7 @@
{
uint64_t sector;
- sector = ldq_p(&req->out.sector);
+ sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector);
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
@@ -374,7 +378,7 @@
- sizeof(struct virtio_blk_inhdr);
iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
- type = ldl_p(&req->out.type);
+ type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
if (type & VIRTIO_BLK_T_FLUSH) {
virtio_blk_handle_flush(req, mrb);
@@ -504,12 +508,12 @@
bdrv_get_geometry(s->bs, &capacity);
memset(&blkcfg, 0, sizeof(blkcfg));
- stq_p(&blkcfg.capacity, capacity);
- stl_p(&blkcfg.seg_max, 128 - 2);
- stw_p(&blkcfg.cylinders, s->conf->cyls);
- stl_p(&blkcfg.blk_size, blk_size);
- stw_p(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
- stw_p(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
+ virtio_stq_p(vdev, &blkcfg.capacity, capacity);
+ virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
+ virtio_stw_p(vdev, &blkcfg.cylinders, s->conf->cyls);
+ virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
+ virtio_stw_p(vdev, &blkcfg.min_io_size, s->conf->min_io_size / blk_size);
+ virtio_stw_p(vdev, &blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
blkcfg.heads = s->conf->heads;
/*
* We must ensure that the block device capacity is a multiple of
@@ -611,12 +615,16 @@
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
- VirtIOBlock *s = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
- VirtIOBlockReq *req = s->rq;
+ VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
virtio_save(vdev, f);
+}
+static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
+{
+ VirtIOBlock *s = VIRTIO_BLK(vdev);
+ VirtIOBlockReq *req = s->rq;
+
while (req) {
qemu_put_sbyte(f, 1);
qemu_put_buffer(f, (unsigned char *)req->elem,
@@ -630,15 +638,17 @@
{
VirtIOBlock *s = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(s);
- int ret;
if (version_id != 2)
return -EINVAL;
- ret = virtio_load(vdev, f);
- if (ret) {
- return ret;
- }
+ return virtio_load(vdev, f, version_id);
+}
+
+static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
+ int version_id)
+{
+ VirtIOBlock *s = VIRTIO_BLK(vdev);
while (qemu_get_sbyte(f)) {
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
@@ -799,6 +809,8 @@
vdc->get_features = virtio_blk_get_features;
vdc->set_status = virtio_blk_set_status;
vdc->reset = virtio_blk_reset;
+ vdc->save = virtio_blk_save_device;
+ vdc->load = virtio_blk_load_device;
}
static const TypeInfo virtio_device_info = {
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index a2958ff..07bebc0 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -24,6 +24,7 @@
#include "hw/sysbus.h"
#include "trace.h"
#include "hw/virtio/virtio-serial.h"
+#include "hw/virtio/virtio-access.h"
static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
{
@@ -183,11 +184,12 @@
static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id,
uint16_t event, uint16_t value)
{
+ VirtIODevice *vdev = VIRTIO_DEVICE(vser);
struct virtio_console_control cpkt;
- stl_p(&cpkt.id, port_id);
- stw_p(&cpkt.event, event);
- stw_p(&cpkt.value, value);
+ virtio_stl_p(vdev, &cpkt.id, port_id);
+ virtio_stw_p(vdev, &cpkt.event, event);
+ virtio_stw_p(vdev, &cpkt.value, value);
trace_virtio_serial_send_control_event(port_id, event, value);
return send_control_msg(vser, &cpkt, sizeof(cpkt));
@@ -278,6 +280,7 @@
/* Guest wants to notify us of some event */
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
{
+ VirtIODevice *vdev = VIRTIO_DEVICE(vser);
struct VirtIOSerialPort *port;
VirtIOSerialPortClass *vsc;
struct virtio_console_control cpkt, *gcpkt;
@@ -291,8 +294,8 @@
return;
}
- cpkt.event = lduw_p(&gcpkt->event);
- cpkt.value = lduw_p(&gcpkt->value);
+ cpkt.event = virtio_lduw_p(vdev, &gcpkt->event);
+ cpkt.value = virtio_lduw_p(vdev, &gcpkt->value);
trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
@@ -312,10 +315,10 @@
return;
}
- port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+ port = find_port_by_id(vser, virtio_ldl_p(vdev, &gcpkt->id));
if (!port) {
error_report("virtio-serial-bus: Unexpected port id %u for device %s",
- ldl_p(&gcpkt->id), vser->bus.qbus.name);
+ virtio_ldl_p(vdev, &gcpkt->id), vser->bus.qbus.name);
return;
}
@@ -342,9 +345,9 @@
}
if (port->name) {
- stl_p(&cpkt.id, port->id);
- stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
- stw_p(&cpkt.value, 1);
+ virtio_stl_p(vdev, &cpkt.id, port->id);
+ virtio_stw_p(vdev, &cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
+ virtio_stw_p(vdev, &cpkt.value, 1);
buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
buffer = g_malloc(buffer_len);
@@ -510,18 +513,25 @@
vser = VIRTIO_SERIAL(vdev);
guest_reset(vser);
+
+ /* In case we have switched endianness */
+ vser->config.max_nr_ports =
+ virtio_tswap32(vdev, vser->serial.max_virtserial_ports);
}
static void virtio_serial_save(QEMUFile *f, void *opaque)
{
- VirtIOSerial *s = VIRTIO_SERIAL(opaque);
+ /* The virtio device */
+ virtio_save(VIRTIO_DEVICE(opaque), f);
+}
+
+static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
+{
+ VirtIOSerial *s = VIRTIO_SERIAL(vdev);
VirtIOSerialPort *port;
uint32_t nr_active_ports;
unsigned int i, max_nr_ports;
- /* The virtio device */
- virtio_save(VIRTIO_DEVICE(s), f);
-
/* The config space */
qemu_put_be16s(f, &s->config.cols);
qemu_put_be16s(f, &s->config.rows);
@@ -529,7 +539,7 @@
qemu_put_be32s(f, &s->config.max_nr_ports);
/* The ports map */
- max_nr_ports = tswap32(s->config.max_nr_ports);
+ max_nr_ports = virtio_tswap32(vdev, s->config.max_nr_ports);
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
qemu_put_be32s(f, &s->ports_map[i]);
}
@@ -659,36 +669,39 @@
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
{
- VirtIOSerial *s = VIRTIO_SERIAL(opaque);
- 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(VIRTIO_DEVICE(s), f);
- if (ret) {
- return ret;
- }
+ return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
+}
+
+static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f,
+ int version_id)
+{
+ VirtIOSerial *s = VIRTIO_SERIAL(vdev);
+ uint32_t max_nr_ports, nr_active_ports, ports_map;
+ unsigned int i;
+ int ret;
+ uint32_t tmp;
if (version_id < 2) {
return 0;
}
- /* The config space */
- qemu_get_be16s(f, &s->config.cols);
- qemu_get_be16s(f, &s->config.rows);
+ /* Unused */
+ qemu_get_be16s(f, (uint16_t *) &tmp);
+ qemu_get_be16s(f, (uint16_t *) &tmp);
+ qemu_get_be32s(f, &tmp);
- 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;
- }
-
+ /* Note: this is the only location where we use tswap32() instead of
+ * virtio_tswap32() because:
+ * - virtio_tswap32() only makes sense when the device is fully restored
+ * - the target endianness that was used to populate s->config is
+ * necessarly the default one
+ */
+ max_nr_ports = tswap32(s->config.max_nr_ports);
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
qemu_get_be32s(f, &ports_map);
@@ -751,9 +764,10 @@
/* This function is only used if a port id is not provided by the user */
static uint32_t find_free_port_id(VirtIOSerial *vser)
{
+ VirtIODevice *vdev = VIRTIO_DEVICE(vser);
unsigned int i, max_nr_ports;
- max_nr_ports = tswap32(vser->config.max_nr_ports);
+ max_nr_ports = virtio_tswap32(vdev, vser->config.max_nr_ports);
for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
uint32_t map, bit;
@@ -806,6 +820,7 @@
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
+ VirtIODevice *vdev = VIRTIO_DEVICE(bus->vser);
int max_nr_ports;
bool plugging_port0;
Error *err = NULL;
@@ -841,7 +856,7 @@
}
}
- max_nr_ports = tswap32(port->vser->config.max_nr_ports);
+ max_nr_ports = virtio_tswap32(vdev, port->vser->config.max_nr_ports);
if (port->id >= max_nr_ports) {
error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
"max. allowed: %u", max_nr_ports - 1);
@@ -863,7 +878,7 @@
add_port(port->vser, port->id);
/* Send an update to the guest about this new port added */
- virtio_notify_config(VIRTIO_DEVICE(port->vser));
+ virtio_notify_config(vdev);
}
static void virtser_port_device_unrealize(DeviceState *dev, Error **errp)
@@ -942,7 +957,8 @@
vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
}
- vser->config.max_nr_ports = tswap32(vser->serial.max_virtserial_ports);
+ vser->config.max_nr_ports =
+ virtio_tswap32(vdev, vser->serial.max_virtserial_ports);
vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
* sizeof(vser->ports_map[0]));
/*
@@ -1019,6 +1035,8 @@
vdc->get_config = get_config;
vdc->set_status = set_status;
vdc->reset = vser_reset;
+ vdc->save = virtio_serial_save_device;
+ vdc->load = virtio_serial_load_device;
}
static const TypeInfo virtio_device_info = {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 47546b7..2dccb34 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -392,6 +392,11 @@
has_pci_info = false;
has_acpi_build = false;
smbios_defaults = false;
+ gigabyte_align = false;
+ smbios_legacy_mode = true;
+ has_reserved_memory = false;
+ option_rom_has_mr = true;
+ rom_file_has_mr = false;
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
enable_compat_apic_id_mode();
pc_init1(machine, 1, 0);
@@ -402,6 +407,11 @@
has_pci_info = false;
has_acpi_build = false;
smbios_defaults = false;
+ gigabyte_align = false;
+ smbios_legacy_mode = true;
+ has_reserved_memory = false;
+ option_rom_has_mr = true;
+ rom_file_has_mr = false;
if (!machine->cpu_model) {
machine->cpu_model = "486";
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 155db99..36b6ab0 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -361,7 +361,7 @@
.name = "pc-q35-2.0",
.init = pc_q35_init_2_0,
.compat_props = (GlobalProperty[]) {
- PC_Q35_COMPAT_2_0,
+ PC_COMPAT_2_0,
{ /* end of list */ }
},
};
@@ -373,7 +373,7 @@
.name = "pc-q35-1.7",
.init = pc_q35_init_1_7,
.compat_props = (GlobalProperty[]) {
- PC_Q35_COMPAT_1_7,
+ PC_COMPAT_1_7,
{ /* end of list */ }
},
};
@@ -385,7 +385,7 @@
.name = "pc-q35-1.6",
.init = pc_q35_init_1_6,
.compat_props = (GlobalProperty[]) {
- PC_Q35_COMPAT_1_6,
+ PC_COMPAT_1_6,
{ /* end of list */ }
},
};
@@ -395,7 +395,7 @@
.name = "pc-q35-1.5",
.init = pc_q35_init_1_5,
.compat_props = (GlobalProperty[]) {
- PC_Q35_COMPAT_1_5,
+ PC_COMPAT_1_5,
{ /* end of list */ }
},
};
@@ -409,7 +409,7 @@
.name = "pc-q35-1.4",
.init = pc_q35_init_1_4,
.compat_props = (GlobalProperty[]) {
- PC_Q35_COMPAT_1_4,
+ PC_COMPAT_1_4,
{ /* end of list */ }
},
};
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 7ac7c21..f87c798 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -275,6 +275,19 @@
vhost_dev_disable_notifiers(&net->dev, dev);
}
+static bool vhost_net_device_endian_ok(VirtIODevice *vdev)
+{
+#ifdef TARGET_IS_BIENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
+ return virtio_is_big_endian(vdev);
+#else
+ return !virtio_is_big_endian(vdev);
+#endif
+#else
+ return true;
+#endif
+}
+
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
int total_queues)
{
@@ -283,6 +296,12 @@
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
int r, i = 0;
+ if (!vhost_net_device_endian_ok(dev)) {
+ error_report("vhost-net does not support cross-endian");
+ r = -ENOSYS;
+ goto err;
+ }
+
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
r = -ENOSYS;
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index e51d753..268eff9 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -23,6 +23,7 @@
#include "hw/virtio/virtio-bus.h"
#include "qapi/qmp/qjson.h"
#include "qapi-event.h"
+#include "hw/virtio/virtio-access.h"
#define VIRTIO_NET_VM_VERSION 11
@@ -72,8 +73,8 @@
VirtIONet *n = VIRTIO_NET(vdev);
struct virtio_net_config netcfg;
- stw_p(&netcfg.status, n->status);
- stw_p(&netcfg.max_virtqueue_pairs, n->max_queues);
+ virtio_stw_p(vdev, &netcfg.status, n->status);
+ virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues);
memcpy(netcfg.mac, n->mac, ETH_ALEN);
memcpy(config, &netcfg, n->config_size);
}
@@ -604,6 +605,7 @@
static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
struct iovec *iov, unsigned int iov_cnt)
{
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct virtio_net_ctrl_mac mac_data;
size_t s;
NetClientState *nc = qemu_get_queue(n->nic);
@@ -632,7 +634,7 @@
s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
sizeof(mac_data.entries));
- mac_data.entries = ldl_p(&mac_data.entries);
+ mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries);
if (s != sizeof(mac_data.entries)) {
goto error;
}
@@ -659,7 +661,7 @@
s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
sizeof(mac_data.entries));
- mac_data.entries = ldl_p(&mac_data.entries);
+ mac_data.entries = virtio_ldl_p(vdev, &mac_data.entries);
if (s != sizeof(mac_data.entries)) {
goto error;
}
@@ -699,12 +701,13 @@
static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
struct iovec *iov, unsigned int iov_cnt)
{
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
uint16_t vid;
size_t s;
NetClientState *nc = qemu_get_queue(n->nic);
s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
- vid = lduw_p(&vid);
+ vid = virtio_lduw_p(vdev, &vid);
if (s != sizeof(vid)) {
return VIRTIO_NET_ERR;
}
@@ -758,7 +761,7 @@
return VIRTIO_NET_ERR;
}
- queues = lduw_p(&mq.virtqueue_pairs);
+ queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs);
if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
@@ -875,6 +878,14 @@
return 1;
}
+static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr)
+{
+ virtio_tswap16s(vdev, &hdr->hdr_len);
+ virtio_tswap16s(vdev, &hdr->gso_size);
+ virtio_tswap16s(vdev, &hdr->csum_start);
+ virtio_tswap16s(vdev, &hdr->csum_offset);
+}
+
/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
* it never finds out that the packets don't have valid checksums. This
* causes dhclient to get upset. Fedora's carried a patch for ages to
@@ -910,6 +921,7 @@
void *wbuf = (void *)buf;
work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
size - n->host_hdr_len);
+ virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
} else {
struct virtio_net_hdr hdr = {
@@ -1059,7 +1071,7 @@
}
if (mhdr_cnt) {
- stw_p(&mhdr.num_buffers, i);
+ virtio_stw_p(vdev, &mhdr.num_buffers, i);
iov_from_buf(mhdr_sg, mhdr_cnt,
0,
&mhdr.num_buffers, sizeof mhdr.num_buffers);
@@ -1118,6 +1130,14 @@
exit(1);
}
+ if (n->has_vnet_hdr) {
+ if (out_sg[0].iov_len < n->guest_hdr_len) {
+ error_report("virtio-net header incorrect");
+ exit(1);
+ }
+ virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
+ }
+
/*
* If host wants to see the guest header as is, we can
* pass it on unchanged. Otherwise, copy just the parts
@@ -1297,7 +1317,6 @@
static void virtio_net_save(QEMUFile *f, void *opaque)
{
- int i;
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
@@ -1305,6 +1324,12 @@
* it might keep writing to memory. */
assert(!n->vhost_started);
virtio_save(vdev, f);
+}
+
+static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f)
+{
+ VirtIONet *n = VIRTIO_NET(vdev);
+ int i;
qemu_put_buffer(f, n->mac, ETH_ALEN);
qemu_put_be32(f, n->vqs[0].tx_waiting);
@@ -1340,15 +1365,18 @@
{
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int ret, i, link_down;
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
return -EINVAL;
- ret = virtio_load(vdev, f);
- if (ret) {
- return ret;
- }
+ return virtio_load(vdev, f, version_id);
+}
+
+static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
+ int version_id)
+{
+ VirtIONet *n = VIRTIO_NET(vdev);
+ int i, link_down;
qemu_get_buffer(f, n->mac, ETH_ALEN);
n->vqs[0].tx_waiting = qemu_get_be32(f);
@@ -1694,6 +1722,8 @@
vdc->set_status = virtio_net_set_status;
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
+ vdc->load = virtio_net_load_device;
+ vdc->save = virtio_net_save_device;
}
static const TypeInfo virtio_net_info = {
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 8c8c9d1..04ecfa7 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -19,6 +19,7 @@
#include <hw/scsi/scsi.h>
#include <block/scsi.h>
#include <hw/virtio/virtio-bus.h>
+#include "hw/virtio/virtio-access.h"
typedef struct VirtIOSCSIReq {
VirtIOSCSI *dev;
@@ -235,7 +236,7 @@
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
req->resp.tmf.response = VIRTIO_SCSI_S_OK;
- tswap32s(&req->req.tmf.subtype);
+ virtio_tswap32s(VIRTIO_DEVICE(s), &req->req.tmf.subtype);
switch (req->req.tmf.subtype) {
case VIRTIO_SCSI_T_TMF_ABORT_TASK:
case VIRTIO_SCSI_T_TMF_QUERY_TASK:
@@ -346,7 +347,7 @@
continue;
}
- tswap32s(&req->req.tmf.type);
+ virtio_tswap32s(vdev, &req->req.tmf.type);
if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) {
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
@@ -384,6 +385,7 @@
VirtIOSCSIReq *req = r->hba_private;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint32_t sense_len;
+ VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
if (r->io_canceled) {
return;
@@ -392,14 +394,14 @@
req->resp.cmd.response = VIRTIO_SCSI_S_OK;
req->resp.cmd.status = status;
if (req->resp.cmd.status == GOOD) {
- req->resp.cmd.resid = tswap32(resid);
+ req->resp.cmd.resid = virtio_tswap32(vdev, resid);
} else {
req->resp.cmd.resid = 0;
sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
&req->resp, sense_len);
- req->resp.cmd.sense_len = tswap32(sense_len);
+ req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
}
virtio_scsi_complete_cmd_req(req);
}
@@ -487,16 +489,16 @@
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
- stl_p(&scsiconf->num_queues, s->conf.num_queues);
- stl_p(&scsiconf->seg_max, 128 - 2);
- stl_p(&scsiconf->max_sectors, s->conf.max_sectors);
- stl_p(&scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
- stl_p(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
- stl_p(&scsiconf->sense_size, s->sense_size);
- stl_p(&scsiconf->cdb_size, s->cdb_size);
- stw_p(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
- stw_p(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
- stl_p(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
+ virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
+ virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2);
+ virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
+ virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
+ virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
+ virtio_stl_p(vdev, &scsiconf->sense_size, s->sense_size);
+ virtio_stl_p(vdev, &scsiconf->cdb_size, s->cdb_size);
+ virtio_stw_p(vdev, &scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
+ virtio_stw_p(vdev, &scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
+ virtio_stl_p(vdev, &scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
}
static void virtio_scsi_set_config(VirtIODevice *vdev,
@@ -505,14 +507,14 @@
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
- if ((uint32_t) ldl_p(&scsiconf->sense_size) >= 65536 ||
- (uint32_t) ldl_p(&scsiconf->cdb_size) >= 256) {
+ if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 ||
+ (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) {
error_report("bad data written to virtio-scsi configuration space");
exit(1);
}
- vs->sense_size = ldl_p(&scsiconf->sense_size);
- vs->cdb_size = ldl_p(&scsiconf->cdb_size);
+ vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size);
+ vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
}
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
@@ -549,7 +551,7 @@
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
int ret;
- ret = virtio_load(vdev, f);
+ ret = virtio_load(vdev, f, version_id);
if (ret) {
return ret;
}
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 05002bf..307732c 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -27,6 +27,7 @@
#include "hw/timer/mc146818rtc.h"
#include "qapi/visitor.h"
#include "qapi-event.h"
+#include "qmp-commands.h"
#ifdef TARGET_I386
#include "hw/i386/apic.h"
@@ -85,6 +86,7 @@
Notifier clock_reset_notifier;
LostTickPolicy lost_tick_policy;
Notifier suspend_notifier;
+ QLIST_ENTRY(RTCState) link;
} RTCState;
static void rtc_set_time(RTCState *s);
@@ -523,6 +525,20 @@
rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900;
}
+static QLIST_HEAD(, RTCState) rtc_devices =
+ QLIST_HEAD_INITIALIZER(rtc_devices);
+
+#ifdef TARGET_I386
+void qmp_rtc_reset_reinjection(Error **errp)
+{
+ RTCState *s;
+
+ QLIST_FOREACH(s, &rtc_devices, link) {
+ s->irq_coalesced = 0;
+ }
+}
+#endif
+
static void rtc_set_time(RTCState *s)
{
struct tm tm;
@@ -911,6 +927,8 @@
} else {
isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ);
}
+ QLIST_INSERT_HEAD(&rtc_devices, s, link);
+
return isadev;
}
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 0df6a93..38e5806 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -14,6 +14,7 @@
#include "sysemu/kvm.h"
#include "qemu/error-report.h"
#include "qemu/sockets.h"
+#include "exec/ram_addr.h"
#include <fcntl.h>
#include <unistd.h>
@@ -47,6 +48,7 @@
uint64_t guest_phys_addr;
uint64_t memory_size;
uint64_t userspace_addr;
+ uint64_t mmap_offset;
} VhostUserMemoryRegion;
typedef struct VhostUserMemory {
@@ -183,10 +185,10 @@
{
VhostUserMsg msg;
VhostUserRequest msg_request;
- RAMBlock *block = 0;
struct vhost_vring_file *file = 0;
int need_reply = 0;
int fds[VHOST_MEMORY_MAX_NREGIONS];
+ int i, fd;
size_t fd_num = 0;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
@@ -212,14 +214,17 @@
break;
case VHOST_SET_MEM_TABLE:
- QTAILQ_FOREACH(block, &ram_list.blocks, next)
- {
- if (block->fd > 0) {
- msg.memory.regions[fd_num].userspace_addr =
- (uintptr_t) block->host;
- msg.memory.regions[fd_num].memory_size = block->length;
- msg.memory.regions[fd_num].guest_phys_addr = block->offset;
- fds[fd_num++] = block->fd;
+ for (i = 0; i < dev->mem->nregions; ++i) {
+ struct vhost_memory_region *reg = dev->mem->regions + i;
+ fd = qemu_get_ram_fd(reg->guest_phys_addr);
+ if (fd > 0) {
+ msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
+ msg.memory.regions[fd_num].memory_size = reg->memory_size;
+ msg.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
+ msg.memory.regions[fd_num].mmap_offset = reg->userspace_addr -
+ (uintptr_t) qemu_get_ram_block_host_ptr(reg->guest_phys_addr);
+ assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
+ fds[fd_num++] = fd;
}
}
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 2a2e58a..2c30b3d 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -31,6 +31,7 @@
#endif
#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-access.h"
static void balloon_page(void *addr, int deflate)
{
@@ -206,8 +207,9 @@
while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) {
ram_addr_t pa;
ram_addr_t addr;
+ int p = virtio_ldl_p(vdev, &pfn);
- pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
+ pa = (ram_addr_t) p << VIRTIO_BALLOON_PFN_SHIFT;
offset += 4;
/* FIXME: remove get_system_memory(), but how? */
@@ -248,8 +250,8 @@
while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
== sizeof(stat)) {
- uint16_t tag = tswap16(stat.tag);
- uint64_t val = tswap64(stat.val);
+ uint16_t tag = virtio_tswap16(vdev, stat.tag);
+ uint64_t val = virtio_tswap64(vdev, stat.val);
offset += sizeof(stat);
if (tag < VIRTIO_BALLOON_S_NR)
@@ -325,10 +327,12 @@
static void virtio_balloon_save(QEMUFile *f, void *opaque)
{
- VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
+ virtio_save(VIRTIO_DEVICE(opaque), f);
+}
- virtio_save(vdev, f);
+static void virtio_balloon_save_device(VirtIODevice *vdev, QEMUFile *f)
+{
+ VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
qemu_put_be32(f, s->num_pages);
qemu_put_be32(f, s->actual);
@@ -336,17 +340,16 @@
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
{
- VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
- VirtIODevice *vdev = VIRTIO_DEVICE(s);
- int ret;
-
if (version_id != 1)
return -EINVAL;
- ret = virtio_load(vdev, f);
- if (ret) {
- return ret;
- }
+ return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
+}
+
+static int virtio_balloon_load_device(VirtIODevice *vdev, QEMUFile *f,
+ int version_id)
+{
+ VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
s->num_pages = qemu_get_be32(f);
s->actual = qemu_get_be32(f);
@@ -416,6 +419,8 @@
vdc->get_config = virtio_balloon_get_config;
vdc->set_config = virtio_balloon_set_config;
vdc->get_features = virtio_balloon_get_features;
+ vdc->save = virtio_balloon_save_device;
+ vdc->load = virtio_balloon_load_device;
}
static const TypeInfo virtio_balloon_info = {
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 57e1e61..317324f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -89,9 +89,6 @@
/* Flags track per-device state like workarounds for quirks in older guests. */
#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0)
-/* HACK for virtio to determine if it's running a big endian guest */
-bool virtio_is_big_endian(void);
-
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOPCIProxy *dev);
@@ -409,13 +406,13 @@
break;
case 2:
val = virtio_config_readw(vdev, addr);
- if (virtio_is_big_endian()) {
+ if (virtio_is_big_endian(vdev)) {
val = bswap16(val);
}
break;
case 4:
val = virtio_config_readl(vdev, addr);
- if (virtio_is_big_endian()) {
+ if (virtio_is_big_endian(vdev)) {
val = bswap32(val);
}
break;
@@ -443,13 +440,13 @@
virtio_config_writeb(vdev, addr, val);
break;
case 2:
- if (virtio_is_big_endian()) {
+ if (virtio_is_big_endian(vdev)) {
val = bswap16(val);
}
virtio_config_writew(vdev, addr, val);
break;
case 4:
- if (virtio_is_big_endian()) {
+ if (virtio_is_big_endian(vdev)) {
val = bswap32(val);
}
virtio_config_writel(vdev, addr, val);
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index b6ab361..1356aca 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -107,19 +107,20 @@
static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
{
- VirtIORNG *vrng = opaque;
- VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
-
if (version_id != 1) {
return -EINVAL;
}
- virtio_load(vdev, f);
+ return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
+}
+static int virtio_rng_load_device(VirtIODevice *vdev, QEMUFile *f,
+ int version_id)
+{
/* We may have an element ready but couldn't process it due to a quota
* limit. Make sure to try again after live migration when the quota may
* have been reset.
*/
- virtio_rng_process(vrng);
+ virtio_rng_process(VIRTIO_RNG(vdev));
return 0;
}
@@ -219,6 +220,7 @@
vdc->realize = virtio_rng_device_realize;
vdc->unrealize = virtio_rng_device_unrealize;
vdc->get_features = get_features;
+ vdc->load = virtio_rng_load_device;
}
static void virtio_rng_initfn(Object *obj)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index a3082d5..5c98180 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -19,6 +19,8 @@
#include "hw/virtio/virtio.h"
#include "qemu/atomic.h"
#include "hw/virtio/virtio-bus.h"
+#include "migration/migration.h"
+#include "hw/virtio/virtio-access.h"
/*
* The alignment to use between consumer and producer parts of vring.
@@ -101,53 +103,56 @@
vq->vring.align);
}
-static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i)
+static inline uint64_t vring_desc_addr(VirtIODevice *vdev, hwaddr desc_pa,
+ int i)
{
hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
- return ldq_phys(&address_space_memory, pa);
+ return virtio_ldq_phys(vdev, pa);
}
-static inline uint32_t vring_desc_len(hwaddr desc_pa, int i)
+static inline uint32_t vring_desc_len(VirtIODevice *vdev, hwaddr desc_pa, int i)
{
hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
- return ldl_phys(&address_space_memory, pa);
+ return virtio_ldl_phys(vdev, pa);
}
-static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i)
+static inline uint16_t vring_desc_flags(VirtIODevice *vdev, hwaddr desc_pa,
+ int i)
{
hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
- return lduw_phys(&address_space_memory, pa);
+ return virtio_lduw_phys(vdev, pa);
}
-static inline uint16_t vring_desc_next(hwaddr desc_pa, int i)
+static inline uint16_t vring_desc_next(VirtIODevice *vdev, hwaddr desc_pa,
+ int i)
{
hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
- return lduw_phys(&address_space_memory, pa);
+ return virtio_lduw_phys(vdev, pa);
}
static inline uint16_t vring_avail_flags(VirtQueue *vq)
{
hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, flags);
- return lduw_phys(&address_space_memory, pa);
+ return virtio_lduw_phys(vq->vdev, pa);
}
static inline uint16_t vring_avail_idx(VirtQueue *vq)
{
hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, idx);
- return lduw_phys(&address_space_memory, pa);
+ return virtio_lduw_phys(vq->vdev, pa);
}
static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
{
hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
- return lduw_phys(&address_space_memory, pa);
+ return virtio_lduw_phys(vq->vdev, pa);
}
static inline uint16_t vring_used_event(VirtQueue *vq)
@@ -159,44 +164,44 @@
{
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
- stl_phys(&address_space_memory, pa, val);
+ virtio_stl_phys(vq->vdev, pa, val);
}
static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
{
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
- stl_phys(&address_space_memory, pa, val);
+ virtio_stl_phys(vq->vdev, pa, val);
}
static uint16_t vring_used_idx(VirtQueue *vq)
{
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, idx);
- return lduw_phys(&address_space_memory, pa);
+ return virtio_lduw_phys(vq->vdev, pa);
}
static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
{
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, idx);
- stw_phys(&address_space_memory, pa, val);
+ virtio_stw_phys(vq->vdev, pa, val);
}
static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
{
+ VirtIODevice *vdev = vq->vdev;
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, flags);
- stw_phys(&address_space_memory,
- pa, lduw_phys(&address_space_memory, pa) | mask);
+ virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) | mask);
}
static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
{
+ VirtIODevice *vdev = vq->vdev;
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, flags);
- stw_phys(&address_space_memory,
- pa, lduw_phys(&address_space_memory, pa) & ~mask);
+ virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) & ~mask);
}
static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
@@ -206,7 +211,7 @@
return;
}
pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
- stw_phys(&address_space_memory, pa, val);
+ virtio_stw_phys(vq->vdev, pa, val);
}
void virtio_queue_set_notification(VirtQueue *vq, int enable)
@@ -323,17 +328,18 @@
return head;
}
-static unsigned virtqueue_next_desc(hwaddr desc_pa,
+static unsigned virtqueue_next_desc(VirtIODevice *vdev, hwaddr desc_pa,
unsigned int i, unsigned int max)
{
unsigned int next;
/* If this descriptor says it doesn't chain, we're done. */
- if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
+ if (!(vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_NEXT)) {
return max;
+ }
/* Check they're not leading us off end of descriptors. */
- next = vring_desc_next(desc_pa, i);
+ next = vring_desc_next(vdev, desc_pa, i);
/* Make sure compiler knows to grab that: we don't want it changing! */
smp_wmb();
@@ -356,6 +362,7 @@
total_bufs = in_total = out_total = 0;
while (virtqueue_num_heads(vq, idx)) {
+ VirtIODevice *vdev = vq->vdev;
unsigned int max, num_bufs, indirect = 0;
hwaddr desc_pa;
int i;
@@ -365,8 +372,8 @@
i = virtqueue_get_head(vq, idx++);
desc_pa = vq->vring.desc;
- if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
- if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
+ if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) {
+ if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) {
error_report("Invalid size for indirect buffer table");
exit(1);
}
@@ -379,8 +386,8 @@
/* loop over the indirect descriptor table */
indirect = 1;
- max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
- desc_pa = vring_desc_addr(desc_pa, i);
+ max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc);
+ desc_pa = vring_desc_addr(vdev, desc_pa, i);
num_bufs = i = 0;
}
@@ -391,15 +398,15 @@
exit(1);
}
- if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
- in_total += vring_desc_len(desc_pa, i);
+ if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) {
+ in_total += vring_desc_len(vdev, desc_pa, i);
} else {
- out_total += vring_desc_len(desc_pa, i);
+ out_total += vring_desc_len(vdev, desc_pa, i);
}
if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
goto done;
}
- } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+ } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max);
if (!indirect)
total_bufs = num_bufs;
@@ -450,6 +457,7 @@
{
unsigned int i, head, max;
hwaddr desc_pa = vq->vring.desc;
+ VirtIODevice *vdev = vq->vdev;
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
return 0;
@@ -460,19 +468,19 @@
max = vq->vring.num;
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
- if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+ if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
vring_avail_event(vq, vring_avail_idx(vq));
}
- if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
- if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
+ if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) {
+ if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) {
error_report("Invalid size for indirect buffer table");
exit(1);
}
/* loop over the indirect descriptor table */
- max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
- desc_pa = vring_desc_addr(desc_pa, i);
+ max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc);
+ desc_pa = vring_desc_addr(vdev, desc_pa, i);
i = 0;
}
@@ -480,30 +488,30 @@
do {
struct iovec *sg;
- if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
+ if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) {
if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
error_report("Too many write descriptors in indirect table");
exit(1);
}
- elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
+ elem->in_addr[elem->in_num] = vring_desc_addr(vdev, desc_pa, i);
sg = &elem->in_sg[elem->in_num++];
} else {
if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
error_report("Too many read descriptors in indirect table");
exit(1);
}
- elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
+ elem->out_addr[elem->out_num] = vring_desc_addr(vdev, desc_pa, i);
sg = &elem->out_sg[elem->out_num++];
}
- sg->iov_len = vring_desc_len(desc_pa, i);
+ sg->iov_len = vring_desc_len(vdev, desc_pa, i);
/* If we've got too many, that implies a descriptor loop. */
if ((elem->in_num + elem->out_num) > max) {
error_report("Looped descriptor");
exit(1);
}
- } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+ } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max);
/* Now map what we have collected */
virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
@@ -544,6 +552,27 @@
vdev->status = val;
}
+bool target_words_bigendian(void);
+static enum virtio_device_endian virtio_default_endian(void)
+{
+ if (target_words_bigendian()) {
+ return VIRTIO_DEVICE_ENDIAN_BIG;
+ } else {
+ return VIRTIO_DEVICE_ENDIAN_LITTLE;
+ }
+}
+
+static enum virtio_device_endian virtio_current_cpu_endian(void)
+{
+ CPUClass *cc = CPU_GET_CLASS(current_cpu);
+
+ if (cc->virtio_is_big_endian(current_cpu)) {
+ return VIRTIO_DEVICE_ENDIAN_BIG;
+ } else {
+ return VIRTIO_DEVICE_ENDIAN_LITTLE;
+ }
+}
+
void virtio_reset(void *opaque)
{
VirtIODevice *vdev = opaque;
@@ -551,6 +580,13 @@
int i;
virtio_set_status(vdev, 0);
+ if (current_cpu) {
+ /* Guest initiated reset */
+ vdev->device_endian = virtio_current_cpu_endian();
+ } else {
+ /* System reset */
+ vdev->device_endian = virtio_default_endian();
+ }
if (k->reset) {
k->reset(vdev);
@@ -839,10 +875,46 @@
virtio_notify_vector(vdev, vdev->config_vector);
}
+static bool virtio_device_endian_needed(void *opaque)
+{
+ VirtIODevice *vdev = opaque;
+
+ assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
+ return vdev->device_endian != virtio_default_endian();
+}
+
+static const VMStateDescription vmstate_virtio_device_endian = {
+ .name = "virtio/device_endian",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(device_endian, VirtIODevice),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_virtio = {
+ .name = "virtio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &vmstate_virtio_device_endian,
+ .needed = &virtio_device_endian_needed
+ },
+ { 0 }
+ }
+};
+
void virtio_save(VirtIODevice *vdev, QEMUFile *f)
{
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
int i;
if (k->save_config) {
@@ -877,6 +949,13 @@
k->save_queue(qbus->parent, i, f);
}
}
+
+ if (vdc->save != NULL) {
+ vdc->save(vdev, f);
+ }
+
+ /* Subsections */
+ vmstate_save_state(f, &vmstate_virtio, vdev);
}
int virtio_set_features(VirtIODevice *vdev, uint32_t val)
@@ -895,7 +974,7 @@
return bad ? -1 : 0;
}
-int virtio_load(VirtIODevice *vdev, QEMUFile *f)
+int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
{
int i, ret;
int32_t config_len;
@@ -904,6 +983,13 @@
uint32_t supported_features;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+ /*
+ * We poison the endianness to ensure it does not get used before
+ * subsections have been loaded.
+ */
+ vdev->device_endian = VIRTIO_DEVICE_ENDIAN_UNKNOWN;
if (k->load_config) {
ret = k->load_config(qbus->parent, f);
@@ -926,12 +1012,18 @@
return -1;
}
config_len = qemu_get_be32(f);
- if (config_len != vdev->config_len) {
- error_report("Unexpected config length 0x%x. Expected 0x%zx",
- config_len, vdev->config_len);
- return -1;
+
+ /*
+ * There are cases where the incoming config can be bigger or smaller
+ * than what we have; so load what we have space for, and skip
+ * any excess that's in the stream.
+ */
+ qemu_get_buffer(f, vdev->config, MIN(config_len, vdev->config_len));
+
+ while (config_len > vdev->config_len) {
+ qemu_get_byte(f);
+ config_len--;
}
- qemu_get_buffer(f, vdev->config, vdev->config_len);
num = qemu_get_be32(f);
@@ -951,18 +1043,7 @@
vdev->vq[i].notification = true;
if (vdev->vq[i].pa) {
- uint16_t nheads;
virtqueue_init(&vdev->vq[i]);
- nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
- /* Check it isn't doing very strange things with descriptor numbers. */
- if (nheads > vdev->vq[i].vring.num) {
- error_report("VQ %d size 0x%x Guest index 0x%x "
- "inconsistent with Host index 0x%x: delta 0x%x",
- i, vdev->vq[i].vring.num,
- vring_avail_idx(&vdev->vq[i]),
- vdev->vq[i].last_avail_idx, nheads);
- return -1;
- }
} else if (vdev->vq[i].last_avail_idx) {
error_report("VQ %d address 0x0 "
"inconsistent with Host index 0x%x",
@@ -977,6 +1058,40 @@
}
virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
+
+ if (vdc->load != NULL) {
+ ret = vdc->load(vdev, f, version_id);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ /* Subsections */
+ ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
+ if (ret) {
+ return ret;
+ }
+
+ if (vdev->device_endian == VIRTIO_DEVICE_ENDIAN_UNKNOWN) {
+ vdev->device_endian = virtio_default_endian();
+ }
+
+ for (i = 0; i < num; i++) {
+ if (vdev->vq[i].pa) {
+ uint16_t nheads;
+ nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+ /* Check it isn't doing strange things with descriptor numbers. */
+ if (nheads > vdev->vq[i].vring.num) {
+ error_report("VQ %d size 0x%x Guest index 0x%x "
+ "inconsistent with Host index 0x%x: delta 0x%x",
+ i, vdev->vq[i].vring.num,
+ vring_avail_idx(&vdev->vq[i]),
+ vdev->vq[i].last_avail_idx, nheads);
+ return -1;
+ }
+ }
+ }
+
return 0;
}
@@ -1034,6 +1149,7 @@
}
vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
vdev);
+ vdev->device_endian = virtio_default_endian();
}
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 55ca676..e9eb831 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -29,6 +29,7 @@
MemoryRegion *mr);
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr);
int qemu_get_ram_fd(ram_addr_t addr);
+void *qemu_get_ram_block_host_ptr(ram_addr_t addr);
void *qemu_get_ram_ptr(ram_addr_t addr);
void qemu_ram_free(ram_addr_t addr);
void qemu_ram_free_from_ptr(ram_addr_t addr);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 486e98f..1c0c382 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -294,43 +294,6 @@
int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
-#define PC_Q35_COMPAT_2_0 \
- PC_COMPAT_2_0, \
- {\
- .driver = "ICH9-LPC",\
- .property = "memory-hotplug-support",\
- .value = "off",\
- },{\
- .driver = "xio3130-downstream",\
- .property = COMPAT_PROP_PCP,\
- .value = "off",\
- },{\
- .driver = "ioh3420",\
- .property = COMPAT_PROP_PCP,\
- .value = "off",\
- }
-
-#define PC_Q35_COMPAT_1_7 \
- PC_COMPAT_1_7, \
- PC_Q35_COMPAT_2_0, \
- {\
- .driver = "hpet",\
- .property = HPET_INTCAP,\
- .value = stringify(4),\
- }
-
-#define PC_Q35_COMPAT_1_6 \
- PC_COMPAT_1_6, \
- PC_Q35_COMPAT_1_7
-
-#define PC_Q35_COMPAT_1_5 \
- PC_COMPAT_1_5, \
- PC_Q35_COMPAT_1_6
-
-#define PC_Q35_COMPAT_1_4 \
- PC_COMPAT_1_4, \
- PC_Q35_COMPAT_1_5
-
#define PC_COMPAT_2_0 \
{\
.driver = "virtio-scsi-pci",\
@@ -358,7 +321,7 @@
},\
{\
.driver = "pci-serial-2x",\
- .property = "prof_if",\
+ .property = "prog_if",\
.value = stringify(0),\
},\
{\
@@ -370,6 +333,19 @@
.driver = "virtio-net-pci",\
.property = "guest_announce",\
.value = "off",\
+ },\
+ {\
+ .driver = "ICH9-LPC",\
+ .property = "memory-hotplug-support",\
+ .value = "off",\
+ },{\
+ .driver = "xio3130-downstream",\
+ .property = COMPAT_PROP_PCP,\
+ .value = "off",\
+ },{\
+ .driver = "ioh3420",\
+ .property = COMPAT_PROP_PCP,\
+ .value = "off",\
}
#define PC_COMPAT_1_7 \
@@ -383,6 +359,11 @@
.driver = "PIIX4_PM",\
.property = "acpi-pci-hotplug-with-bridge-support",\
.value = "off",\
+ },\
+ {\
+ .driver = "hpet",\
+ .property = HPET_INTCAP,\
+ .value = stringify(4),\
}
#define PC_COMPAT_1_6 \
diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
new file mode 100644
index 0000000..46456fd
--- /dev/null
+++ b/include/hw/virtio/virtio-access.h
@@ -0,0 +1,170 @@
+/*
+ * Virtio Accessor Support: In case your target can change endian.
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * Rusty Russell <rusty@au.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#ifndef _QEMU_VIRTIO_ACCESS_H
+#define _QEMU_VIRTIO_ACCESS_H
+#include "hw/virtio/virtio.h"
+#include "exec/address-spaces.h"
+
+static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
+{
+#if defined(TARGET_IS_BIENDIAN)
+ return virtio_is_big_endian(vdev);
+#elif defined(TARGET_WORDS_BIGENDIAN)
+ return true;
+#else
+ return false;
+#endif
+}
+
+static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ return lduw_be_phys(&address_space_memory, pa);
+ }
+ return lduw_le_phys(&address_space_memory, pa);
+}
+
+static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ return ldl_be_phys(&address_space_memory, pa);
+ }
+ return ldl_le_phys(&address_space_memory, pa);
+}
+
+static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ return ldq_be_phys(&address_space_memory, pa);
+ }
+ return ldq_le_phys(&address_space_memory, pa);
+}
+
+static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa,
+ uint16_t value)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ stw_be_phys(&address_space_memory, pa, value);
+ } else {
+ stw_le_phys(&address_space_memory, pa, value);
+ }
+}
+
+static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa,
+ uint32_t value)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ stl_be_phys(&address_space_memory, pa, value);
+ } else {
+ stl_le_phys(&address_space_memory, pa, value);
+ }
+}
+
+static inline void virtio_stw_p(VirtIODevice *vdev, void *ptr, uint16_t v)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ stw_be_p(ptr, v);
+ } else {
+ stw_le_p(ptr, v);
+ }
+}
+
+static inline void virtio_stl_p(VirtIODevice *vdev, void *ptr, uint32_t v)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ stl_be_p(ptr, v);
+ } else {
+ stl_le_p(ptr, v);
+ }
+}
+
+static inline void virtio_stq_p(VirtIODevice *vdev, void *ptr, uint64_t v)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ stq_be_p(ptr, v);
+ } else {
+ stq_le_p(ptr, v);
+ }
+}
+
+static inline int virtio_lduw_p(VirtIODevice *vdev, const void *ptr)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ return lduw_be_p(ptr);
+ } else {
+ return lduw_le_p(ptr);
+ }
+}
+
+static inline int virtio_ldl_p(VirtIODevice *vdev, const void *ptr)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ return ldl_be_p(ptr);
+ } else {
+ return ldl_le_p(ptr);
+ }
+}
+
+static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
+{
+ if (virtio_access_is_big_endian(vdev)) {
+ return ldq_be_p(ptr);
+ } else {
+ return ldq_le_p(ptr);
+ }
+}
+
+static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return virtio_access_is_big_endian(vdev) ? s : bswap16(s);
+#else
+ return virtio_access_is_big_endian(vdev) ? bswap16(s) : s;
+#endif
+}
+
+static inline void virtio_tswap16s(VirtIODevice *vdev, uint16_t *s)
+{
+ *s = virtio_tswap16(vdev, *s);
+}
+
+static inline uint32_t virtio_tswap32(VirtIODevice *vdev, uint32_t s)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return virtio_access_is_big_endian(vdev) ? s : bswap32(s);
+#else
+ return virtio_access_is_big_endian(vdev) ? bswap32(s) : s;
+#endif
+}
+
+static inline void virtio_tswap32s(VirtIODevice *vdev, uint32_t *s)
+{
+ *s = virtio_tswap32(vdev, *s);
+}
+
+static inline uint64_t virtio_tswap64(VirtIODevice *vdev, uint64_t s)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return virtio_access_is_big_endian(vdev) ? s : bswap64(s);
+#else
+ return virtio_access_is_big_endian(vdev) ? bswap64(s) : s;
+#endif
+}
+
+static inline void virtio_tswap64s(VirtIODevice *vdev, uint64_t *s)
+{
+ *s = virtio_tswap64(vdev, *s);
+}
+#endif /* _QEMU_VIRTIO_ACCESS_H */
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 3e54e90..a60104c 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -104,6 +104,12 @@
#define VIRTIO_DEVICE(obj) \
OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE)
+enum virtio_device_endian {
+ VIRTIO_DEVICE_ENDIAN_UNKNOWN,
+ VIRTIO_DEVICE_ENDIAN_LITTLE,
+ VIRTIO_DEVICE_ENDIAN_BIG,
+};
+
struct VirtIODevice
{
DeviceState parent_obj;
@@ -121,6 +127,7 @@
bool vm_running;
VMChangeStateEntry *vmstate;
char *bus_name;
+ uint8_t device_endian;
};
typedef struct VirtioDeviceClass {
@@ -150,6 +157,8 @@
* must mask in frontend instead.
*/
void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
+ void (*save)(VirtIODevice *vdev, QEMUFile *f);
+ int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id);
} VirtioDeviceClass;
void virtio_init(VirtIODevice *vdev, const char *name,
@@ -184,7 +193,7 @@
void virtio_save(VirtIODevice *vdev, QEMUFile *f);
-int virtio_load(VirtIODevice *vdev, QEMUFile *f);
+int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id);
void virtio_notify_config(VirtIODevice *vdev);
@@ -253,4 +262,10 @@
bool set_handler);
void virtio_queue_notify_vq(VirtQueue *vq);
void virtio_irq(VirtQueue *vq);
+
+static inline bool virtio_is_big_endian(VirtIODevice *vdev)
+{
+ assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
+ return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG;
+}
#endif
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 4b352a2..1aafbf5 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -116,6 +116,7 @@
CPUUnassignedAccess do_unassigned_access;
void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
int is_write, int is_user, uintptr_t retaddr);
+ bool (*virtio_is_big_endian)(CPUState *cpu);
int (*memory_rw_debug)(CPUState *cpu, vaddr addr,
uint8_t *buf, int len, bool is_write);
void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 285c45b..d8539fd 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -146,11 +146,16 @@
*/
#define MAX_CPUMASK_BITS 255
-extern int nb_numa_nodes;
+extern int nb_numa_nodes; /* Number of NUMA nodes */
+extern int max_numa_nodeid; /* Highest specified NUMA node ID, plus one.
+ * For all nodes, nodeid < max_numa_nodeid
+ */
+
typedef struct node_info {
uint64_t node_mem;
DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS);
struct HostMemoryBackend *node_memdev;
+ bool present;
} NodeInfo;
extern NodeInfo numa_info[MAX_NODES];
void set_numa_nodes(void);
diff --git a/monitor.c b/monitor.c
index 5718d0b..799131b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -5441,3 +5441,10 @@
{ /* end of list */ }
},
};
+
+#ifndef TARGET_I386
+void qmp_rtc_reset_reinjection(Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
+}
+#endif
diff --git a/numa.c b/numa.c
index e471afe..2fde740 100644
--- a/numa.c
+++ b/numa.c
@@ -62,6 +62,11 @@
return;
}
+ if (numa_info[nodenr].present) {
+ error_setg(errp, "Duplicate NUMA nodeid: %" PRIu16, nodenr);
+ return;
+ }
+
for (cpus = node->cpus; cpus; cpus = cpus->next) {
if (cpus->value > MAX_CPUMASK_BITS) {
error_setg(errp, "CPU number %" PRIu16 " is bigger than %d",
@@ -106,6 +111,8 @@
numa_info[nodenr].node_mem = object_property_get_int(o, "size", NULL);
numa_info[nodenr].node_memdev = MEMORY_BACKEND(o);
}
+ numa_info[nodenr].present = true;
+ max_numa_nodeid = MAX(max_numa_nodeid, nodenr + 1);
}
int numa_init_func(QemuOpts *opts, void *opaque)
@@ -153,15 +160,30 @@
void set_numa_nodes(void)
{
+ int i;
+
+ assert(max_numa_nodeid <= MAX_NODES);
+
+ /* No support for sparse NUMA node IDs yet: */
+ for (i = max_numa_nodeid - 1; i >= 0; i--) {
+ /* Report large node IDs first, to make mistakes easier to spot */
+ if (!numa_info[i].present) {
+ error_report("numa: Node ID missing: %d", i);
+ exit(1);
+ }
+ }
+
+ /* This must be always true if all nodes are present: */
+ assert(nb_numa_nodes == max_numa_nodeid);
+
if (nb_numa_nodes > 0) {
uint64_t numa_total;
- int i;
if (nb_numa_nodes > MAX_NODES) {
nb_numa_nodes = MAX_NODES;
}
- /* If no memory size if given for any node, assume the default case
+ /* If no memory size is given for any node, assume the default case
* and distribute the available memory equally across all nodes
*/
for (i = 0; i < nb_numa_nodes; i++) {
@@ -172,7 +194,7 @@
if (i == nb_numa_nodes) {
uint64_t usedmem = 0;
- /* On Linux, the each node's border has to be 8MB aligned,
+ /* On Linux, each node's border has to be 8MB aligned,
* the final node gets the rest.
*/
for (i = 0; i < nb_numa_nodes - 1; i++) {
diff --git a/qapi-schema.json b/qapi-schema.json
index a83befc..b11aad2 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3468,3 +3468,15 @@
##
{ 'enum': 'GuestPanicAction',
'data': [ 'pause' ] }
+
+##
+# @rtc-reset-reinjection
+#
+# This command will reset the RTC interrupt reinjection backlog.
+# Can be used if another mechanism to synchronize guest time
+# is in effect, for example QEMU guest agent's guest-set-time
+# command.
+#
+# Since: 2.1
+##
+{ 'command': 'rtc-reset-reinjection' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 65218bc..1ea18b2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3675,3 +3675,26 @@
{ "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
]}
EQMP
+
+#if defined TARGET_I386
+ {
+ .name = "rtc-reset-reinjection",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_rtc_reset_reinjection,
+ },
+#endif
+
+SQMP
+rtc-reset-reinjection
+---------------------
+
+Reset the RTC interrupt reinjection backlog.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "rtc-reset-reinjection" }
+<- { "return": {} }
+
+EQMP
diff --git a/qom/cpu.c b/qom/cpu.c
index fada2d4..b32dd0a 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -196,6 +196,11 @@
return 0;
}
+bool target_words_bigendian(void);
+static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
+{
+ return target_words_bigendian();
+}
void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags)
@@ -334,6 +339,7 @@
k->write_elf64_note = cpu_common_write_elf64_note;
k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_register;
+ k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
dc->realize = cpu_common_realizefn;
/*
* Reason: CPUs still need special care by board code: wiring up
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index b728718..55ff935 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -531,14 +531,14 @@
TCGv_i64 high = tcg_temp_new_i64();
TCGv_i32 sr_ove = tcg_temp_local_new_i32();
int lab = gen_new_label();
- /* Calculate the each result. */
+ /* Calculate each result. */
tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
tcg_gen_mul_i64(result, tra, trb);
tcg_temp_free_i64(tra);
tcg_temp_free_i64(trb);
tcg_gen_shri_i64(high, result, TARGET_LONG_BITS);
- /* Overflow or not. */
+ /* Overflow or not. */
tcg_gen_brcondi_i64(TCG_COND_EQ, high, 0x00000000, lab);
tcg_gen_ori_tl(cpu_sr, cpu_sr, (SR_OV | SR_CY));
tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 08ae527..b64c652 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -29,6 +29,8 @@
#define TARGET_LONG_BITS 64
#define TARGET_PAGE_BITS 12
+#define TARGET_IS_BIENDIAN 1
+
/* Note that the official physical address space bits is 62-M where M
is implementation dependent. I've not looked up M for the set of
cpus we emulate at the system level. */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index a3bb336..2ab2810 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9597,6 +9597,18 @@
tlb_flush(s, 1);
}
+#ifndef CONFIG_USER_ONLY
+static bool ppc_cpu_is_big_endian(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ cpu_synchronize_state(cs);
+
+ return !msr_le;
+}
+#endif
+
static void ppc_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -9692,6 +9704,9 @@
#else
cc->gdb_core_xml_file = "power-core.xml";
#endif
+#ifndef CONFIG_USER_ONLY
+ cc->virtio_is_big_endian = ppc_cpu_is_big_endian;
+#endif
dc->fw_name = "PowerPC,UNKNOWN";
}
diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c
index 28e7359..e89e43c 100644
--- a/tests/test-string-output-visitor.c
+++ b/tests/test-string-output-visitor.c
@@ -21,12 +21,25 @@
typedef struct TestOutputVisitorData {
StringOutputVisitor *sov;
Visitor *ov;
+ bool human;
} TestOutputVisitorData;
static void visitor_output_setup(TestOutputVisitorData *data,
const void *unused)
{
- data->sov = string_output_visitor_new(false);
+ data->human = false;
+ data->sov = string_output_visitor_new(data->human);
+ g_assert(data->sov != NULL);
+
+ data->ov = string_output_get_visitor(data->sov);
+ g_assert(data->ov != NULL);
+}
+
+static void visitor_output_setup_human(TestOutputVisitorData *data,
+ const void *unused)
+{
+ data->human = true;
+ data->sov = string_output_visitor_new(data->human);
g_assert(data->sov != NULL);
data->ov = string_output_get_visitor(data->sov);
@@ -53,7 +66,11 @@
str = string_output_get_string(data->sov);
g_assert(str != NULL);
- g_assert_cmpstr(str, ==, "42");
+ if (data->human) {
+ g_assert_cmpstr(str, ==, "42 (0x2a)");
+ } else {
+ g_assert_cmpstr(str, ==, "42");
+ }
g_free(str);
}
@@ -78,8 +95,15 @@
str = string_output_get_string(data->sov);
g_assert(str != NULL);
- g_assert_cmpstr(str, ==,
- "0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807");
+ if (data->human) {
+ g_assert_cmpstr(str, ==,
+ "0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807 "
+ "(0x0-0x1,0x3-0x6,0x9-0x10,0x15-0x16,"
+ "0x7ffffffffffffffe-0x7fffffffffffffff)");
+ } else {
+ g_assert_cmpstr(str, ==,
+ "0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807");
+ }
g_free(str);
while (list) {
intList *tmp2;
@@ -125,6 +149,7 @@
const void *unused)
{
char *string = (char *) "Q E M U";
+ const char *string_human = "\"Q E M U\"";
Error *err = NULL;
char *str;
@@ -133,7 +158,11 @@
str = string_output_get_string(data->sov);
g_assert(str != NULL);
- g_assert_cmpstr(str, ==, string);
+ if (data->human) {
+ g_assert_cmpstr(str, ==, string_human);
+ } else {
+ g_assert_cmpstr(str, ==, string);
+ }
g_free(str);
}
@@ -150,7 +179,11 @@
str = string_output_get_string(data->sov);
g_assert(str != NULL);
- g_assert_cmpstr(str, ==, "");
+ if (data->human) {
+ g_assert_cmpstr(str, ==, "<null>");
+ } else {
+ g_assert_cmpstr(str, ==, "");
+ }
g_free(str);
}
@@ -162,12 +195,26 @@
EnumOne i;
for (i = 0; i < ENUM_ONE_MAX; i++) {
+ char *str_human;
+ int len;
+
visit_type_EnumOne(data->ov, &i, "unused", &err);
g_assert(!err);
+ len = strlen(EnumOne_lookup[i]) + 2;
+ str_human = g_malloc0(len);
+ str_human[0] = '"';
+ strncpy(str_human + 1, EnumOne_lookup[i], strlen(EnumOne_lookup[i]));
+ str_human[len - 1] = '"';
+
str = string_output_get_string(data->sov);
g_assert(str != NULL);
- g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
+ if (data->human) {
+ g_assert_cmpstr(str, ==, str_human);
+ } else {
+ g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
+ }
+ g_free(str_human);
g_free(str);
}
}
@@ -186,11 +233,15 @@
}
}
-static void output_visitor_test_add(const char *testpath,
- TestOutputVisitorData *data,
- void (*test_func)(TestOutputVisitorData *data, const void *user_data))
+static void
+output_visitor_test_add(const char *testpath,
+ TestOutputVisitorData *data,
+ void (*test_func)(TestOutputVisitorData *data,
+ const void *user_data),
+ bool human)
{
- g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
+ g_test_add(testpath, TestOutputVisitorData, data,
+ human ? visitor_output_setup_human : visitor_output_setup,
test_func, visitor_output_teardown);
}
@@ -201,21 +252,41 @@
g_test_init(&argc, &argv, NULL);
output_visitor_test_add("/string-visitor/output/int",
- &out_visitor_data, test_visitor_out_int);
+ &out_visitor_data, test_visitor_out_int, false);
+ output_visitor_test_add("/string-visitor/output/int",
+ &out_visitor_data, test_visitor_out_int, true);
output_visitor_test_add("/string-visitor/output/bool",
- &out_visitor_data, test_visitor_out_bool);
+ &out_visitor_data, test_visitor_out_bool, false);
+ output_visitor_test_add("/string-visitor/output/bool",
+ &out_visitor_data, test_visitor_out_bool, true);
output_visitor_test_add("/string-visitor/output/number",
- &out_visitor_data, test_visitor_out_number);
+ &out_visitor_data, test_visitor_out_number, false);
+ output_visitor_test_add("/string-visitor/output/number",
+ &out_visitor_data, test_visitor_out_number, true);
output_visitor_test_add("/string-visitor/output/string",
- &out_visitor_data, test_visitor_out_string);
+ &out_visitor_data, test_visitor_out_string, false);
+ output_visitor_test_add("/string-visitor/output/string",
+ &out_visitor_data, test_visitor_out_string, true);
output_visitor_test_add("/string-visitor/output/no-string",
- &out_visitor_data, test_visitor_out_no_string);
+ &out_visitor_data, test_visitor_out_no_string,
+ false);
+ output_visitor_test_add("/string-visitor/output/no-string",
+ &out_visitor_data, test_visitor_out_no_string,
+ true);
output_visitor_test_add("/string-visitor/output/enum",
- &out_visitor_data, test_visitor_out_enum);
+ &out_visitor_data, test_visitor_out_enum, false);
+ output_visitor_test_add("/string-visitor/output/enum",
+ &out_visitor_data, test_visitor_out_enum, true);
output_visitor_test_add("/string-visitor/output/enum-errors",
- &out_visitor_data, test_visitor_out_enum_errors);
+ &out_visitor_data, test_visitor_out_enum_errors,
+ false);
+ output_visitor_test_add("/string-visitor/output/enum-errors",
+ &out_visitor_data, test_visitor_out_enum_errors,
+ true);
output_visitor_test_add("/string-visitor/output/intList",
- &out_visitor_data, test_visitor_out_intList);
+ &out_visitor_data, test_visitor_out_intList, false);
+ output_visitor_test_add("/string-visitor/output/intList",
+ &out_visitor_data, test_visitor_out_intList, true);
g_test_run();
diff --git a/vl.c b/vl.c
index a1686ef..41ddcd26 100644
--- a/vl.c
+++ b/vl.c
@@ -196,6 +196,7 @@
QTAILQ_HEAD_INITIALIZER(fw_boot_order);
int nb_numa_nodes;
+int max_numa_nodeid;
NodeInfo numa_info[MAX_NODES];
uint8_t qemu_uuid[16];
@@ -2984,10 +2985,12 @@
for (i = 0; i < MAX_NODES; i++) {
numa_info[i].node_mem = 0;
+ numa_info[i].present = false;
bitmap_zero(numa_info[i].node_cpu, MAX_CPUMASK_BITS);
}
nb_numa_nodes = 0;
+ max_numa_nodeid = 0;
nb_nics = 0;
bdrv_init_with_whitelist();