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>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJTsEGpAAoJECgfDbjSjVRpAEMIALoOOk6KyDZ30tX7iretmXIG
 MM8BG8uvox3KdPN/A2VHCVQyM1s8DSsBAoU3hL7sL5zBkPpOYwlOxJA0Bf9aw8+o
 2MIgpFr2ifd0ukmDZkBFEwmyo+XMYDXrYiRAlSTYqpEaidRr82mHteR0lblHz4gC
 wMjn+MiXaBPkTXqPymKGseIslyNipPLkV4Y5h0ycExLBYK2VwVSG/Jr2d3rp0ZU1
 z7MOeME6qw6PdhQBXzX2FyByBY2e2z4/jzbAWP2sPmqb/cwPKeacnTOKip58PWIC
 xyHD4XgAp2ZpwKMZkJbNEF1GQPI72duASfFiACkUgfXl7s8BpSm0rrD4auhqLCY=
 =aFOP
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2014-06-29 18:09:51 +01:00
commit 9328cfd2fe
32 changed files with 854 additions and 282 deletions

View File

@ -78,14 +78,14 @@ Depending on the request type, payload can be:
Padding: 32-bit Padding: 32-bit
A region is: 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 Guest address: a 64-bit guest address of the region
Size: a 64-bit size Size: a 64-bit size
User address: a 64-bit user address 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: In QEMU the vhost-user message is implemented with the following struct:
@ -132,7 +132,7 @@ Message types
* VHOST_USER_GET_FEATURES * VHOST_USER_GET_FEATURES
Id: 2 Id: 1
Equivalent ioctl: VHOST_GET_FEATURES Equivalent ioctl: VHOST_GET_FEATURES
Master payload: N/A Master payload: N/A
Slave payload: u64 Slave payload: u64
@ -141,7 +141,7 @@ Message types
* VHOST_USER_SET_FEATURES * VHOST_USER_SET_FEATURES
Id: 3 Id: 2
Ioctl: VHOST_SET_FEATURES Ioctl: VHOST_SET_FEATURES
Master payload: u64 Master payload: u64
@ -149,7 +149,7 @@ Message types
* VHOST_USER_SET_OWNER * VHOST_USER_SET_OWNER
Id: 4 Id: 3
Equivalent ioctl: VHOST_SET_OWNER Equivalent ioctl: VHOST_SET_OWNER
Master payload: N/A Master payload: N/A
@ -159,7 +159,7 @@ Message types
* VHOST_USER_RESET_OWNER * VHOST_USER_RESET_OWNER
Id: 5 Id: 4
Equivalent ioctl: VHOST_RESET_OWNER Equivalent ioctl: VHOST_RESET_OWNER
Master payload: N/A Master payload: N/A
@ -168,7 +168,7 @@ Message types
* VHOST_USER_SET_MEM_TABLE * VHOST_USER_SET_MEM_TABLE
Id: 6 Id: 5
Equivalent ioctl: VHOST_SET_MEM_TABLE Equivalent ioctl: VHOST_SET_MEM_TABLE
Master payload: memory regions description Master payload: memory regions description
@ -179,7 +179,7 @@ Message types
* VHOST_USER_SET_LOG_BASE * VHOST_USER_SET_LOG_BASE
Id: 7 Id: 6
Equivalent ioctl: VHOST_SET_LOG_BASE Equivalent ioctl: VHOST_SET_LOG_BASE
Master payload: u64 Master payload: u64
@ -187,7 +187,7 @@ Message types
* VHOST_USER_SET_LOG_FD * VHOST_USER_SET_LOG_FD
Id: 8 Id: 7
Equivalent ioctl: VHOST_SET_LOG_FD Equivalent ioctl: VHOST_SET_LOG_FD
Master payload: N/A Master payload: N/A
@ -195,7 +195,7 @@ Message types
* VHOST_USER_SET_VRING_NUM * VHOST_USER_SET_VRING_NUM
Id: 9 Id: 8
Equivalent ioctl: VHOST_SET_VRING_NUM Equivalent ioctl: VHOST_SET_VRING_NUM
Master payload: vring state description Master payload: vring state description
@ -203,7 +203,7 @@ Message types
* VHOST_USER_SET_VRING_ADDR * VHOST_USER_SET_VRING_ADDR
Id: 10 Id: 9
Equivalent ioctl: VHOST_SET_VRING_ADDR Equivalent ioctl: VHOST_SET_VRING_ADDR
Master payload: vring address description Master payload: vring address description
Slave payload: N/A Slave payload: N/A
@ -212,7 +212,7 @@ Message types
* VHOST_USER_SET_VRING_BASE * VHOST_USER_SET_VRING_BASE
Id: 11 Id: 10
Equivalent ioctl: VHOST_SET_VRING_BASE Equivalent ioctl: VHOST_SET_VRING_BASE
Master payload: vring state description Master payload: vring state description
@ -220,7 +220,7 @@ Message types
* VHOST_USER_GET_VRING_BASE * VHOST_USER_GET_VRING_BASE
Id: 12 Id: 11
Equivalent ioctl: VHOST_USER_GET_VRING_BASE Equivalent ioctl: VHOST_USER_GET_VRING_BASE
Master payload: vring state description Master payload: vring state description
Slave payload: vring state description Slave payload: vring state description
@ -229,7 +229,7 @@ Message types
* VHOST_USER_SET_VRING_KICK * VHOST_USER_SET_VRING_KICK
Id: 13 Id: 12
Equivalent ioctl: VHOST_SET_VRING_KICK Equivalent ioctl: VHOST_SET_VRING_KICK
Master payload: u64 Master payload: u64
@ -242,7 +242,7 @@ Message types
* VHOST_USER_SET_VRING_CALL * VHOST_USER_SET_VRING_CALL
Id: 14 Id: 13
Equivalent ioctl: VHOST_SET_VRING_CALL Equivalent ioctl: VHOST_SET_VRING_CALL
Master payload: u64 Master payload: u64
@ -255,7 +255,7 @@ Message types
* VHOST_USER_SET_VRING_ERR * VHOST_USER_SET_VRING_ERR
Id: 15 Id: 14
Equivalent ioctl: VHOST_SET_VRING_ERR Equivalent ioctl: VHOST_SET_VRING_ERR
Master payload: u64 Master payload: u64

15
exec.c
View File

