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