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