@ -1456,6 +1456,13 @@ int qemu_get_ram_fd(ram_addr_t addr)
return block->fd; 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. /* Return a host pointer to ram allocated with qemu_ram_alloc.
With the exception of the softmmu code in this file, this should 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, only be used for local memory (e.g. video ram) that the device owns,
@ -2752,14 +2759,12 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
} }
#endif #endif
#if !defined(CONFIG_USER_ONLY)
/* /*
* A helper function for the _utterly broken_ virtio device model to find out if * 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! * it's running on a big endian machine. Don't do this at home kids!
*/ */
bool virtio_is_big_endian(void); bool target_words_bigendian(void);
bool virtio_is_big_endian(void) bool target_words_bigendian(void)
{ {
#if defined(TARGET_WORDS_BIGENDIAN) #if defined(TARGET_WORDS_BIGENDIAN)
return true; return true;
@ -2768,8 +2773,6 @@ bool virtio_is_big_endian(void)
#endif #endif
} }
#endif
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
bool cpu_physical_memory_is_io(hwaddr phys_addr) bool cpu_physical_memory_is_io(hwaddr phys_addr)
{ {

View File

@ -19,6 +19,7 @@
#include "fsdev/qemu-fsdev.h" #include "fsdev/qemu-fsdev.h"
#include "virtio-9p-xattr.h" #include "virtio-9p-xattr.h"
#include "virtio-9p-coth.h" #include "virtio-9p-coth.h"
#include "hw/virtio/virtio-access.h"
static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features) static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
{ {
@ -34,7 +35,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
len = strlen(s->tag); len = strlen(s->tag);
cfg = g_malloc0(sizeof(struct virtio_9p_config) + len); 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 */ /* We don't copy the terminating null to config space */
memcpy(cfg->tag, s->tag, len); memcpy(cfg->tag, s->tag, len);
memcpy(config, cfg, s->config_size); memcpy(config, cfg, s->config_size);

View File

@ -27,6 +27,7 @@
# include <scsi/sg.h> # include <scsi/sg.h>
#endif #endif
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s) static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
{ {
@ -88,7 +89,8 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
trace_virtio_blk_rw_complete(req, ret); trace_virtio_blk_rw_complete(req, ret);
if (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)) if (virtio_blk_handle_rw_error(req, -ret, is_read))
return; return;
} }
@ -130,6 +132,8 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
{ {
int status = VIRTIO_BLK_S_OK; int status = VIRTIO_BLK_S_OK;
struct virtio_scsi_inhdr *scsi = NULL; struct virtio_scsi_inhdr *scsi = NULL;
VirtIODevice *vdev = VIRTIO_DEVICE(blk);
#ifdef __linux__ #ifdef __linux__
int i; int i;
struct sg_io_hdr hdr; struct sg_io_hdr hdr;
@ -224,12 +228,12 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
hdr.status = CHECK_CONDITION; hdr.status = CHECK_CONDITION;
} }
stl_p(&scsi->errors, virtio_stl_p(vdev, &scsi->errors,
hdr.status | (hdr.msg_status << 8) | hdr.status | (hdr.msg_status << 8) |
(hdr.host_status << 16) | (hdr.driver_status << 24)); (hdr.host_status << 16) | (hdr.driver_status << 24));
stl_p(&scsi->residual, hdr.resid); virtio_stl_p(vdev, &scsi->residual, hdr.resid);
stl_p(&scsi->sense_len, hdr.sb_len_wr); virtio_stl_p(vdev, &scsi->sense_len, hdr.sb_len_wr);
stl_p(&scsi->data_len, hdr.dxfer_len); virtio_stl_p(vdev, &scsi->data_len, hdr.dxfer_len);
return status; return status;
#else #else
@ -239,7 +243,7 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
fail: fail:
/* Just put anything nonzero so that the ioctl fails in the guest. */ /* Just put anything nonzero so that the ioctl fails in the guest. */
if (scsi) { if (scsi) {
stl_p(&scsi->errors, 255); virtio_stl_p(vdev, &scsi->errors, 255);
} }
return status; return status;
} }
@ -289,7 +293,7 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
BlockRequest *blkreq; BlockRequest *blkreq;
uint64_t sector; 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); bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
@ -323,7 +327,7 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
{ {
uint64_t sector; 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); bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
@ -374,7 +378,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
- sizeof(struct virtio_blk_inhdr); - sizeof(struct virtio_blk_inhdr);
iov_discard_back(in_iov, &in_num, 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) { if (type & VIRTIO_BLK_T_FLUSH) {
virtio_blk_handle_flush(req, mrb); virtio_blk_handle_flush(req, mrb);
@ -504,12 +508,12 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
bdrv_get_geometry(s->bs, &capacity); bdrv_get_geometry(s->bs, &capacity);
memset(&blkcfg, 0, sizeof(blkcfg)); memset(&blkcfg, 0, sizeof(blkcfg));
stq_p(&blkcfg.capacity, capacity); virtio_stq_p(vdev, &blkcfg.capacity, capacity);
stl_p(&blkcfg.seg_max, 128 - 2); virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
stw_p(&blkcfg.cylinders, s->conf->cyls); virtio_stw_p(vdev, &blkcfg.cylinders, s->conf->cyls);
stl_p(&blkcfg.blk_size, blk_size); virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
stw_p(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); virtio_stw_p(vdev, &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_stw_p(vdev, &blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
blkcfg.heads = s->conf->heads; blkcfg.heads = s->conf->heads;
/* /*
* We must ensure that the block device capacity is a multiple of * We must ensure that the block device capacity is a multiple of
@ -611,11 +615,15 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
static void virtio_blk_save(QEMUFile *f, void *opaque) static void virtio_blk_save(QEMUFile *f, void *opaque)
{ {
VirtIOBlock *s = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
VirtIODevice *vdev = VIRTIO_DEVICE(s);
VirtIOBlockReq *req = s->rq;
virtio_save(vdev, f); 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) { while (req) {
qemu_put_sbyte(f, 1); qemu_put_sbyte(f, 1);
@ -630,16 +638,18 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
{ {
VirtIOBlock *s = opaque; VirtIOBlock *s = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(s); VirtIODevice *vdev = VIRTIO_DEVICE(s);
int ret;
if (version_id != 2) if (version_id != 2)
return -EINVAL; return -EINVAL;
ret = virtio_load(vdev, f); return virtio_load(vdev, f, version_id);
if (ret) {
return ret;
} }
static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
int version_id)
{
VirtIOBlock *s = VIRTIO_BLK(vdev);
while (qemu_get_sbyte(f)) { while (qemu_get_sbyte(f)) {
VirtIOBlockReq *req = virtio_blk_alloc_request(s); VirtIOBlockReq *req = virtio_blk_alloc_request(s);
qemu_get_buffer(f, (unsigned char *)req->elem, qemu_get_buffer(f, (unsigned char *)req->elem,
@ -799,6 +809,8 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data)
vdc->get_features = virtio_blk_get_features; vdc->get_features = virtio_blk_get_features;
vdc->set_status = virtio_blk_set_status; vdc->set_status = virtio_blk_set_status;
vdc->reset = virtio_blk_reset; vdc->reset = virtio_blk_reset;
vdc->save = virtio_blk_save_device;
vdc->load = virtio_blk_load_device;
} }
static const TypeInfo virtio_device_info = { static const TypeInfo virtio_device_info = {

View File

@ -24,6 +24,7 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "trace.h" #include "trace.h"
#include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-serial.h"
#include "hw/virtio/virtio-access.h"
static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
{ {
@ -183,11 +184,12 @@ static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id, static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id,
uint16_t event, uint16_t value) uint16_t event, uint16_t value)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
struct virtio_console_control cpkt; struct virtio_console_control cpkt;
stl_p(&cpkt.id, port_id); virtio_stl_p(vdev, &cpkt.id, port_id);
stw_p(&cpkt.event, event); virtio_stw_p(vdev, &cpkt.event, event);
stw_p(&cpkt.value, value); virtio_stw_p(vdev, &cpkt.value, value);
trace_virtio_serial_send_control_event(port_id, event, value); trace_virtio_serial_send_control_event(port_id, event, value);
return send_control_msg(vser, &cpkt, sizeof(cpkt)); return send_control_msg(vser, &cpkt, sizeof(cpkt));
@ -278,6 +280,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
/* Guest wants to notify us of some event */ /* Guest wants to notify us of some event */
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
struct VirtIOSerialPort *port; struct VirtIOSerialPort *port;
VirtIOSerialPortClass *vsc; VirtIOSerialPortClass *vsc;
struct virtio_console_control cpkt, *gcpkt; struct virtio_console_control cpkt, *gcpkt;
@ -291,8 +294,8 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
return; return;
} }
cpkt.event = lduw_p(&gcpkt->event); cpkt.event = virtio_lduw_p(vdev, &gcpkt->event);
cpkt.value = lduw_p(&gcpkt->value); cpkt.value = virtio_lduw_p(vdev, &gcpkt->value);
trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value); trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
@ -312,10 +315,10 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
return; 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) { if (!port) {
error_report("virtio-serial-bus: Unexpected port id %u for device %s", 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; return;
} }
@ -342,9 +345,9 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
} }
if (port->name) { if (port->name) {
stl_p(&cpkt.id, port->id); virtio_stl_p(vdev, &cpkt.id, port->id);
stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME); virtio_stw_p(vdev, &cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
stw_p(&cpkt.value, 1); virtio_stw_p(vdev, &cpkt.value, 1);
buffer_len = sizeof(cpkt) + strlen(port->name) + 1; buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
buffer = g_malloc(buffer_len); buffer = g_malloc(buffer_len);
@ -510,18 +513,25 @@ static void vser_reset(VirtIODevice *vdev)
vser = VIRTIO_SERIAL(vdev); vser = VIRTIO_SERIAL(vdev);
guest_reset(vser); 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) 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; VirtIOSerialPort *port;
uint32_t nr_active_ports; uint32_t nr_active_ports;
unsigned int i, max_nr_ports; unsigned int i, max_nr_ports;
/* The virtio device */
virtio_save(VIRTIO_DEVICE(s), f);
/* The config space */ /* The config space */
qemu_put_be16s(f, &s->config.cols); qemu_put_be16s(f, &s->config.cols);
qemu_put_be16s(f, &s->config.rows); qemu_put_be16s(f, &s->config.rows);
@ -529,7 +539,7 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &s->config.max_nr_ports); qemu_put_be32s(f, &s->config.max_nr_ports);
/* The ports map */ /* 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++) { for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
qemu_put_be32s(f, &s->ports_map[i]); qemu_put_be32s(f, &s->ports_map[i]);
} }
@ -659,36 +669,39 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) 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) { if (version_id > 3) {
return -EINVAL; return -EINVAL;
} }
/* The virtio device */ /* The virtio device */
ret = virtio_load(VIRTIO_DEVICE(s), f); return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
if (ret) {
return ret;
} }
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) { if (version_id < 2) {
return 0; return 0;
} }
/* The config space */ /* Unused */
qemu_get_be16s(f, &s->config.cols); qemu_get_be16s(f, (uint16_t *) &tmp);
qemu_get_be16s(f, &s->config.rows); 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++) { for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
qemu_get_be32s(f, &ports_map); qemu_get_be32s(f, &ports_map);
@ -751,9 +764,10 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
/* This function is only used if a port id is not provided by the user */ /* This function is only used if a port id is not provided by the user */
static uint32_t find_free_port_id(VirtIOSerial *vser) static uint32_t find_free_port_id(VirtIOSerial *vser)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
unsigned int i, max_nr_ports; 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++) { for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
uint32_t map, bit; uint32_t map, bit;
@ -806,6 +820,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev)); VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
VirtIODevice *vdev = VIRTIO_DEVICE(bus->vser);
int max_nr_ports; int max_nr_ports;
bool plugging_port0; bool plugging_port0;
Error *err = NULL; Error *err = NULL;
@ -841,7 +856,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
} }
} }
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) { if (port->id >= max_nr_ports) {
error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, " error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
"max. allowed: %u", max_nr_ports - 1); "max. allowed: %u", max_nr_ports - 1);
@ -863,7 +878,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
add_port(port->vser, port->id); add_port(port->vser, port->id);
/* Send an update to the guest about this new port added */ /* 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) static void virtser_port_device_unrealize(DeviceState *dev, Error **errp)
@ -942,7 +957,8 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output); 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) vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
* sizeof(vser->ports_map[0])); * sizeof(vser->ports_map[0]));
/* /*
@ -1019,6 +1035,8 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
vdc->get_config = get_config; vdc->get_config = get_config;
vdc->set_status = set_status; vdc->set_status = set_status;
vdc->reset = vser_reset; vdc->reset = vser_reset;
vdc->save = virtio_serial_save_device;
vdc->load = virtio_serial_load_device;
} }
static const TypeInfo virtio_device_info = { static const TypeInfo virtio_device_info = {

View File

@ -392,6 +392,11 @@ static void pc_init_pci_no_kvmclock(MachineState *machine)
has_pci_info = false; has_pci_info = false;
has_acpi_build = false; has_acpi_build = false;
smbios_defaults = 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); x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
enable_compat_apic_id_mode(); enable_compat_apic_id_mode();
pc_init1(machine, 1, 0); pc_init1(machine, 1, 0);
@ -402,6 +407,11 @@ static void pc_init_isa(MachineState *machine)
has_pci_info = false; has_pci_info = false;
has_acpi_build = false; has_acpi_build = false;
smbios_defaults = 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) { if (!machine->cpu_model) {
machine->cpu_model = "486"; machine->cpu_model = "486";
} }

View File

@ -361,7 +361,7 @@ static QEMUMachine pc_q35_machine_v2_0 = {
.name = "pc-q35-2.0", .name = "pc-q35-2.0",
.init = pc_q35_init_2_0, .init = pc_q35_init_2_0,
.compat_props = (GlobalProperty[]) { .compat_props = (GlobalProperty[]) {
PC_Q35_COMPAT_2_0, PC_COMPAT_2_0,
{ /* end of list */ } { /* end of list */ }
}, },
}; };
@ -373,7 +373,7 @@ static QEMUMachine pc_q35_machine_v1_7 = {
.name = "pc-q35-1.7", .name = "pc-q35-1.7",
.init = pc_q35_init_1_7, .init = pc_q35_init_1_7,
.compat_props = (GlobalProperty[]) { .compat_props = (GlobalProperty[]) {
PC_Q35_COMPAT_1_7, PC_COMPAT_1_7,
{ /* end of list */ } { /* end of list */ }
}, },
}; };
@ -385,7 +385,7 @@ static QEMUMachine pc_q35_machine_v1_6 = {
.name = "pc-q35-1.6", .name = "pc-q35-1.6",
.init = pc_q35_init_1_6, .init = pc_q35_init_1_6,
.compat_props = (GlobalProperty[]) { .compat_props = (GlobalProperty[]) {
PC_Q35_COMPAT_1_6, PC_COMPAT_1_6,
{ /* end of list */ } { /* end of list */ }
}, },
}; };
@ -395,7 +395,7 @@ static QEMUMachine pc_q35_machine_v1_5 = {
.name = "pc-q35-1.5", .name = "pc-q35-1.5",
.init = pc_q35_init_1_5, .init = pc_q35_init_1_5,
.compat_props = (GlobalProperty[]) { .compat_props = (GlobalProperty[]) {
PC_Q35_COMPAT_1_5, PC_COMPAT_1_5,
{ /* end of list */ } { /* end of list */ }
}, },
}; };
@ -409,7 +409,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
.name = "pc-q35-1.4", .name = "pc-q35-1.4",
.init = pc_q35_init_1_4, .init = pc_q35_init_1_4,
.compat_props = (GlobalProperty[]) { .compat_props = (GlobalProperty[]) {
PC_Q35_COMPAT_1_4, PC_COMPAT_1_4,
{ /* end of list */ } { /* end of list */ }
}, },
}; };

