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
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
View file

@ -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)
{

View file

@ -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);

View file

@ -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 = {

View file

@ -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 = {

View file

@ -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";
}

View file

@ -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 */ }
},
};

View file

@ -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;

View file

@ -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 = {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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 = {

View file

@ -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);

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)
{
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)

View file

@ -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)

View file

@ -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);

View file

@ -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 \

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) \
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

View file

@ -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,

View file

@ -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);

View file

@ -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
View file

@ -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++) {

View file

@ -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' }

View file

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

View file

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

View file

@ -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);

View file

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

View file

@ -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";
}

View file

@ -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
View file

@ -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();