View File

@ -275,6 +275,19 @@ static void vhost_net_stop_one(struct vhost_net *net,
vhost_dev_disable_notifiers(&net->dev, dev); 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 vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
int total_queues) int total_queues)
{ {
@ -283,6 +296,12 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
int r, i = 0; 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) { if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers"); error_report("binding does not support guest notifiers");
r = -ENOSYS; r = -ENOSYS;

View File

@ -23,6 +23,7 @@
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "qapi/qmp/qjson.h" #include "qapi/qmp/qjson.h"
#include "qapi-event.h" #include "qapi-event.h"
#include "hw/virtio/virtio-access.h"
#define VIRTIO_NET_VM_VERSION 11 #define VIRTIO_NET_VM_VERSION 11
@ -72,8 +73,8 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
VirtIONet *n = VIRTIO_NET(vdev); VirtIONet *n = VIRTIO_NET(vdev);
struct virtio_net_config netcfg; struct virtio_net_config netcfg;
stw_p(&netcfg.status, n->status); virtio_stw_p(vdev, &netcfg.status, n->status);
stw_p(&netcfg.max_virtqueue_pairs, n->max_queues); virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues);
memcpy(netcfg.mac, n->mac, ETH_ALEN); memcpy(netcfg.mac, n->mac, ETH_ALEN);
memcpy(config, &netcfg, n->config_size); memcpy(config, &netcfg, n->config_size);
} }
@ -604,6 +605,7 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
struct iovec *iov, unsigned int iov_cnt) struct iovec *iov, unsigned int iov_cnt)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(n);
struct virtio_net_ctrl_mac mac_data; struct virtio_net_ctrl_mac mac_data;
size_t s; size_t s;
NetClientState *nc = qemu_get_queue(n->nic); NetClientState *nc = qemu_get_queue(n->nic);
@ -632,7 +634,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
sizeof(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)) { if (s != sizeof(mac_data.entries)) {
goto error; goto error;
} }
@ -659,7 +661,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
sizeof(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)) { if (s != sizeof(mac_data.entries)) {
goto error; goto error;
} }
@ -699,12 +701,13 @@ error:
static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
struct iovec *iov, unsigned int iov_cnt) struct iovec *iov, unsigned int iov_cnt)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(n);
uint16_t vid; uint16_t vid;
size_t s; size_t s;
NetClientState *nc = qemu_get_queue(n->nic); NetClientState *nc = qemu_get_queue(n->nic);
s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid)); 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)) { if (s != sizeof(vid)) {
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
} }
@ -758,7 +761,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR; 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 || if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
@ -875,6 +878,14 @@ static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
return 1; 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 /* 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 * 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 * causes dhclient to get upset. Fedora's carried a patch for ages to
@ -910,6 +921,7 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
void *wbuf = (void *)buf; void *wbuf = (void *)buf;
work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
size - 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)); iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
} else { } else {
struct virtio_net_hdr hdr = { struct virtio_net_hdr hdr = {
@ -1059,7 +1071,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
} }
if (mhdr_cnt) { if (mhdr_cnt) {
stw_p(&mhdr.num_buffers, i); virtio_stw_p(vdev, &mhdr.num_buffers, i);
iov_from_buf(mhdr_sg, mhdr_cnt, iov_from_buf(mhdr_sg, mhdr_cnt,
0, 0,
&mhdr.num_buffers, sizeof mhdr.num_buffers); &mhdr.num_buffers, sizeof mhdr.num_buffers);
@ -1118,6 +1130,14 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
exit(1); 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 * If host wants to see the guest header as is, we can
* pass it on unchanged. Otherwise, copy just the parts * pass it on unchanged. Otherwise, copy just the parts
@ -1297,7 +1317,6 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
static void virtio_net_save(QEMUFile *f, void *opaque) static void virtio_net_save(QEMUFile *f, void *opaque)
{ {
int i;
VirtIONet *n = opaque; VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIODevice *vdev = VIRTIO_DEVICE(n);
@ -1305,6 +1324,12 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
* it might keep writing to memory. */ * it might keep writing to memory. */
assert(!n->vhost_started); assert(!n->vhost_started);
virtio_save(vdev, f); 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_buffer(f, n->mac, ETH_ALEN);
qemu_put_be32(f, n->vqs[0].tx_waiting); qemu_put_be32(f, n->vqs[0].tx_waiting);
@ -1340,16 +1365,19 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{ {
VirtIONet *n = opaque; VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIODevice *vdev = VIRTIO_DEVICE(n);
int ret, i, link_down;
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
return -EINVAL; return -EINVAL;
ret = virtio_load(vdev, f); return virtio_load(vdev, f, version_id);
if (ret) {
return ret;
} }
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); qemu_get_buffer(f, n->mac, ETH_ALEN);
n->vqs[0].tx_waiting = qemu_get_be32(f); n->vqs[0].tx_waiting = qemu_get_be32(f);
@ -1694,6 +1722,8 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
vdc->set_status = virtio_net_set_status; vdc->set_status = virtio_net_set_status;
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; 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 = { static const TypeInfo virtio_net_info = {

View File

@ -19,6 +19,7 @@
#include <hw/scsi/scsi.h> #include <hw/scsi/scsi.h>
#include <block/scsi.h> #include <block/scsi.h>
#include <hw/virtio/virtio-bus.h> #include <hw/virtio/virtio-bus.h>
#include "hw/virtio/virtio-access.h"
typedef struct VirtIOSCSIReq { typedef struct VirtIOSCSIReq {
VirtIOSCSI *dev; VirtIOSCSI *dev;
@ -235,7 +236,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
req->resp.tmf.response = VIRTIO_SCSI_S_OK; 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) { switch (req->req.tmf.subtype) {
case VIRTIO_SCSI_T_TMF_ABORT_TASK: case VIRTIO_SCSI_T_TMF_ABORT_TASK:
case VIRTIO_SCSI_T_TMF_QUERY_TASK: case VIRTIO_SCSI_T_TMF_QUERY_TASK:
@ -346,7 +347,7 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
continue; continue;
} }
tswap32s(&req->req.tmf.type); virtio_tswap32s(vdev, &req->req.tmf.type);
if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) {
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
sizeof(VirtIOSCSICtrlTMFResp)) < 0) { sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
@ -384,6 +385,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
VirtIOSCSIReq *req = r->hba_private; VirtIOSCSIReq *req = r->hba_private;
uint8_t sense[SCSI_SENSE_BUF_SIZE]; uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint32_t sense_len; uint32_t sense_len;
VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
if (r->io_canceled) { if (r->io_canceled) {
return; return;
@ -392,14 +394,14 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
req->resp.cmd.response = VIRTIO_SCSI_S_OK; req->resp.cmd.response = VIRTIO_SCSI_S_OK;
req->resp.cmd.status = status; req->resp.cmd.status = status;
if (req->resp.cmd.status == GOOD) { if (req->resp.cmd.status == GOOD) {
req->resp.cmd.resid = tswap32(resid); req->resp.cmd.resid = virtio_tswap32(vdev, resid);
} else { } else {
req->resp.cmd.resid = 0; req->resp.cmd.resid = 0;
sense_len = scsi_req_get_sense(r, sense, sizeof(sense)); sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd)); sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd), qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
&req->resp, sense_len); &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); virtio_scsi_complete_cmd_req(req);
} }
@ -487,16 +489,16 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev); VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
stl_p(&scsiconf->num_queues, s->conf.num_queues); virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
stl_p(&scsiconf->seg_max, 128 - 2); virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2);
stl_p(&scsiconf->max_sectors, s->conf.max_sectors); virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
stl_p(&scsiconf->cmd_per_lun, s->conf.cmd_per_lun); virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
stl_p(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
stl_p(&scsiconf->sense_size, s->sense_size); virtio_stl_p(vdev, &scsiconf->sense_size, s->sense_size);
stl_p(&scsiconf->cdb_size, s->cdb_size); virtio_stl_p(vdev, &scsiconf->cdb_size, s->cdb_size);
stw_p(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); virtio_stw_p(vdev, &scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
stw_p(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); virtio_stw_p(vdev, &scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
stl_p(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); virtio_stl_p(vdev, &scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
} }
static void virtio_scsi_set_config(VirtIODevice *vdev, static void virtio_scsi_set_config(VirtIODevice *vdev,
@ -505,14 +507,14 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
if ((uint32_t) ldl_p(&scsiconf->sense_size) >= 65536 || if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 ||
(uint32_t) ldl_p(&scsiconf->cdb_size) >= 256) { (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) {
error_report("bad data written to virtio-scsi configuration space"); error_report("bad data written to virtio-scsi configuration space");
exit(1); exit(1);
} }
vs->sense_size = ldl_p(&scsiconf->sense_size); vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size);
vs->cdb_size = ldl_p(&scsiconf->cdb_size); vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
} }
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
@ -549,7 +551,7 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
VirtIODevice *vdev = VIRTIO_DEVICE(opaque); VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
int ret; int ret;
ret = virtio_load(vdev, f); ret = virtio_load(vdev, f, version_id);
if (ret) { if (ret) {
return ret; return ret;
} }

View File

@ -27,6 +27,7 @@
#include "hw/timer/mc146818rtc.h" #include "hw/timer/mc146818rtc.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "qapi-event.h" #include "qapi-event.h"
#include "qmp-commands.h"
#ifdef TARGET_I386 #ifdef TARGET_I386
#include "hw/i386/apic.h" #include "hw/i386/apic.h"
@ -85,6 +86,7 @@ typedef struct RTCState {
Notifier clock_reset_notifier; Notifier clock_reset_notifier;
LostTickPolicy lost_tick_policy; LostTickPolicy lost_tick_policy;
Notifier suspend_notifier; Notifier suspend_notifier;
QLIST_ENTRY(RTCState) link;
} RTCState; } RTCState;
static void rtc_set_time(RTCState *s); static void rtc_set_time(RTCState *s);
@ -523,6 +525,20 @@ static void rtc_get_time(RTCState *s, struct tm *tm)
rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; 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) static void rtc_set_time(RTCState *s)
{ {
struct tm tm; struct tm tm;
@ -911,6 +927,8 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
} else { } else {
isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ); isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ);
} }
QLIST_INSERT_HEAD(&rtc_devices, s, link);
return isadev; return isadev;
} }

View File

@ -14,6 +14,7 @@
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "exec/ram_addr.h"
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
@ -47,6 +48,7 @@ typedef struct VhostUserMemoryRegion {
uint64_t guest_phys_addr; uint64_t guest_phys_addr;
uint64_t memory_size; uint64_t memory_size;
uint64_t userspace_addr; uint64_t userspace_addr;
uint64_t mmap_offset;
} VhostUserMemoryRegion; } VhostUserMemoryRegion;
typedef struct VhostUserMemory { typedef struct VhostUserMemory {
@ -183,10 +185,10 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
{ {
VhostUserMsg msg; VhostUserMsg msg;
VhostUserRequest msg_request; VhostUserRequest msg_request;
RAMBlock *block = 0;
struct vhost_vring_file *file = 0; struct vhost_vring_file *file = 0;
int need_reply = 0; int need_reply = 0;
int fds[VHOST_MEMORY_MAX_NREGIONS]; int fds[VHOST_MEMORY_MAX_NREGIONS];
int i, fd;
size_t fd_num = 0; size_t fd_num = 0;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
@ -212,14 +214,17 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
break; break;
case VHOST_SET_MEM_TABLE: case VHOST_SET_MEM_TABLE:
QTAILQ_FOREACH(block, &ram_list.blocks, next) for (i = 0; i < dev->mem->nregions; ++i) {
{ struct vhost_memory_region *reg = dev->mem->regions + i;
if (block->fd > 0) { fd = qemu_get_ram_fd(reg->guest_phys_addr);
msg.memory.regions[fd_num].userspace_addr = if (fd > 0) {
(uintptr_t) block->host; msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
msg.memory.regions[fd_num].memory_size = block->length; msg.memory.regions[fd_num].memory_size = reg->memory_size;
msg.memory.regions[fd_num].guest_phys_addr = block->offset; msg.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
fds[fd_num++] = block->fd; 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;
} }
} }

View File

@ -31,6 +31,7 @@
#endif #endif
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
static void balloon_page(void *addr, int deflate) static void balloon_page(void *addr, int deflate)
{ {
@ -206,8 +207,9 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) { while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) {
ram_addr_t pa; ram_addr_t pa;
ram_addr_t addr; 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; offset += 4;
/* FIXME: remove get_system_memory(), but how? */ /* FIXME: remove get_system_memory(), but how? */
@ -248,8 +250,8 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat)) while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
== sizeof(stat)) { == sizeof(stat)) {
uint16_t tag = tswap16(stat.tag); uint16_t tag = virtio_tswap16(vdev, stat.tag);
uint64_t val = tswap64(stat.val); uint64_t val = virtio_tswap64(vdev, stat.val);
offset += sizeof(stat); offset += sizeof(stat);
if (tag < VIRTIO_BALLOON_S_NR) if (tag < VIRTIO_BALLOON_S_NR)
@ -325,10 +327,12 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
static void virtio_balloon_save(QEMUFile *f, void *opaque) static void virtio_balloon_save(QEMUFile *f, void *opaque)
{ {
VirtIOBalloon *s = VIRTIO_BALLOON(opaque); virtio_save(VIRTIO_DEVICE(opaque), f);
VirtIODevice *vdev = VIRTIO_DEVICE(s); }
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->num_pages);
qemu_put_be32(f, s->actual); qemu_put_be32(f, s->actual);
@ -336,18 +340,17 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque)
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) 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) if (version_id != 1)
return -EINVAL; return -EINVAL;
ret = virtio_load(vdev, f); return virtio_load(VIRTIO_DEVICE(opaque), f, version_id);
if (ret) {
return ret;
} }
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->num_pages = qemu_get_be32(f);
s->actual = qemu_get_be32(f); s->actual = qemu_get_be32(f);
return 0; return 0;
@ -416,6 +419,8 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data)
vdc->get_config = virtio_balloon_get_config; vdc->get_config = virtio_balloon_get_config;
vdc->set_config = virtio_balloon_set_config; vdc->set_config = virtio_balloon_set_config;
vdc->get_features = virtio_balloon_get_features; 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 = { static const TypeInfo virtio_balloon_info = {

View File

@ -89,9 +89,6 @@
/* Flags track per-device state like workarounds for quirks in older guests. */ /* Flags track per-device state like workarounds for quirks in older guests. */
#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0) #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, static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOPCIProxy *dev); VirtIOPCIProxy *dev);
@ -409,13 +406,13 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
break; break;
case 2: case 2:
val = virtio_config_readw(vdev, addr); val = virtio_config_readw(vdev, addr);
if (virtio_is_big_endian()) { if (virtio_is_big_endian(vdev)) {
val = bswap16(val); val = bswap16(val);
} }
break; break;
case 4: case 4:
val = virtio_config_readl(vdev, addr); val = virtio_config_readl(vdev, addr);
if (virtio_is_big_endian()) { if (virtio_is_big_endian(vdev)) {
val = bswap32(val); val = bswap32(val);
} }
break; break;
@ -443,13 +440,13 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr,
virtio_config_writeb(vdev, addr, val); virtio_config_writeb(vdev, addr, val);
break; break;
case 2: case 2:
if (virtio_is_big_endian()) { if (virtio_is_big_endian(vdev)) {
val = bswap16(val); val = bswap16(val);
} }
virtio_config_writew(vdev, addr, val); virtio_config_writew(vdev, addr, val);
break; break;
case 4: case 4:
if (virtio_is_big_endian()) { if (virtio_is_big_endian(vdev)) {
val = bswap32(val); val = bswap32(val);
} }
virtio_config_writel(vdev, addr, val); virtio_config_writel(vdev, addr, val);

View File

@ -107,19 +107,20 @@ static void virtio_rng_save(QEMUFile *f, void *opaque)
static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
{ {
VirtIORNG *vrng = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
if (version_id != 1) { if (version_id != 1) {
return -EINVAL; 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 /* 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 * limit. Make sure to try again after live migration when the quota may
* have been reset. * have been reset.
*/ */
virtio_rng_process(vrng); virtio_rng_process(VIRTIO_RNG(vdev));
return 0; return 0;
} }
@ -219,6 +220,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data)
vdc->realize = virtio_rng_device_realize; vdc->realize = virtio_rng_device_realize;
vdc->unrealize = virtio_rng_device_unrealize; vdc->unrealize = virtio_rng_device_unrealize;
vdc->get_features = get_features; vdc->get_features = get_features;
vdc->load = virtio_rng_load_device;
} }
static void virtio_rng_initfn(Object *obj) static void virtio_rng_initfn(Object *obj)

View File

@ -19,6 +19,8 @@
#include "hw/virtio/virtio.h" #include "hw/virtio/virtio.h"
#include "qemu/atomic.h" #include "qemu/atomic.h"
#include "hw/virtio/virtio-bus.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. * The alignment to use between consumer and producer parts of vring.
@ -101,53 +103,56 @@ static void virtqueue_init(VirtQueue *vq)
vq->vring.align); 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; hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); 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; hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); 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; hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); 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; hwaddr pa;
pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); 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) static inline uint16_t vring_avail_flags(VirtQueue *vq)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, flags); 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) static inline uint16_t vring_avail_idx(VirtQueue *vq)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, idx); 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) static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, ring[i]); 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) static inline uint16_t vring_used_event(VirtQueue *vq)
@ -159,44 +164,44 @@ static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, ring[i].id); 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) static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, ring[i].len); 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) static uint16_t vring_used_idx(VirtQueue *vq)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, idx); 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) static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
{ {
hwaddr pa; hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, idx); 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) static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
{ {
VirtIODevice *vdev = vq->vdev;
hwaddr pa; hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, flags); pa = vq->vring.used + offsetof(VRingUsed, flags);
stw_phys(&address_space_memory, virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) | mask);
pa, lduw_phys(&address_space_memory, pa) | mask);
} }
static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
{ {
VirtIODevice *vdev = vq->vdev;
hwaddr pa; hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, flags); pa = vq->vring.used + offsetof(VRingUsed, flags);
stw_phys(&address_space_memory, virtio_stw_phys(vdev, pa, virtio_lduw_phys(vdev, pa) & ~mask);
pa, lduw_phys(&address_space_memory, pa) & ~mask);
} }
static inline void vring_avail_event(VirtQueue *vq, uint16_t val) static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
@ -206,7 +211,7 @@ static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
return; return;
} }
pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]); 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) void virtio_queue_set_notification(VirtQueue *vq, int enable)
@ -323,17 +328,18 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
return head; 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 i, unsigned int max)
{ {
unsigned int next; unsigned int next;
/* If this descriptor says it doesn't chain, we're done. */ /* 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; return max;
}
/* Check they're not leading us off end of descriptors. */ /* 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! */ /* Make sure compiler knows to grab that: we don't want it changing! */
smp_wmb(); smp_wmb();
@ -356,6 +362,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
total_bufs = in_total = out_total = 0; total_bufs = in_total = out_total = 0;
while (virtqueue_num_heads(vq, idx)) { while (virtqueue_num_heads(vq, idx)) {
VirtIODevice *vdev = vq->vdev;
unsigned int max, num_bufs, indirect = 0; unsigned int max, num_bufs, indirect = 0;
hwaddr desc_pa; hwaddr desc_pa;
int i; int i;
@ -365,8 +372,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
i = virtqueue_get_head(vq, idx++); i = virtqueue_get_head(vq, idx++);
desc_pa = vq->vring.desc; desc_pa = vq->vring.desc;
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) {
if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) {
error_report("Invalid size for indirect buffer table"); error_report("Invalid size for indirect buffer table");
exit(1); exit(1);
} }
@ -379,8 +386,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
/* loop over the indirect descriptor table */ /* loop over the indirect descriptor table */
indirect = 1; indirect = 1;
max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc); max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc);
desc_pa = vring_desc_addr(desc_pa, i); desc_pa = vring_desc_addr(vdev, desc_pa, i);
num_bufs = i = 0; num_bufs = i = 0;
} }
@ -391,15 +398,15 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
exit(1); exit(1);
} }
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) {
in_total += vring_desc_len(desc_pa, i); in_total += vring_desc_len(vdev, desc_pa, i);
} else { } 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) { if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
goto done; 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) if (!indirect)
total_bufs = num_bufs; total_bufs = num_bufs;
@ -450,6 +457,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{ {
unsigned int i, head, max; unsigned int i, head, max;
hwaddr desc_pa = vq->vring.desc; hwaddr desc_pa = vq->vring.desc;
VirtIODevice *vdev = vq->vdev;
if (!virtqueue_num_heads(vq, vq->last_avail_idx)) if (!virtqueue_num_heads(vq, vq->last_avail_idx))
return 0; return 0;
@ -460,19 +468,19 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
max = vq->vring.num; max = vq->vring.num;
i = head = virtqueue_get_head(vq, vq->last_avail_idx++); 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)); vring_avail_event(vq, vring_avail_idx(vq));
} }
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) {
if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) {
error_report("Invalid size for indirect buffer table"); error_report("Invalid size for indirect buffer table");
exit(1); exit(1);
} }
/* loop over the indirect descriptor table */ /* loop over the indirect descriptor table */
max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc); max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc);
desc_pa = vring_desc_addr(desc_pa, i); desc_pa = vring_desc_addr(vdev, desc_pa, i);
i = 0; i = 0;
} }
@ -480,30 +488,30 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
do { do {
struct iovec *sg; 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)) { if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
error_report("Too many write descriptors in indirect table"); error_report("Too many write descriptors in indirect table");
exit(1); 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++]; sg = &elem->in_sg[elem->in_num++];
} else { } else {
if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) { if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
error_report("Too many read descriptors in indirect table"); error_report("Too many read descriptors in indirect table");
exit(1); 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 = &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 we've got too many, that implies a descriptor loop. */
if ((elem->in_num + elem->out_num) > max) { if ((elem->in_num + elem->out_num) > max) {
error_report("Looped descriptor"); error_report("Looped descriptor");
exit(1); 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 */ /* Now map what we have collected */
virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1); virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
@ -544,6 +552,27 @@ void virtio_set_status(VirtIODevice *vdev, uint8_t val)
vdev->status = val; 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) void virtio_reset(void *opaque)
{ {
VirtIODevice *vdev = opaque; VirtIODevice *vdev = opaque;
@ -551,6 +580,13 @@ void virtio_reset(void *opaque)
int i; int i;
virtio_set_status(vdev, 0); 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) { if (k->reset) {
k->reset(vdev); k->reset(vdev);
@ -839,10 +875,46 @@ void virtio_notify_config(VirtIODevice *vdev)
virtio_notify_vector(vdev, vdev->config_vector); 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) void virtio_save(VirtIODevice *vdev, QEMUFile *f)
{ {
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
int i; int i;
if (k->save_config) { if (k->save_config) {
@ -877,6 +949,13 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
k->save_queue(qbus->parent, i, f); 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) int virtio_set_features(VirtIODevice *vdev, uint32_t val)
@ -895,7 +974,7 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val)
return bad ? -1 : 0; return bad ? -1 : 0;
} }
int virtio_load(VirtIODevice *vdev, QEMUFile *f) int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
{ {
int i, ret; int i, ret;
int32_t config_len; int32_t config_len;
@ -904,6 +983,13 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
uint32_t supported_features; uint32_t supported_features;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 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) { if (k->load_config) {
ret = k->load_config(qbus->parent, f); ret = k->load_config(qbus->parent, f);
@ -926,12 +1012,18 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
return -1; return -1;
} }
config_len = qemu_get_be32(f); 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); * There are cases where the incoming config can be bigger or smaller
return -1; * 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); num = qemu_get_be32(f);
@ -951,18 +1043,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
vdev->vq[i].notification = true; vdev->vq[i].notification = true;
if (vdev->vq[i].pa) { if (vdev->vq[i].pa) {
uint16_t nheads;
virtqueue_init(&vdev->vq[i]); 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) { } else if (vdev->vq[i].last_avail_idx) {
error_report("VQ %d address 0x0 " error_report("VQ %d address 0x0 "
"inconsistent with Host index 0x%x", "inconsistent with Host index 0x%x",
@ -977,6 +1058,40 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
} }
virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); 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; return 0;
} }
@ -1034,6 +1149,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
} }
vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
vdev); vdev);
vdev->device_endian = virtio_default_endian();
} }
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)

View File

@ -29,6 +29,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
MemoryRegion *mr); MemoryRegion *mr);
ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr); ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr);
int qemu_get_ram_fd(ram_addr_t addr); 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_get_ram_ptr(ram_addr_t addr);
void qemu_ram_free(ram_addr_t addr); void qemu_ram_free(ram_addr_t addr);
void qemu_ram_free_from_ptr(ram_addr_t addr); void qemu_ram_free_from_ptr(ram_addr_t addr);

View File

@ -294,43 +294,6 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void); int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); 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 \ #define PC_COMPAT_2_0 \
{\ {\
.driver = "virtio-scsi-pci",\ .driver = "virtio-scsi-pci",\
@ -358,7 +321,7 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},\ },\
{\ {\
.driver = "pci-serial-2x",\ .driver = "pci-serial-2x",\
.property = "prof_if",\ .property = "prog_if",\
.value = stringify(0),\ .value = stringify(0),\
},\ },\
{\ {\
@ -370,6 +333,19 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "virtio-net-pci",\ .driver = "virtio-net-pci",\
.property = "guest_announce",\ .property = "guest_announce",\
.value = "off",\ .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 \ #define PC_COMPAT_1_7 \
@ -383,6 +359,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
.driver = "PIIX4_PM",\ .driver = "PIIX4_PM",\
.property = "acpi-pci-hotplug-with-bridge-support",\ .property = "acpi-pci-hotplug-with-bridge-support",\
.value = "off",\ .value = "off",\
},\
{\
.driver = "hpet",\
.property = HPET_INTCAP,\
.value = stringify(4),\
} }
#define PC_COMPAT_1_6 \ #define PC_COMPAT_1_6 \

View File

@ -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 */

View File

@ -104,6 +104,12 @@ typedef struct VirtQueueElement
#define VIRTIO_DEVICE(obj) \ #define VIRTIO_DEVICE(obj) \
OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE) 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 struct VirtIODevice
{ {
DeviceState parent_obj; DeviceState parent_obj;
@ -121,6 +127,7 @@ struct VirtIODevice
bool vm_running; bool vm_running;
VMChangeStateEntry *vmstate; VMChangeStateEntry *vmstate;
char *bus_name; char *bus_name;
uint8_t device_endian;
}; };
typedef struct VirtioDeviceClass { typedef struct VirtioDeviceClass {
@ -150,6 +157,8 @@ typedef struct VirtioDeviceClass {
* must mask in frontend instead. * must mask in frontend instead.
*/ */
void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); 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; } VirtioDeviceClass;
void virtio_init(VirtIODevice *vdev, const char *name, void virtio_init(VirtIODevice *vdev, const char *name,
@ -184,7 +193,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
void virtio_save(VirtIODevice *vdev, QEMUFile *f); 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); void virtio_notify_config(VirtIODevice *vdev);
@ -253,4 +262,10 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
bool set_handler); bool set_handler);
void virtio_queue_notify_vq(VirtQueue *vq); void virtio_queue_notify_vq(VirtQueue *vq);
void virtio_irq(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 #endif

View File

@ -116,6 +116,7 @@ typedef struct CPUClass {
CPUUnassignedAccess do_unassigned_access; CPUUnassignedAccess do_unassigned_access;
void (*do_unaligned_access)(CPUState *cpu, vaddr addr, void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
int is_write, int is_user, uintptr_t retaddr); int is_write, int is_user, uintptr_t retaddr);
bool (*virtio_is_big_endian)(CPUState *cpu);
int (*memory_rw_debug)(CPUState *cpu, vaddr addr, int (*memory_rw_debug)(CPUState *cpu, vaddr addr,
uint8_t *buf, int len, bool is_write); uint8_t *buf, int len, bool is_write);
void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,

View File

@ -146,11 +146,16 @@ extern int mem_prealloc;
*/ */
#define MAX_CPUMASK_BITS 255 #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 { typedef struct node_info {
uint64_t node_mem; uint64_t node_mem;
DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS); DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS);
struct HostMemoryBackend *node_memdev; struct HostMemoryBackend *node_memdev;
bool present;
} NodeInfo; } NodeInfo;
extern NodeInfo numa_info[MAX_NODES]; extern NodeInfo numa_info[MAX_NODES];
void set_numa_nodes(void); void set_numa_nodes(void);

View File

@ -5441,3 +5441,10 @@ QemuOptsList qemu_mon_opts = {
{ /* end of list */ } { /* end of list */ }
}, },
}; };
#ifndef TARGET_I386
void qmp_rtc_reset_reinjection(Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
}
#endif

28
numa.c
View File

@ -62,6 +62,11 @@ static void numa_node_parse(NumaNodeOptions *node, QemuOpts *opts, Error **errp)
return; return;
} }
if (numa_info[nodenr].present) {
error_setg(errp, "Duplicate NUMA nodeid: %" PRIu16, nodenr);
return;
}
for (cpus = node->cpus; cpus; cpus = cpus->next) { for (cpus = node->cpus; cpus; cpus = cpus->next) {
if (cpus->value > MAX_CPUMASK_BITS) { if (cpus->value > MAX_CPUMASK_BITS) {
error_setg(errp, "CPU number %" PRIu16 " is bigger than %d", error_setg(errp, "CPU number %" PRIu16 " is bigger than %d",
@ -106,6 +111,8 @@ static void numa_node_parse(NumaNodeOptions *node, QemuOpts *opts, Error **errp)
numa_info[nodenr].node_mem = object_property_get_int(o, "size", NULL); numa_info[nodenr].node_mem = object_property_get_int(o, "size", NULL);
numa_info[nodenr].node_memdev = MEMORY_BACKEND(o); 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) int numa_init_func(QemuOpts *opts, void *opaque)
@ -153,15 +160,30 @@ error:
void set_numa_nodes(void) 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) { if (nb_numa_nodes > 0) {
uint64_t numa_total; uint64_t numa_total;
int i;
if (nb_numa_nodes > MAX_NODES) { if (nb_numa_nodes > MAX_NODES) {
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 * and distribute the available memory equally across all nodes
*/ */
for (i = 0; i < nb_numa_nodes; i++) { for (i = 0; i < nb_numa_nodes; i++) {
@ -172,7 +194,7 @@ void set_numa_nodes(void)
if (i == nb_numa_nodes) { if (i == nb_numa_nodes) {
uint64_t usedmem = 0; 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. * the final node gets the rest.
*/ */
for (i = 0; i < nb_numa_nodes - 1; i++) { for (i = 0; i < nb_numa_nodes - 1; i++) {

View File

@ -3468,3 +3468,15 @@
## ##
{ 'enum': 'GuestPanicAction', { 'enum': 'GuestPanicAction',
'data': [ 'pause' ] } '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' }

View File

@ -3675,3 +3675,26 @@ Example:
{ "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0} { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
]} ]}
EQMP 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

View File

@ -196,6 +196,11 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
return 0; 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, void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags) int flags)
@ -334,6 +339,7 @@ static void cpu_class_init(ObjectClass *klass, void *data)
k->write_elf64_note = cpu_common_write_elf64_note; k->write_elf64_note = cpu_common_write_elf64_note;
k->gdb_read_register = cpu_common_gdb_read_register; k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_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; dc->realize = cpu_common_realizefn;
/* /*
* Reason: CPUs still need special care by board code: wiring up * Reason: CPUs still need special care by board code: wiring up

View File

@ -531,7 +531,7 @@ static void dec_calc(DisasContext *dc, uint32_t insn)
TCGv_i64 high = tcg_temp_new_i64(); TCGv_i64 high = tcg_temp_new_i64();
TCGv_i32 sr_ove = tcg_temp_local_new_i32(); TCGv_i32 sr_ove = tcg_temp_local_new_i32();
int lab = gen_new_label(); 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(tra, cpu_R[ra]);
tcg_gen_extu_i32_i64(trb, cpu_R[rb]); tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
tcg_gen_mul_i64(result, tra, trb); tcg_gen_mul_i64(result, tra, trb);

View File

@ -29,6 +29,8 @@
#define TARGET_LONG_BITS 64 #define TARGET_LONG_BITS 64
#define TARGET_PAGE_BITS 12 #define TARGET_PAGE_BITS 12
#define TARGET_IS_BIENDIAN 1
/* Note that the official physical address space bits is 62-M where M /* 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 is implementation dependent. I've not looked up M for the set of
cpus we emulate at the system level. */ cpus we emulate at the system level. */

View File

@ -9597,6 +9597,18 @@ static void ppc_cpu_reset(CPUState *s)
tlb_flush(s, 1); 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) static void ppc_cpu_initfn(Object *obj)
{ {
CPUState *cs = CPU(obj); CPUState *cs = CPU(obj);
@ -9692,6 +9704,9 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#else #else
cc->gdb_core_xml_file = "power-core.xml"; cc->gdb_core_xml_file = "power-core.xml";
#endif #endif
#ifndef CONFIG_USER_ONLY
cc->virtio_is_big_endian = ppc_cpu_is_big_endian;
#endif
dc->fw_name = "PowerPC,UNKNOWN"; dc->fw_name = "PowerPC,UNKNOWN";
} }

View File

@ -21,12 +21,25 @@
typedef struct TestOutputVisitorData { typedef struct TestOutputVisitorData {
StringOutputVisitor *sov; StringOutputVisitor *sov;
Visitor *ov; Visitor *ov;
bool human;
} TestOutputVisitorData; } TestOutputVisitorData;
static void visitor_output_setup(TestOutputVisitorData *data, static void visitor_output_setup(TestOutputVisitorData *data,
const void *unused) 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); g_assert(data->sov != NULL);
data->ov = string_output_get_visitor(data->sov); data->ov = string_output_get_visitor(data->sov);
@ -53,7 +66,11 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
str = string_output_get_string(data->sov); str = string_output_get_string(data->sov);
g_assert(str != NULL); g_assert(str != NULL);
if (data->human) {
g_assert_cmpstr(str, ==, "42 (0x2a)");
} else {
g_assert_cmpstr(str, ==, "42"); g_assert_cmpstr(str, ==, "42");
}
g_free(str); g_free(str);
} }
@ -78,8 +95,15 @@ static void test_visitor_out_intList(TestOutputVisitorData *data,
str = string_output_get_string(data->sov); str = string_output_get_string(data->sov);
g_assert(str != NULL); g_assert(str != NULL);
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, ==, g_assert_cmpstr(str, ==,
"0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807"); "0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807");
}
g_free(str); g_free(str);
while (list) { while (list) {
intList *tmp2; intList *tmp2;
@ -125,6 +149,7 @@ static void test_visitor_out_string(TestOutputVisitorData *data,
const void *unused) const void *unused)
{ {
char *string = (char *) "Q E M U"; char *string = (char *) "Q E M U";
const char *string_human = "\"Q E M U\"";
Error *err = NULL; Error *err = NULL;
char *str; char *str;
@ -133,7 +158,11 @@ static void test_visitor_out_string(TestOutputVisitorData *data,
str = string_output_get_string(data->sov); str = string_output_get_string(data->sov);
g_assert(str != NULL); g_assert(str != NULL);
if (data->human) {
g_assert_cmpstr(str, ==, string_human);
} else {
g_assert_cmpstr(str, ==, string); g_assert_cmpstr(str, ==, string);
}
g_free(str); g_free(str);
} }
@ -150,7 +179,11 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data,
str = string_output_get_string(data->sov); str = string_output_get_string(data->sov);
g_assert(str != NULL); g_assert(str != NULL);
if (data->human) {
g_assert_cmpstr(str, ==, "<null>");
} else {
g_assert_cmpstr(str, ==, ""); g_assert_cmpstr(str, ==, "");
}
g_free(str); g_free(str);
} }
@ -162,12 +195,26 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
EnumOne i; EnumOne i;
for (i = 0; i < ENUM_ONE_MAX; i++) { for (i = 0; i < ENUM_ONE_MAX; i++) {
char *str_human;
int len;
visit_type_EnumOne(data->ov, &i, "unused", &err); visit_type_EnumOne(data->ov, &i, "unused", &err);
g_assert(!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); str = string_output_get_string(data->sov);
g_assert(str != NULL); g_assert(str != NULL);
if (data->human) {
g_assert_cmpstr(str, ==, str_human);
} else {
g_assert_cmpstr(str, ==, EnumOne_lookup[i]); g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
}
g_free(str_human);
g_free(str); g_free(str);
} }
} }
@ -186,11 +233,15 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
} }
} }
static void output_visitor_test_add(const char *testpath, static void
output_visitor_test_add(const char *testpath,
TestOutputVisitorData *data, TestOutputVisitorData *data,
void (*test_func)(TestOutputVisitorData *data, const void *user_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); test_func, visitor_output_teardown);
} }
@ -201,21 +252,41 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
output_visitor_test_add("/string-visitor/output/int", 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", 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", 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", 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", 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", 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", 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", 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(); g_test_run();

3
vl.c
View File

@ -196,6 +196,7 @@ static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
QTAILQ_HEAD_INITIALIZER(fw_boot_order); QTAILQ_HEAD_INITIALIZER(fw_boot_order);
int nb_numa_nodes; int nb_numa_nodes;
int max_numa_nodeid;
NodeInfo numa_info[MAX_NODES]; NodeInfo numa_info[MAX_NODES];
uint8_t qemu_uuid[16]; uint8_t qemu_uuid[16];
@ -2984,10 +2985,12 @@ int main(int argc, char **argv, char **envp)
for (i = 0; i < MAX_NODES; i++) { for (i = 0; i < MAX_NODES; i++) {
numa_info[i].node_mem = 0; numa_info[i].node_mem = 0;
numa_info[i].present = false;
bitmap_zero(numa_info[i].node_cpu, MAX_CPUMASK_BITS); bitmap_zero(numa_info[i].node_cpu, MAX_CPUMASK_BITS);
} }
nb_numa_nodes = 0; nb_numa_nodes = 0;
max_numa_nodeid = 0;
nb_nics = 0; nb_nics = 0;
bdrv_init_with_whitelist(); bdrv_init_with_whitelist();