aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-02-08 11:25:31 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-02-08 11:25:31 +0000
commitbdad0f3977ee38f681453f602ddec9f4e24b03f9 (patch)
tree236ceead1b8de76a588474ab3b2d3e48a2f1c1a8 /hw
parentee8e8f92a730afc17ab8be6e86df6b9a23b8ebc6 (diff)
parenta407644079c8639002e7ea635d851953b10a38c3 (diff)
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc and misc cleanups and fixes, virtio optimizations Included here: Refactoring and bugfix patches in PC/ACPI. New commands for ipmi. Virtio optimizations. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Sat 06 Feb 2016 18:44:26 GMT 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: (45 commits) net: set endianness on all backend devices fix MSI injection on Xen intel_iommu: large page support dimm: Correct type of MemoryHotplugState->base pc: set the OEM fields in the RSDT and the FADT from the SLIC acpi: add function to extract oem_id and oem_table_id from the user's SLIC acpi: expose oem_id and oem_table_id in build_rsdt() acpi: take oem_id in build_header(), optionally pc: Eliminate PcGuestInfo struct pc: Move APIC and NUMA data from PcGuestInfo to PCMachineState pc: Move PcGuestInfo.fw_cfg to PCMachineState pc: Remove PcGuestInfo.isapc_ram_fw field pc: Remove RAM size fields from PcGuestInfo pc: Remove compat fields from PcGuestInfo acpi: Don't save PcGuestInfo on AcpiBuildState acpi: Remove guest_info parameters from functions pc: Simplify xen_load_linux() signature pc: Simplify pc_memory_init() signature pc: Eliminate struct PcGuestInfoState pc: Move PcGuestInfo declaration to top of file ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/9p.c2
-rw-r--r--hw/9pfs/virtio-9p-device.c17
-rw-r--r--hw/9pfs/virtio-9p.h2
-rw-r--r--hw/acpi/aml-build.c14
-rw-r--r--hw/acpi/core.c16
-rw-r--r--hw/acpi/nvdimm.c4
-rw-r--r--hw/arm/virt-acpi-build.c14
-rw-r--r--hw/block/dataplane/virtio-blk.c11
-rw-r--r--hw/block/virtio-blk.c23
-rw-r--r--hw/char/virtio-serial-bus.c78
-rw-r--r--hw/display/virtio-gpu.c21
-rw-r--r--hw/i386/acpi-build.c346
-rw-r--r--hw/i386/acpi-build.h2
-rw-r--r--hw/i386/intel_iommu.c76
-rw-r--r--hw/i386/intel_iommu_internal.h6
-rw-r--r--hw/i386/pc.c77
-rw-r--r--hw/i386/pc_piix.c14
-rw-r--r--hw/i386/pc_q35.c14
-rw-r--r--hw/input/virtio-input.c24
-rw-r--r--hw/ipmi/ipmi_bmc_sim.c351
-rw-r--r--hw/net/vhost_net.c23
-rw-r--r--hw/net/virtio-net.c69
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c2
-rw-r--r--hw/pci/msi.c9
-rw-r--r--hw/pci/msix.c12
-rw-r--r--hw/pci/pci.c7
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c15
-rw-r--r--hw/scsi/virtio-scsi.c26
-rw-r--r--hw/virtio/dataplane/vring.c62
-rw-r--r--hw/virtio/virtio-balloon.c22
-rw-r--r--hw/virtio/virtio-rng.c10
-rw-r--r--hw/virtio/virtio.c348
-rw-r--r--hw/xen/xen_pt_msi.c4
33 files changed, 1004 insertions, 717 deletions
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 15fb0ab75d..db5f4780dc 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1587,7 +1587,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
int read_count;
int64_t xattr_len;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = &v->elems[pdu->idx];
+ VirtQueueElement *elem = v->elems[pdu->idx];
xattr_len = fidp->fs.xattr.len;
read_count = xattr_len - off;
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index c5f7b92640..a38850ee89 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -26,10 +26,12 @@ void virtio_9p_push_and_notify(V9fsPDU *pdu)
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = &v->elems[pdu->idx];
+ VirtQueueElement *elem = v->elems[pdu->idx];
/* push onto queue and notify */
virtqueue_push(v->vq, elem, pdu->size);
+ g_free(elem);
+ v->elems[pdu->idx] = NULL;
/* FIXME: we should batch these completions */
virtio_notify(VIRTIO_DEVICE(v), v->vq);
@@ -48,10 +50,10 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
uint8_t id;
uint16_t tag_le;
} QEMU_PACKED out;
- VirtQueueElement *elem = &v->elems[pdu->idx];
+ VirtQueueElement *elem;
- len = virtqueue_pop(vq, elem);
- if (!len) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
pdu_free(pdu);
break;
}
@@ -59,6 +61,7 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
BUG_ON(elem->out_num == 0 || elem->in_num == 0);
QEMU_BUILD_BUG_ON(sizeof out != 7);
+ v->elems[pdu->idx] = elem;
len = iov_to_buf(elem->out_sg, elem->out_num, 0,
&out, sizeof out);
BUG_ON(len != sizeof out);
@@ -141,7 +144,7 @@ ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = &v->elems[pdu->idx];
+ VirtQueueElement *elem = v->elems[pdu->idx];
return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
}
@@ -151,7 +154,7 @@ ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = &v->elems[pdu->idx];
+ VirtQueueElement *elem = v->elems[pdu->idx];
return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
}
@@ -161,7 +164,7 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
{
V9fsState *s = pdu->s;
V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
- VirtQueueElement *elem = &v->elems[pdu->idx];
+ VirtQueueElement *elem = v->elems[pdu->idx];
if (is_write) {
*piov = elem->out_sg;
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 1cdf0a2d65..7f6d885539 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -11,7 +11,7 @@ typedef struct V9fsVirtioState
VirtQueue *vq;
size_t config_size;
V9fsPDU pdus[MAX_REQ];
- VirtQueueElement elems[MAX_REQ];
+ VirtQueueElement *elems[MAX_REQ];
V9fsState state;
} V9fsVirtioState;
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 21d2ea0c9c..603068b5ea 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1426,12 +1426,17 @@ Aml *aml_alias(const char *source_object, const char *alias_object)
void
build_header(GArray *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
- const char *oem_table_id)
+ const char *oem_id, const char *oem_table_id)
{
memcpy(&h->signature, sig, 4);
h->length = cpu_to_le32(len);
h->revision = rev;
- memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
+
+ if (oem_id) {
+ strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id);
+ } else {
+ memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
+ }
if (oem_table_id) {
strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id));
@@ -1487,7 +1492,8 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
/* Build rsdt table */
void
-build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
+build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets,
+ const char *oem_id, const char *oem_table_id)
{
AcpiRsdtDescriptorRev1 *rsdt;
size_t rsdt_len;
@@ -1506,5 +1512,5 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets)
sizeof(uint32_t));
}
build_header(linker, table_data,
- (void *)rsdt, "RSDT", rsdt_len, 1, NULL);
+ (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
}
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index 397e6da9b6..edf3f960a7 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -350,6 +350,22 @@ uint8_t *acpi_table_next(uint8_t *current)
}
}
+int acpi_get_slic_oem(AcpiSlicOem *oem)
+{
+ uint8_t *u;
+
+ for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
+ struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length));
+
+ if (memcmp(hdr->sig, "SLIC", 4) == 0) {
+ oem->id = hdr->oem_id;
+ oem->table_id = hdr->oem_table_id;
+ return 0;
+ }
+ }
+ return -1;
+}
+
static void acpi_notify_wakeup(Notifier *notifier, void *data)
{
ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index 7ee7e1623c..49ee68e614 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -366,7 +366,7 @@ static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets,
build_header(linker, table_data,
(void *)(table_data->data + header), "NFIT",
- sizeof(NvdimmNfitHeader) + structures->len, 1, NULL);
+ sizeof(NvdimmNfitHeader) + structures->len, 1, NULL, NULL);
g_array_free(structures, true);
}
@@ -471,7 +471,7 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets,
g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
build_header(linker, table_data,
(void *)(table_data->data + table_data->len - ssdt->buf->len),
- "SSDT", ssdt->buf->len, 1, "NVDIMM");
+ "SSDT", ssdt->buf->len, 1, NULL, "NVDIMM");
free_aml_allocator();
}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 26146919cd..8cf9a2167f 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -394,7 +394,7 @@ build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2,
- NULL);
+ NULL, NULL);
}
static void
@@ -413,7 +413,7 @@ build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size
/ PCIE_MMCFG_SIZE_MIN) - 1;
- build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL);
+ build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
}
/* GTDT */
@@ -439,7 +439,7 @@ build_gtdt(GArray *table_data, GArray *linker)
build_header(linker, table_data,
(void *)(table_data->data + gtdt_start), "GTDT",
- table_data->len - gtdt_start, 2, NULL);
+ table_data->len - gtdt_start, 2, NULL, NULL);
}
/* MADT */
@@ -498,7 +498,7 @@ build_madt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
build_header(linker, table_data,
(void *)(table_data->data + madt_start), "APIC",
- table_data->len - madt_start, 3, NULL);
+ table_data->len - madt_start, 3, NULL, NULL);
}
/* FADT */
@@ -523,7 +523,7 @@ build_fadt(GArray *table_data, GArray *linker, unsigned dsdt)
sizeof fadt->dsdt);
build_header(linker, table_data,
- (void *)fadt, "FACP", sizeof(*fadt), 5, NULL);
+ (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL);
}
/* DSDT */
@@ -562,7 +562,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
build_header(linker, table_data,
(void *)(table_data->data + table_data->len - dsdt->buf->len),
- "DSDT", dsdt->buf->len, 2, NULL);
+ "DSDT", dsdt->buf->len, 2, NULL, NULL);
free_aml_allocator();
}
@@ -623,7 +623,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
/* RSDT is pointed to by RSDP */
rsdt = tables_blob->len;
- build_rsdt(tables_blob, tables->linker, table_offsets);
+ build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
/* RSDP is in FSEG memory, so allocate it separately */
build_rsdp(tables->rsdp, tables->linker, rsdt);
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index ee0c4d4070..0d9978109c 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -100,20 +100,19 @@ static void handle_notify(EventNotifier *e)
blk_io_plug(s->conf->conf.blk);
for (;;) {
MultiReqBuffer mrb = {};
- int ret;
/* Disable guest->host notifies to avoid unnecessary vmexits */
vring_disable_notification(s->vdev, &s->vring);
for (;;) {
- VirtIOBlockReq *req = virtio_blk_alloc_request(vblk);
+ VirtIOBlockReq *req = vring_pop(s->vdev, &s->vring,
+ sizeof(VirtIOBlockReq));
- ret = vring_pop(s->vdev, &s->vring, &req->elem);
- if (ret < 0) {
- virtio_blk_free_request(req);
+ if (req == NULL) {
break; /* no more requests */
}
+ virtio_blk_init_request(vblk, req);
trace_virtio_blk_data_plane_process_request(s, req->elem.out_num,
req->elem.in_num,
req->elem.index);
@@ -125,7 +124,7 @@ static void handle_notify(EventNotifier *e)
virtio_blk_submit_multireq(s->conf->conf.blk, &mrb);
}
- if (likely(ret == -EAGAIN)) { /* vring emptied */
+ if (likely(!vring_more_avail(s->vdev, &s->vring))) { /* vring emptied */
/* Re-enable guest->host notifies and stop processing the vring.
* But if the guest has snuck in more descriptors, keep processing.
*/
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 11bedff6d6..c427698fcb 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -29,15 +29,13 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
-VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
+void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req)
{
- VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1);
req->dev = s;
req->qiov.size = 0;
req->in_len = 0;
req->next = NULL;
req->mr_next = NULL;
- return req;
}
void virtio_blk_free_request(VirtIOBlockReq *req)
@@ -193,13 +191,11 @@ out:
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
{
- VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+ VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq));
- if (!virtqueue_pop(s->vq, &req->elem)) {
- virtio_blk_free_request(req);
- return NULL;
+ if (req) {
+ virtio_blk_init_request(s, req);
}
-
return req;
}
@@ -812,8 +808,7 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
while (req) {
qemu_put_sbyte(f, 1);
- qemu_put_buffer(f, (unsigned char *)&req->elem,
- sizeof(VirtQueueElement));
+ qemu_put_virtqueue_element(f, &req->elem);
req = req->next;
}
qemu_put_sbyte(f, 0);
@@ -836,13 +831,11 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
VirtIOBlock *s = VIRTIO_BLK(vdev);
while (qemu_get_sbyte(f)) {
- VirtIOBlockReq *req = virtio_blk_alloc_request(s);
- qemu_get_buffer(f, (unsigned char *)&req->elem,
- sizeof(VirtQueueElement));
+ VirtIOBlockReq *req;
+ req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
+ virtio_blk_init_request(s, req);
req->next = s->rq;
s->rq = req;
-
- virtqueue_map(&req->elem);
}
return 0;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 8d5c740558..99cb6836ad 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -83,7 +83,7 @@ static bool use_multiport(VirtIOSerial *vser)
static size_t write_to_port(VirtIOSerialPort *port,
const uint8_t *buf, size_t size)
{
- VirtQueueElement elem;
+ VirtQueueElement *elem;
VirtQueue *vq;
size_t offset;
@@ -96,15 +96,17 @@ static size_t write_to_port(VirtIOSerialPort *port,
while (offset < size) {
size_t len;
- if (!virtqueue_pop(vq, &elem)) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
break;
}
- len = iov_from_buf(elem.in_sg, elem.in_num, 0,
+ len = iov_from_buf(elem->in_sg, elem->in_num, 0,
buf + offset, size - offset);
offset += len;
- virtqueue_push(vq, &elem, len);
+ virtqueue_push(vq, elem, len);
+ g_free(elem);
}
virtio_notify(VIRTIO_DEVICE(port->vser), vq);
@@ -113,13 +115,18 @@ static size_t write_to_port(VirtIOSerialPort *port,
static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
{
- VirtQueueElement elem;
+ VirtQueueElement *elem;
if (!virtio_queue_ready(vq)) {
return;
}
- while (virtqueue_pop(vq, &elem)) {
- virtqueue_push(vq, &elem, 0);
+ for (;;) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+ virtqueue_push(vq, elem, 0);
+ g_free(elem);
}
virtio_notify(vdev, vq);
}
@@ -138,21 +145,22 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
unsigned int i;
/* Pop an elem only if we haven't left off a previous one mid-way */
- if (!port->elem.out_num) {
- if (!virtqueue_pop(vq, &port->elem)) {
+ if (!port->elem) {
+ port->elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!port->elem) {
break;
}
port->iov_idx = 0;
port->iov_offset = 0;
}
- for (i = port->iov_idx; i < port->elem.out_num; i++) {
+ for (i = port->iov_idx; i < port->elem->out_num; i++) {
size_t buf_size;
ssize_t ret;
- buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
+ buf_size = port->elem->out_sg[i].iov_len - port->iov_offset;
ret = vsc->have_data(port,
- port->elem.out_sg[i].iov_base
+ port->elem->out_sg[i].iov_base
+ port->iov_offset,
buf_size);
if (port->throttled) {
@@ -167,8 +175,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
if (port->throttled) {
break;
}
- virtqueue_push(vq, &port->elem, 0);
- port->elem.out_num = 0;
+ virtqueue_push(vq, port->elem, 0);
+ g_free(port->elem);
+ port->elem = NULL;
}
virtio_notify(vdev, vq);
}
@@ -185,22 +194,26 @@ static void flush_queued_data(VirtIOSerialPort *port)
static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
{
- VirtQueueElement elem;
+ VirtQueueElement *elem;
VirtQueue *vq;
vq = vser->c_ivq;
if (!virtio_queue_ready(vq)) {
return 0;
}
- if (!virtqueue_pop(vq, &elem)) {
+
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
return 0;
}
/* TODO: detect a buffer that's too short, set NEEDS_RESET */
- iov_from_buf(elem.in_sg, elem.in_num, 0, buf, len);
+ iov_from_buf(elem->in_sg, elem->in_num, 0, buf, len);
- virtqueue_push(vq, &elem, len);
+ virtqueue_push(vq, elem, len);
virtio_notify(VIRTIO_DEVICE(vser), vq);
+ g_free(elem);
+
return len;
}
@@ -414,7 +427,7 @@ static void control_in(VirtIODevice *vdev, VirtQueue *vq)
static void control_out(VirtIODevice *vdev, VirtQueue *vq)
{
- VirtQueueElement elem;
+ VirtQueueElement *elem;
VirtIOSerial *vser;
uint8_t *buf;
size_t len;
@@ -423,10 +436,15 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
len = 0;
buf = NULL;
- while (virtqueue_pop(vq, &elem)) {
+ for (;;) {
size_t cur_len;
- cur_len = iov_size(elem.out_sg, elem.out_num);
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+
+ cur_len = iov_size(elem->out_sg, elem->out_num);
/*
* Allocate a new buf only if we didn't have one previously or
* if the size of the buf differs
@@ -437,10 +455,11 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
buf = g_malloc(cur_len);
len = cur_len;
}
- iov_to_buf(elem.out_sg, elem.out_num, 0, buf, cur_len);
+ iov_to_buf(elem->out_sg, elem->out_num, 0, buf, cur_len);
handle_control_message(vser, buf, cur_len);
- virtqueue_push(vq, &elem, 0);
+ virtqueue_push(vq, elem, 0);
+ g_free(elem);
}
g_free(buf);
virtio_notify(vdev, vq);
@@ -620,16 +639,14 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
qemu_put_byte(f, port->host_connected);
elem_popped = 0;
- if (port->elem.out_num) {
+ if (port->elem) {
elem_popped = 1;
}
qemu_put_be32s(f, &elem_popped);
if (elem_popped) {
qemu_put_be32s(f, &port->iov_idx);
qemu_put_be64s(f, &port->iov_offset);
-
- qemu_put_buffer(f, (unsigned char *)&port->elem,
- sizeof(port->elem));
+ qemu_put_virtqueue_element(f, port->elem);
}
}
}
@@ -704,9 +721,8 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
qemu_get_be32s(f, &port->iov_idx);
qemu_get_be64s(f, &port->iov_offset);
- qemu_get_buffer(f, (unsigned char *)&port->elem,
- sizeof(port->elem));
- virtqueue_map(&port->elem);
+ port->elem =
+ qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
/*
* Port was throttled on source machine. Let's
@@ -928,7 +944,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
return;
}
- port->elem.out_num = 0;
+ port->elem = NULL;
}
static void virtser_port_device_plug(HotplugHandler *hotplug_dev,
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 1cb4002e0e..ddf3bfbef4 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -804,16 +804,15 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
}
#endif
- cmd = g_new(struct virtio_gpu_ctrl_command, 1);
- while (virtqueue_pop(vq, &cmd->elem)) {
+ cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
+ while (cmd) {
cmd->vq = vq;
cmd->error = 0;
cmd->finished = false;
cmd->waiting = false;
QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
- cmd = g_new(struct virtio_gpu_ctrl_command, 1);
+ cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
}
- g_free(cmd);
virtio_gpu_process_cmdq(g);
@@ -833,15 +832,20 @@ static void virtio_gpu_ctrl_bh(void *opaque)
static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
- VirtQueueElement elem;
+ VirtQueueElement *elem;
size_t s;
struct virtio_gpu_update_cursor cursor_info;
if (!virtio_queue_ready(vq)) {
return;
}
- while (virtqueue_pop(vq, &elem)) {
- s = iov_to_buf(elem.out_sg, elem.out_num, 0,
+ for (;;) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+
+ s = iov_to_buf(elem->out_sg, elem->out_num, 0,
&cursor_info, sizeof(cursor_info));
if (s != sizeof(cursor_info)) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -850,8 +854,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
} else {
update_cursor(g, &cursor_info);
}
- virtqueue_push(vq, &elem, 0);
+ virtqueue_push(vq, elem, 0);
virtio_notify(vdev, vq);
+ g_free(elem);
}
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 739cfa3bb9..4554eb88bc 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -290,7 +290,7 @@ static void acpi_align_size(GArray *blob, unsigned align)
/* FACS */
static void
-build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
+build_facs(GArray *table_data, GArray *linker)
{
AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs);
memcpy(&facs->signature, "FACS", 4);
@@ -336,7 +336,8 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
/* FADT */
static void
build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm,
- unsigned facs, unsigned dsdt)
+ unsigned facs, unsigned dsdt,
+ const char *oem_id, const char *oem_table_id)
{
AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
@@ -357,13 +358,13 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm,
fadt_setup(fadt, pm);
build_header(linker, table_data,
- (void *)fadt, "FACP", sizeof(*fadt), 1, NULL);
+ (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
}
static void
-build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
- PcGuestInfo *guest_info)
+build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu)
{
+ PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
int madt_start = table_data->len;
AcpiMultipleApicTable *madt;
@@ -376,7 +377,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
madt->local_apic_address = cpu_to_le32(APIC_DEFAULT_ADDRESS);
madt->flags = cpu_to_le32(1);
- for (i = 0; i < guest_info->apic_id_limit; i++) {
+ for (i = 0; i < pcms->apic_id_limit; i++) {
AcpiMadtProcessorApic *apic = acpi_data_push(table_data, sizeof *apic);
apic->type = ACPI_APIC_PROCESSOR;
apic->length = sizeof(*apic);
@@ -396,7 +397,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS);
io_apic->interrupt = cpu_to_le32(0);
- if (guest_info->apic_xrupt_override) {
+ if (pcms->apic_xrupt_override) {
intsrcovr = acpi_data_push(table_data, sizeof *intsrcovr);
intsrcovr->type = ACPI_APIC_XRUPT_OVERRIDE;
intsrcovr->length = sizeof(*intsrcovr);
@@ -427,7 +428,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu,
build_header(linker, table_data,
(void *)(table_data->data + madt_start), "APIC",
- table_data->len - madt_start, 1, NULL);
+ table_data->len - madt_start, 1, NULL, NULL);
}
/* Assign BSEL property to all buses. In the future, this can be changed
@@ -1935,24 +1936,114 @@ static Aml *build_q35_osc_method(void)
}
static void
-build_ssdt(GArray *table_data, GArray *linker,
+build_dsdt(GArray *table_data, GArray *linker,
AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
- PcPciInfo *pci, PcGuestInfo *guest_info)
+ PcPciInfo *pci)
{
+ CrsRangeEntry *entry;
+ Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs;
+ GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
+ GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
MachineState *machine = MACHINE(qdev_get_machine());
+ PCMachineState *pcms = PC_MACHINE(machine);
uint32_t nr_mem = machine->ram_slots;
- Aml *ssdt, *sb_scope, *scope, *pkg, *dev, *method, *crs, *field;
- PCIBus *bus = NULL;
- GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
- CrsRangeEntry *entry;
int root_bus_limit = 0xFF;
+ PCIBus *bus = NULL;
int i;
- ssdt = init_aml_allocator();
+ dsdt = init_aml_allocator();
/* Reserve space for header */
- acpi_data_push(ssdt->buf, sizeof(AcpiTableHeader));
+ acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
+
+ build_dbg_aml(dsdt);
+ if (misc->is_piix4) {
+ sb_scope = aml_scope("_SB");
+ dev = aml_device("PCI0");
+ aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(1)));
+ aml_append(sb_scope, dev);
+ aml_append(dsdt, sb_scope);
+
+ build_hpet_aml(dsdt);
+ build_piix4_pm(dsdt);
+ build_piix4_isa_bridge(dsdt);
+ build_isa_devices_aml(dsdt);
+ build_piix4_pci_hotplug(dsdt);
+ build_piix4_pci0_int(dsdt);
+ } else {
+ sb_scope = aml_scope("_SB");
+ aml_append(sb_scope,
+ aml_operation_region("PCST", AML_SYSTEM_IO, 0xae00, 0x0c));
+ aml_append(sb_scope,
+ aml_operation_region("PCSB", AML_SYSTEM_IO, 0xae0c, 0x01));
+ field = aml_field("PCSB", AML_ANY_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
+ aml_append(field, aml_named_field("PCIB", 8));
+ aml_append(sb_scope, field);
+ aml_append(dsdt, sb_scope);
+
+ sb_scope = aml_scope("_SB");
+ dev = aml_device("PCI0");
+ aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
+ aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(1)));
+ aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
+ aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
+ aml_append(dev, build_q35_osc_method());
+ aml_append(sb_scope, dev);
+ aml_append(dsdt, sb_scope);
+
+ build_hpet_aml(dsdt);
+ build_q35_isa_bridge(dsdt);
+ build_isa_devices_aml(dsdt);
+ build_q35_pci0_int(dsdt);
+ }
+
+ build_cpu_hotplug_aml(dsdt);
+ build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
+ pm->mem_hp_io_len);
+
+ scope = aml_scope("_GPE");
+ {
+ aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006")));
+
+ aml_append(scope, aml_method("_L00", 0, AML_NOTSERIALIZED));
+
+ if (misc->is_piix4) {
+ method = aml_method("_E01", 0, AML_NOTSERIALIZED);
+ aml_append(method,
+ aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
+ aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
+ aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
+ aml_append(scope, method);
+ } else {
+ aml_append(scope, aml_method("_L01", 0, AML_NOTSERIALIZED));
+ }
+
+ method = aml_method("_E02", 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD));
+ aml_append(scope, method);
+
+ method = aml_method("_E03", 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH));
+ aml_append(scope, method);
+
+ aml_append(scope, aml_method("_L04", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L05", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L06", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L07", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L08", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L09", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L0A", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L0B", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L0C", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L0D", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L0E", 0, AML_NOTSERIALIZED));
+ aml_append(scope, aml_method("_L0F", 0, AML_NOTSERIALIZED));
+ }
+ aml_append(dsdt, scope);
bus = PC_MACHINE(machine)->bus;
if (bus) {
@@ -1984,7 +2075,7 @@ build_ssdt(GArray *table_data, GArray *linker,
io_ranges, mem_ranges);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
- aml_append(ssdt, scope);
+ aml_append(dsdt, scope);
}
}
@@ -2068,7 +2159,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}
- aml_append(ssdt, scope);
+ aml_append(dsdt, scope);
/* create S3_ / S4_ / S5_ packages if necessary */
scope = aml_scope("\\");
@@ -2097,7 +2188,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(pkg, aml_int(0)); /* reserved */
aml_append(pkg, aml_int(0)); /* reserved */
aml_append(scope, aml_name_decl("_S5", pkg));
- aml_append(ssdt, scope);
+ aml_append(dsdt, scope);
if (misc->applesmc_io_base) {
scope = aml_scope("\\_SB.PCI0.ISA");
@@ -2116,7 +2207,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
- aml_append(ssdt, scope);
+ aml_append(dsdt, scope);
}
if (misc->pvpanic_port) {
@@ -2150,12 +2241,12 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, method);
aml_append(scope, dev);
- aml_append(ssdt, scope);
+ aml_append(dsdt, scope);
}
sb_scope = aml_scope("\\_SB");
{
- build_processor_devices(sb_scope, guest_info->apic_id_limit, cpu, pm);
+ build_processor_devices(sb_scope, pcms->apic_id_limit, cpu, pm);
build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base,
pm->mem_hp_io_len);
@@ -2189,14 +2280,14 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(sb_scope, scope);
}
}
- aml_append(ssdt, sb_scope);
+ aml_append(dsdt, sb_scope);
}
/* copy AML table into ACPI tables blob and patch header there */
- g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
+ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
build_header(linker, table_data,
- (void *)(table_data->data + table_data->len - ssdt->buf->len),
- "SSDT", ssdt->buf->len, 1, NULL);
+ (void *)(table_data->data + table_data->len - dsdt->buf->len),
+ "DSDT", dsdt->buf->len, 1, NULL, NULL);
free_aml_allocator();
}
@@ -2212,7 +2303,7 @@ build_hpet(GArray *table_data, GArray *linker)
hpet->timer_block_id = cpu_to_le32(0x8086a201);
hpet->addr.address = cpu_to_le64(HPET_BASE);
build_header(linker, table_data,
- (void *)hpet, "HPET", sizeof(*hpet), 1, NULL);
+ (void *)hpet, "HPET", sizeof(*hpet), 1, NULL, NULL);
}
static void
@@ -2235,7 +2326,7 @@ build_tpm_tcpa(GArray *table_data, GArray *linker, GArray *tcpalog)
sizeof(tcpa->log_area_start_address));
build_header(linker, table_data,
- (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL);
+ (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL);
acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE);
}
@@ -2252,7 +2343,7 @@ build_tpm2(GArray *table_data, GArray *linker)
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
build_header(linker, table_data,
- (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL);
+ (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
}
typedef enum {
@@ -2276,7 +2367,7 @@ acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
}
static void
-build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
+build_srat(GArray *table_data, GArray *linker)
{
AcpiSystemResourceAffinityTable *srat;
AcpiSratProcessorAffinity *core;
@@ -2297,12 +2388,12 @@ build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
srat->reserved1 = cpu_to_le32(1);
core = (void *)(srat + 1);
- for (i = 0; i < guest_info->apic_id_limit; ++i) {
+ for (i = 0; i < pcms->apic_id_limit; ++i) {
core = acpi_data_push(table_data, sizeof *core);
core->type = ACPI_SRAT_PROCESSOR;
core->length = sizeof(*core);
core->local_apic_id = i;
- curnode = guest_info->node_cpu[i];
+ curnode = pcms->node_cpu[i];
core->proximity_lo = curnode;
memset(core->proximity_hi, 0, 3);
core->local_sapic_eid = 0;
@@ -2319,33 +2410,33 @@ build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
numamem = acpi_data_push(table_data, sizeof *numamem);
acpi_build_srat_memory(numamem, 0, 640*1024, 0, MEM_AFFINITY_ENABLED);
next_base = 1024 * 1024;
- for (i = 1; i < guest_info->numa_nodes + 1; ++i) {
+ for (i = 1; i < pcms->numa_nodes + 1; ++i) {
mem_base = next_base;
- mem_len = guest_info->node_mem[i - 1];
+ mem_len = pcms->node_mem[i - 1];
if (i == 1) {
mem_len -= 1024 * 1024;
}
next_base = mem_base + mem_len;
/* Cut out the ACPI_PCI hole */
- if (mem_base <= guest_info->ram_size_below_4g &&
- next_base > guest_info->ram_size_below_4g) {
- mem_len -= next_base - guest_info->ram_size_below_4g;
+ if (mem_base <= pcms->below_4g_mem_size &&
+ next_base > pcms->below_4g_mem_size) {
+ mem_len -= next_base - pcms->below_4g_mem_size;
if (mem_len > 0) {
numamem = acpi_data_push(table_data, sizeof *numamem);
acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
MEM_AFFINITY_ENABLED);
}
mem_base = 1ULL << 32;
- mem_len = next_base - guest_info->ram_size_below_4g;
- next_base += (1ULL << 32) - guest_info->ram_size_below_4g;
+ mem_len = next_base - pcms->below_4g_mem_size;
+ next_base += (1ULL << 32) - pcms->below_4g_mem_size;
}
numamem = acpi_data_push(table_data, sizeof *numamem);
acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
MEM_AFFINITY_ENABLED);
}
slots = (table_data->len - numa_start) / sizeof *numamem;
- for (; slots < guest_info->numa_nodes + 2; slots++) {
+ for (; slots < pcms->numa_nodes + 2; slots++) {
numamem = acpi_data_push(table_data, sizeof *numamem);
acpi_build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
}
@@ -2366,7 +2457,7 @@ build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
build_header(linker, table_data,
(void *)(table_data->data + srat_start),
"SRAT",
- table_data->len - srat_start, 1, NULL);
+ table_data->len - srat_start, 1, NULL, NULL);
}
static void
@@ -2395,7 +2486,7 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info)
} else {
sig = "MCFG";
}
- build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL);
+ build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL);
}
static void
@@ -2419,117 +2510,7 @@ build_dmar_q35(GArray *table_data, GArray *linker)
drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR);
build_header(linker, table_data, (void *)(table_data->data + dmar_start),
- "DMAR", table_data->len - dmar_start, 1, NULL);
-}
-
-static void
-build_dsdt(GArray *table_data, GArray *linker,
- AcpiPmInfo *pm, AcpiMiscInfo *misc)
-{
- Aml *dsdt, *sb_scope, *scope, *dev, *method, *field;
- MachineState *machine = MACHINE(qdev_get_machine());
- uint32_t nr_mem = machine->ram_slots;
-
- dsdt = init_aml_allocator();
-
- /* Reserve space for header */
- acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
-
- build_dbg_aml(dsdt);
- if (misc->is_piix4) {
- sb_scope = aml_scope("_SB");
- dev = aml_device("PCI0");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_int(1)));
- aml_append(sb_scope, dev);
- aml_append(dsdt, sb_scope);
-
- build_hpet_aml(dsdt);
- build_piix4_pm(dsdt);
- build_piix4_isa_bridge(dsdt);
- build_isa_devices_aml(dsdt);
- build_piix4_pci_hotplug(dsdt);
- build_piix4_pci0_int(dsdt);
- } else {
- sb_scope = aml_scope("_SB");
- aml_append(sb_scope,
- aml_operation_region("PCST", AML_SYSTEM_IO, 0xae00, 0x0c));
- aml_append(sb_scope,
- aml_operation_region("PCSB", AML_SYSTEM_IO, 0xae0c, 0x01));
- field = aml_field("PCSB", AML_ANY_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
- aml_append(field, aml_named_field("PCIB", 8));
- aml_append(sb_scope, field);
- aml_append(dsdt, sb_scope);
-
- sb_scope = aml_scope("_SB");
- dev = aml_device("PCI0");
- aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
- aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
- aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
- aml_append(dev, aml_name_decl("_UID", aml_int(1)));
- aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
- aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
- aml_append(dev, build_q35_osc_method());
- aml_append(sb_scope, dev);
- aml_append(dsdt, sb_scope);
-
- build_hpet_aml(dsdt);
- build_q35_isa_bridge(dsdt);
- build_isa_devices_aml(dsdt);
- build_q35_pci0_int(dsdt);
- }
-
- build_cpu_hotplug_aml(dsdt);
- build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
- pm->mem_hp_io_len);
-
- scope = aml_scope("_GPE");
- {
- aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006")));
-
- aml_append(scope, aml_method("_L00", 0, AML_NOTSERIALIZED));
-
- if (misc->is_piix4) {
- method = aml_method("_E01", 0, AML_NOTSERIALIZED);
- aml_append(method,
- aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
- aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
- aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
- aml_append(scope, method);
- } else {
- aml_append(scope, aml_method("_L01", 0, AML_NOTSERIALIZED));
- }
-
- method = aml_method("_E02", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD));
- aml_append(scope, method);
-
- method = aml_method("_E03", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH));
- aml_append(scope, method);
-
- aml_append(scope, aml_method("_L04", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L05", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L06", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L07", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L08", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L09", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0A", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0B", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0C", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0D", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0E", 0, AML_NOTSERIALIZED));
- aml_append(scope, aml_method("_L0F", 0, AML_NOTSERIALIZED));
- }
- aml_append(dsdt, scope);
-
- /* copy AML table into ACPI tables blob and patch header there */
- g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
- build_header(linker, table_data,
- (void *)(table_data->data + table_data->len - dsdt->buf->len),
- "DSDT", dsdt->buf->len, 1, NULL);
- free_aml_allocator();
+ "DMAR", table_data->len - dmar_start, 1, NULL, NULL);
}
static GArray *
@@ -2562,7 +2543,6 @@ struct AcpiBuildState {
MemoryRegion *table_mr;
/* Is table patched? */
uint8_t patched;
- PcGuestInfo *guest_info;
void *rsdp;
MemoryRegion *rsdp_mr;
MemoryRegion *linker_mr;
@@ -2608,10 +2588,12 @@ static bool acpi_has_nvdimm(void)
}
static
-void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
+void acpi_build(AcpiBuildTables *tables)
{
+ PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
GArray *table_offsets;
- unsigned facs, ssdt, dsdt, rsdt;
+ unsigned facs, dsdt, rsdt, fadt;
AcpiCpuInfo cpu;
AcpiPmInfo pm;
AcpiMiscInfo misc;
@@ -2620,11 +2602,13 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
uint8_t *u;
size_t aml_len = 0;
GArray *tables_blob = tables->table_data;
+ AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL };
acpi_get_cpu_info(&cpu);
acpi_get_pm_info(&pm);
acpi_get_misc_info(&misc);
acpi_get_pci_info(&pci);
+ acpi_get_slic_oem(&slic_oem);
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -2640,11 +2624,11 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
* requirements.
*/
facs = tables_blob->len;
- build_facs(tables_blob, tables->linker, guest_info);
+ build_facs(tables_blob, tables->linker);
/* DSDT is pointed to by FADT */
dsdt = tables_blob->len;
- build_dsdt(tables_blob, tables->linker, &pm, &misc);
+ build_dsdt(tables_blob, tables->linker, &cpu, &pm, &misc, &pci);
/* Count the size of the DSDT and SSDT, we will need it for legacy
* sizing of ACPI tables.
@@ -2652,17 +2636,14 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
aml_len += tables_blob->len - dsdt;
/* ACPI tables pointed to by RSDT */
+ fadt = tables_blob->len;
acpi_add_table(table_offsets, tables_blob);
- build_fadt(tables_blob, tables->linker, &pm, facs, dsdt);
-
- ssdt = tables_blob->len;
- acpi_add_table(table_offsets, tables_blob);
- build_ssdt(tables_blob, tables->linker, &cpu, &pm, &misc, &pci,
- guest_info);
- aml_len += tables_blob->len - ssdt;
+ build_fadt(tables_blob, tables->linker, &pm, facs, dsdt,
+ slic_oem.id, slic_oem.table_id);
+ aml_len += tables_blob->len - fadt;
acpi_add_table(table_offsets, tables_blob);
- build_madt(tables_blob, tables->linker, &cpu, guest_info);
+ build_madt(tables_blob, tables->linker, &cpu);
if (misc.has_hpet) {
acpi_add_table(table_offsets, tables_blob);
@@ -2677,9 +2658,9 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
build_tpm2(tables_blob, tables->linker);
}
}
- if (guest_info->numa_nodes) {
+ if (pcms->numa_nodes) {
acpi_add_table(table_offsets, tables_blob);
- build_srat(tables_blob, tables->linker, guest_info);
+ build_srat(tables_blob, tables->linker);
}
if (acpi_get_mcfg(&mcfg)) {
acpi_add_table(table_offsets, tables_blob);
@@ -2704,7 +2685,8 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
/* RSDT is pointed to by RSDP */
rsdt = tables_blob->len;
- build_rsdt(tables_blob, tables->linker, table_offsets);
+ build_rsdt(tables_blob, tables->linker, table_offsets,
+ slic_oem.id, slic_oem.table_id);
/* RSDP is in FSEG memory, so allocate it separately */
build_rsdp(tables->rsdp, tables->linker, rsdt);
@@ -2726,12 +2708,12 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
*
* All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration.
*/
- if (guest_info->legacy_acpi_table_size) {
+ if (pcmc->legacy_acpi_table_size) {
/* Subtracting aml_len gives the size of fixed tables. Then add the
* size of the PIIX4 DSDT/SSDT in QEMU 2.0.
*/
int legacy_aml_len =
- guest_info->legacy_acpi_table_size +
+ pcmc->legacy_acpi_table_size +
ACPI_BUILD_LEGACY_CPU_AML_SIZE * max_cpus;
int legacy_table_size =
ROUND_UP(tables_blob->len - aml_len + legacy_aml_len,
@@ -2783,7 +2765,7 @@ static void acpi_build_update(void *build_opaque)
acpi_build_tables_init(&tables);
- acpi_build(build_state->guest_info, &tables);
+ acpi_build(&tables);
acpi_ram_update(build_state->table_mr, tables.table_data);
@@ -2821,17 +2803,19 @@ static const VMStateDescription vmstate_acpi_build = {
},
};
-void acpi_setup(PcGuestInfo *guest_info)
+void acpi_setup(void)
{
+ PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
AcpiBuildTables tables;
AcpiBuildState *build_state;
- if (!guest_info->fw_cfg) {
+ if (!pcms->fw_cfg) {
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
return;
}
- if (!guest_info->has_acpi_build) {
+ if (!pcmc->has_acpi_build) {
ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n");
return;
}
@@ -2843,12 +2827,10 @@ void acpi_setup(PcGuestInfo *guest_info)
build_state = g_malloc0(sizeof *build_state);
- build_state->guest_info = guest_info;
-
acpi_set_pci_info();
acpi_build_tables_init(&tables);
- acpi_build(build_state->guest_info, &tables);
+ acpi_build(&tables);
/* Now expose it all to Guest */
build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
@@ -2859,10 +2841,10 @@ void acpi_setup(PcGuestInfo *guest_info)
build_state->linker_mr =
acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
- fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
+ fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
- if (!guest_info->rsdp_in_ram) {
+ if (!pcmc->rsdp_in_ram) {
/*
* Keep for compatibility with old machine types.
* Though RSDP is small, its contents isn't immutable, so
@@ -2871,7 +2853,7 @@ void acpi_setup(PcGuestInfo *guest_info)
uint32_t rsdp_size = acpi_data_len(tables.rsdp);
build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
- fw_cfg_add_file_callback(guest_info->fw_cfg, ACPI_BUILD_RSDP_FILE,
+ fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
acpi_build_update, build_state,
build_state->rsdp, rsdp_size);
build_state->rsdp_mr = NULL;
diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h
index e57b1aafdc..148c0f9977 100644
--- a/hw/i386/acpi-build.h
+++ b/hw/i386/acpi-build.h
@@ -4,6 +4,6 @@
#include "qemu/typedefs.h"
-void acpi_setup(PcGuestInfo *);
+void acpi_setup(void);
#endif
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index c25b1fd242..347718f938 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -153,14 +153,27 @@ static gboolean vtd_hash_remove_by_domain(gpointer key, gpointer value,
return entry->domain_id == domain_id;
}
+/* The shift of an addr for a certain level of paging structure */
+static inline uint32_t vtd_slpt_level_shift(uint32_t level)
+{
+ return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
+}
+
+static inline uint64_t vtd_slpt_level_page_mask(uint32_t level)
+{
+ return ~((1ULL << vtd_slpt_level_shift(level)) - 1);
+}
+
static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
gpointer user_data)
{
VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value;
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
- uint64_t gfn = info->gfn & info->mask;
+ uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
+ uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
return (entry->domain_id == info->domain_id) &&
- ((entry->gfn & info->mask) == gfn);
+ (((entry->gfn & info->mask) == gfn) ||
+ (entry->gfn == gfn_tlb));
}
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
@@ -194,24 +207,46 @@ static void vtd_reset_iotlb(IntelIOMMUState *s)
g_hash_table_remove_all(s->iotlb);
}
+static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint8_t source_id,
+ uint32_t level)
+{
+ return gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT) |
+ ((uint64_t)(level) << VTD_IOTLB_LVL_SHIFT);
+}
+
+static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level)
+{
+ return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K;
+}
+
static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
hwaddr addr)
{
+ VTDIOTLBEntry *entry;
uint64_t key;
+ int level;
+
+ for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
+ key = vtd_get_iotlb_key(vtd_get_iotlb_gfn(addr, level),
+ source_id, level);
+ entry = g_hash_table_lookup(s->iotlb, &key);
+ if (entry) {
+ goto out;
+ }
+ }
- key = (addr >> VTD_PAGE_SHIFT_4K) |
- ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT);
- return g_hash_table_lookup(s->iotlb, &key);
-
+out:
+ return entry;
}
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
uint16_t domain_id, hwaddr addr, uint64_t slpte,
- bool read_flags, bool write_flags)
+ bool read_flags, bool write_flags,
+ uint32_t level)
{
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
uint64_t *key = g_malloc(sizeof(*key));
- uint64_t gfn = addr >> VTD_PAGE_SHIFT_4K;
+ uint64_t gfn = vtd_get_iotlb_gfn(addr, level);
VTD_DPRINTF(CACHE, "update iotlb sid 0x%"PRIx16 " gpa 0x%"PRIx64
" slpte 0x%"PRIx64 " did 0x%"PRIx16, source_id, addr, slpte,
@@ -226,7 +261,8 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
entry->slpte = slpte;
entry->read_flags = read_flags;
entry->write_flags = write_flags;
- *key = gfn | ((uint64_t)(source_id) << VTD_IOTLB_SID_SHIFT);
+ entry->mask = vtd_slpt_level_page_mask(level);
+ *key = vtd_get_iotlb_key(gfn, source_id, level);
g_hash_table_replace(s->iotlb, key, entry);
}
@@ -501,12 +537,6 @@ static inline dma_addr_t vtd_get_slpt_base_from_context(VTDContextEntry *ce)
return ce->lo & VTD_CONTEXT_ENTRY_SLPTPTR;
}
-/* The shift of an addr for a certain level of paging structure */
-static inline uint32_t vtd_slpt_level_shift(uint32_t level)
-{
- return VTD_PAGE_SHIFT_4K + (level - 1) * VTD_SL_LEVEL_BITS;
-}
-
static inline uint64_t vtd_get_slpte_addr(uint64_t slpte)
{
return slpte & VTD_SL_PT_BASE_ADDR_MASK;
@@ -762,7 +792,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
VTDContextEntry ce;
uint8_t bus_num = pci_bus_num(bus);
VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry;
- uint64_t slpte;
+ uint64_t slpte, page_mask;
uint32_t level;
uint16_t source_id = vtd_make_source_id(bus_num, devfn);
int ret_fr;
@@ -802,6 +832,7 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
slpte = iotlb_entry->slpte;
reads = iotlb_entry->read_flags;
writes = iotlb_entry->write_flags;
+ page_mask = iotlb_entry->mask;
goto out;
}
/* Try to fetch context-entry from cache first */
@@ -848,12 +879,13 @@ static void vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
return;
}
+ page_mask = vtd_slpt_level_page_mask(level);
vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte,
- reads, writes);
+ reads, writes, level);
out:
- entry->iova = addr & VTD_PAGE_MASK_4K;
- entry->translated_addr = vtd_get_slpte_addr(slpte) & VTD_PAGE_MASK_4K;
- entry->addr_mask = ~VTD_PAGE_MASK_4K;
+ entry->iova = addr & page_mask;
+ entry->translated_addr = vtd_get_slpte_addr(slpte) & page_mask;
+ entry->addr_mask = ~page_mask;
entry->perm = (writes ? 2 : 0) + (reads ? 1 : 0);
}
@@ -991,7 +1023,7 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
assert(am <= VTD_MAMV);
info.domain_id = domain_id;
- info.gfn = addr >> VTD_PAGE_SHIFT_4K;
+ info.addr = addr;
info.mask = ~((1 << am) - 1);
g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info);
}
@@ -1917,7 +1949,7 @@ static void vtd_init(IntelIOMMUState *s)
s->iq_last_desc_type = VTD_INV_DESC_NONE;
s->next_frcd_reg = 0;
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND | VTD_CAP_MGAW |
- VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI;
+ VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS;
s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
vtd_reset_context_cache(s);
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index ba288ab1d9..e5f514c6e3 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -113,6 +113,7 @@
/* The shift of source_id in the key of IOTLB hash table */
#define VTD_IOTLB_SID_SHIFT 36
+#define VTD_IOTLB_LVL_SHIFT 44
#define VTD_IOTLB_MAX_SIZE 1024 /* Max size of the hash table */
/* IOTLB_REG */
@@ -185,9 +186,10 @@
#define VTD_CAP_ND (((VTD_DOMAIN_ID_SHIFT - 4) / 2) & 7ULL)
#define VTD_MGAW 39 /* Maximum Guest Address Width */
#define VTD_CAP_MGAW (((VTD_MGAW - 1) & 0x3fULL) << 16)
-#define VTD_MAMV 9ULL
+#define VTD_MAMV 18ULL
#define VTD_CAP_MAMV (VTD_MAMV << 48)
#define VTD_CAP_PSI (1ULL << 39)
+#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
/* Supported Adjusted Guest Address Widths */
#define VTD_CAP_SAGAW_SHIFT 8
@@ -320,7 +322,7 @@ typedef struct VTDInvDesc VTDInvDesc;
/* Information about page-selective IOTLB invalidate */
struct VTDIOTLBPageInvInfo {
uint16_t domain_id;
- uint64_t gfn;
+ uint64_t addr;
uint8_t mask;
};
typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index b28bac4b66..af2fe84ffb 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1156,18 +1156,12 @@ typedef struct PcRomPciInfo {
uint64_t w64_max;
} PcRomPciInfo;
-typedef struct PcGuestInfoState {
- PcGuestInfo info;
- Notifier machine_done;
-} PcGuestInfoState;
-
static
-void pc_guest_info_machine_done(Notifier *notifier, void *data)
+void pc_machine_done(Notifier *notifier, void *data)
{
- PcGuestInfoState *guest_info_state = container_of(notifier,
- PcGuestInfoState,
- machine_done);
- PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
+ PCMachineState *pcms = container_of(notifier,
+ PCMachineState, machine_done);
+ PCIBus *bus = pcms->bus;
if (bus) {
int extra_hosts = 0;
@@ -1178,51 +1172,46 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data)
extra_hosts++;
}
}
- if (extra_hosts && guest_info_state->info.fw_cfg) {
+ if (extra_hosts && pcms->fw_cfg) {
uint64_t *val = g_malloc(sizeof(*val));
*val = cpu_to_le64(extra_hosts);
- fw_cfg_add_file(guest_info_state->info.fw_cfg,
+ fw_cfg_add_file(pcms->fw_cfg,
"etc/extra-pci-roots", val, sizeof(*val));
}
}
- acpi_setup(&guest_info_state->info);
+ acpi_setup();
}
-PcGuestInfo *pc_guest_info_init(PCMachineState *pcms)
+void pc_guest_info_init(PCMachineState *pcms)
{
- PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
- PcGuestInfo *guest_info = &guest_info_state->info;
int i, j;
- guest_info->ram_size_below_4g = pcms->below_4g_mem_size;
- guest_info->ram_size = pcms->below_4g_mem_size + pcms->above_4g_mem_size;
- guest_info->apic_id_limit = pc_apic_id_limit(max_cpus);
- guest_info->apic_xrupt_override = kvm_allows_irq0_override();
- guest_info->numa_nodes = nb_numa_nodes;
- guest_info->node_mem = g_malloc0(guest_info->numa_nodes *
- sizeof *guest_info->node_mem);
+ pcms->apic_id_limit = pc_apic_id_limit(max_cpus);
+ pcms->apic_xrupt_override = kvm_allows_irq0_override();
+ pcms->numa_nodes = nb_numa_nodes;
+ pcms->node_mem = g_malloc0(pcms->numa_nodes *
+ sizeof *pcms->node_mem);
for (i = 0; i < nb_numa_nodes; i++) {
- guest_info->node_mem[i] = numa_info[i].node_mem;
+ pcms->node_mem[i] = numa_info[i].node_mem;
}
- guest_info->node_cpu = g_malloc0(guest_info->apic_id_limit *
- sizeof *guest_info->node_cpu);
+ pcms->node_cpu = g_malloc0(pcms->apic_id_limit *
+ sizeof *pcms->node_cpu);
for (i = 0; i < max_cpus; i++) {
unsigned int apic_id = x86_cpu_apic_id_from_index(i);
- assert(apic_id < guest_info->apic_id_limit);
+ assert(apic_id < pcms->apic_id_limit);
for (j = 0; j < nb_numa_nodes; j++) {
if (test_bit(i, numa_info[j].node_cpu)) {
- guest_info->node_cpu[apic_id] = j;
+ pcms->node_cpu[apic_id] = j;
break;
}
}
}
- guest_info_state->machine_done.notify = pc_guest_info_machine_done;
- qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
- return guest_info;
+ pcms->machine_done.notify = pc_machine_done;
+ qemu_add_machine_init_done_notifier(&pcms->machine_done);
}
/* setup pci memory address space mapping into system address space */
@@ -1262,8 +1251,7 @@ void pc_acpi_init(const char *default_dsdt)
}
}
-FWCfgState *xen_load_linux(PCMachineState *pcms,
- PcGuestInfo *guest_info)
+void xen_load_linux(PCMachineState *pcms)
{
int i;
FWCfgState *fw_cfg;
@@ -1279,15 +1267,13 @@ FWCfgState *xen_load_linux(PCMachineState *pcms,
!strcmp(option_rom[i].name, "multiboot.bin"));
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
}
- guest_info->fw_cfg = fw_cfg;
- return fw_cfg;
+ pcms->fw_cfg = fw_cfg;
}
-FWCfgState *pc_memory_init(PCMachineState *pcms,
- MemoryRegion *system_memory,
- MemoryRegion *rom_memory,
- MemoryRegion **ram_memory,
- PcGuestInfo *guest_info)
+void pc_memory_init(PCMachineState *pcms,
+ MemoryRegion *system_memory,
+ MemoryRegion *rom_memory,
+ MemoryRegion **ram_memory)
{
int linux_boot, i;
MemoryRegion *ram, *option_rom_mr;
@@ -1324,7 +1310,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM);
}
- if (!guest_info->has_reserved_memory &&
+ if (!pcmc->has_reserved_memory &&
(machine->ram_slots ||
(machine->maxram_size > machine->ram_size))) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -1335,7 +1321,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
}
/* initialize hotplug memory address space */
- if (guest_info->has_reserved_memory &&
+ if (pcmc->has_reserved_memory &&
(machine->ram_size < machine->maxram_size)) {
ram_addr_t hotplug_mem_size =
machine->maxram_size - machine->ram_size;
@@ -1375,7 +1361,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
}
/* Initialize PC system firmware */
- pc_system_firmware_init(rom_memory, guest_info->isapc_ram_fw);
+ pc_system_firmware_init(rom_memory, !pcmc->pci_enabled);
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
@@ -1390,7 +1376,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
rom_set_fw(fw_cfg);
- if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) {
+ if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) {
uint64_t *val = g_malloc(sizeof(*val));
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
uint64_t res_mem_end = pcms->hotplug_memory.base;
@@ -1409,8 +1395,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms,
for (i = 0; i < nb_option_roms; i++) {
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
}
- guest_info->fw_cfg = fw_cfg;
- return fw_cfg;
+ pcms->fw_cfg = fw_cfg;
}
qemu_irq pc_allocate_cpu_irq(void)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9951d6e1d5..6f8c2cd816 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -85,7 +85,6 @@ static void pc_init1(MachineState *machine,
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
MemoryRegion *rom_memory;
- PcGuestInfo *guest_info;
ram_addr_t lowmem;
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory).
@@ -141,14 +140,7 @@ static void pc_init1(MachineState *machine,
rom_memory = system_memory;
}
- guest_info = pc_guest_info_init(pcms);
-
- guest_info->has_acpi_build = pcmc->has_acpi_build;
- guest_info->legacy_acpi_table_size = pcmc->legacy_acpi_table_size;
-
- guest_info->isapc_ram_fw = !pcmc->pci_enabled;
- guest_info->has_reserved_memory = pcmc->has_reserved_memory;
- guest_info->rsdp_in_ram = pcmc->rsdp_in_ram;
+ pc_guest_info_init(pcms);
if (pcmc->smbios_defaults) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -162,10 +154,10 @@ static void pc_init1(MachineState *machine,
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
pc_memory_init(pcms, system_memory,
- rom_memory, &ram_memory, guest_info);
+ rom_memory, &ram_memory);
} else if (machine->kernel_filename != NULL) {
/* For xen HVM direct kernel boot, load linux here */
- xen_load_linux(pcms, guest_info);
+ xen_load_linux(pcms);
}
gsi_state = g_malloc0(sizeof(*gsi_state));
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 56be9b1d16..208a224226 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -71,7 +71,6 @@ static void pc_q35_init(MachineState *machine)
int i;
ICH9LPCState *ich9_lpc;
PCIDevice *ahci;
- PcGuestInfo *guest_info;
ram_addr_t lowmem;
DriveInfo *hd[MAX_SATA_PORTS];
MachineClass *mc = MACHINE_GET_CLASS(machine);
@@ -134,16 +133,7 @@ static void pc_q35_init(MachineState *machine)
rom_memory = get_system_memory();
}
- guest_info = pc_guest_info_init(pcms);
- guest_info->isapc_ram_fw = false;
- guest_info->has_acpi_build = pcmc->has_acpi_build;
- guest_info->has_reserved_memory = pcmc->has_reserved_memory;
- guest_info->rsdp_in_ram = pcmc->rsdp_in_ram;
-
- /* Migration was not supported in 2.0 for Q35, so do not bother
- * with this hack (see hw/i386/acpi-build.c).
- */
- guest_info->legacy_acpi_table_size = 0;
+ pc_guest_info_init(pcms);
if (pcmc->smbios_defaults) {
/* These values are guest ABI, do not change */
@@ -156,7 +146,7 @@ static void pc_q35_init(MachineState *machine)
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
pc_memory_init(pcms, get_system_memory(),
- rom_memory, &ram_memory, guest_info);
+ rom_memory, &ram_memory);
}
/* irq lines */
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index f12ed8a504..5061f4cf7a 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -17,7 +17,7 @@
void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
{
- VirtQueueElement elem;
+ VirtQueueElement *elem;
unsigned have, need;
int i, len;
@@ -50,14 +50,16 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
/* ... and finally pass them to the guest */
for (i = 0; i < vinput->qindex; i++) {
- if (!virtqueue_pop(vinput->evt, &elem)) {
+ elem = virtqueue_pop(vinput->evt, sizeof(VirtQueueElement));
+ if (!elem) {
/* should not happen, we've checked for space beforehand */
fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
return;
}
- len = iov_from_buf(elem.in_sg, elem.in_num,
+ len = iov_from_buf(elem->in_sg, elem->in_num,
0, vinput->queue+i, sizeof(virtio_input_event));
- virtqueue_push(vinput->evt, &elem, len);
+ virtqueue_push(vinput->evt, elem, len);
+ g_free(elem);
}
virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
vinput->qindex = 0;
@@ -73,17 +75,23 @@ static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
VirtIOInput *vinput = VIRTIO_INPUT(vdev);
virtio_input_event event;
- VirtQueueElement elem;
+ VirtQueueElement *elem;
int len;
- while (virtqueue_pop(vinput->sts, &elem)) {
+ for (;;) {
+ elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+
memset(&event, 0, sizeof(event));
- len = iov_to_buf(elem.out_sg, elem.out_num,
+ len = iov_to_buf(elem->out_sg, elem->out_num,
0, &event, sizeof(event));
if (vic->handle_status) {
vic->handle_status(vinput, &event);
}
- virtqueue_push(vinput->sts, &elem, len);
+ virtqueue_push(vinput->sts, elem, len);
+ g_free(elem);
}
virtio_notify(vdev, vinput->sts);
}
diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c
index dcdab035d6..e1ad19b8db 100644
--- a/hw/ipmi/ipmi_bmc_sim.c
+++ b/hw/ipmi/ipmi_bmc_sim.c
@@ -23,32 +23,36 @@
*/
#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
#include "qemu/timer.h"
#include "hw/ipmi/ipmi.h"
#include "qemu/error-report.h"
#define IPMI_NETFN_CHASSIS 0x00
-#define IPMI_NETFN_CHASSIS_MAXCMD 0x03
#define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
#define IPMI_CMD_GET_CHASSIS_STATUS 0x01
#define IPMI_CMD_CHASSIS_CONTROL 0x02
+#define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
#define IPMI_NETFN_SENSOR_EVENT 0x04
-#define IPMI_NETFN_SENSOR_EVENT_MAXCMD 0x2e
#define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
#define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
#define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
#define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
#define IPMI_CMD_GET_SENSOR_READING 0x2d
+#define IPMI_CMD_SET_SENSOR_TYPE 0x2e
+#define IPMI_CMD_GET_SENSOR_TYPE 0x2f
/* #define IPMI_NETFN_APP 0x06 In ipmi.h */
-#define IPMI_NETFN_APP_MAXCMD 0x36
#define IPMI_CMD_GET_DEVICE_ID 0x01
#define IPMI_CMD_COLD_RESET 0x02
#define IPMI_CMD_WARM_RESET 0x03
+#define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
+#define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
+#define IPMI_CMD_GET_DEVICE_GUID 0x08
#define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
#define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
#define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
@@ -61,7 +65,6 @@
#define IPMI_CMD_READ_EVT_MSG_BUF 0x35
#define IPMI_NETFN_STORAGE 0x0a
-#define IPMI_NETFN_STORAGE_MAXCMD 0x4a
#define IPMI_CMD_GET_SDR_REP_INFO 0x20
#define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
@@ -197,6 +200,11 @@ struct IPMIBmcSim {
uint8_t mfg_id[3];
uint8_t product_id[2];
+ uint8_t restart_cause;
+
+ uint8_t acpi_power_state[2];
+ uint8_t uuid[16];
+
IPMISel sel;
IPMISdr sdr;
IPMISensor sensors[MAX_SENSORS];
@@ -256,7 +264,7 @@ struct IPMIBmcSim {
do { \
if (*rsp_len >= max_rsp_len) { \
rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \
- goto out; \
+ return; \
} \
rsp[(*rsp_len)++] = (b); \
} while (0)
@@ -265,7 +273,7 @@ struct IPMIBmcSim {
#define IPMI_CHECK_CMD_LEN(l) \
if (cmd_len < l) { \
rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \
- goto out; \
+ return; \
}
/* Check that the reservation in the command is valid. */
@@ -273,7 +281,7 @@ struct IPMIBmcSim {
do { \
if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \
rsp[2] = IPMI_CC_INVALID_RESERVATION; \
- goto out; \
+ return; \
} \
} while (0)
@@ -322,14 +330,18 @@ static void sdr_inc_reservation(IPMISdr *sdr)
}
}
-static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry,
+static int sdr_add_entry(IPMIBmcSim *ibs,
+ const struct ipmi_sdr_header *sdrh_entry,
unsigned int len, uint16_t *recid)
{
- if ((len < 5) || (len > 255)) {
+ struct ipmi_sdr_header *sdrh =
+ (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
+
+ if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
return 1;
}
- if (entry[4] != len - 5) {
+ if (ipmi_sdr_length(sdrh_entry) != len) {
return 1;
}
@@ -338,10 +350,10 @@ static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry,
return 1;
}
- memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len);
- ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff;
- ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
- ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */
+ memcpy(sdrh, sdrh_entry, len);
+ sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
+ sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
+ sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
if (recid) {
*recid = ibs->sdr.next_rec_id;
@@ -359,8 +371,10 @@ static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
unsigned int pos = *retpos;
while (pos < sdr->next_free) {
- uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8);
- unsigned int nextpos = pos + sdr->sdr[pos + 4];
+ struct ipmi_sdr_header *sdrh =
+ (struct ipmi_sdr_header *) &sdr->sdr[pos];
+ uint16_t trec = ipmi_sdr_recid(sdrh);
+ unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
if (trec == recid) {
if (nextrec) {
@@ -451,14 +465,12 @@ static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
}
if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
- goto out;
+ return;
}
memcpy(ibs->evtbuf, evt, 16);
ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
k->set_atn(s, 1, attn_irq_enabled(ibs));
- out:
- return;
}
static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
@@ -511,29 +523,32 @@ static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
pos = 0;
for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
- uint8_t *sdr = s->sdr.sdr + pos;
- unsigned int len = sdr[4];
+ struct ipmi_sdr_compact *sdr =
+ (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
+ unsigned int len = sdr->header.rec_length;
if (len < 20) {
continue;
}
- if ((sdr[3] < 1) || (sdr[3] > 2)) {
+ if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
continue; /* Not a sensor SDR we set from */
}
- if (sdr[7] > MAX_SENSORS) {
+ if (sdr->sensor_owner_number > MAX_SENSORS) {
continue;
}
- sens = s->sensors + sdr[7];
+ sens = s->sensors + sdr->sensor_owner_number;
IPMI_SENSOR_SET_PRESENT(sens, 1);
- IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1);
- IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1);
- sens->assert_suppt = sdr[14] | (sdr[15] << 8);
- sens->deassert_suppt = sdr[16] | (sdr[17] << 8);
- sens->states_suppt = sdr[18] | (sdr[19] << 8);
- sens->sensor_type = sdr[12];
- sens->evt_reading_type_code = sdr[13] & 0x7f;
+ IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
+ IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
+ sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
+ sens->deassert_suppt =
+ sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
+ sens->states_suppt =
+ sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
+ sens->sensor_type = sdr->sensor_type;
+ sens->evt_reading_type_code = sdr->reading_type & 0x7f;
/* Enable all the events that are supported. */
sens->assert_enable = sens->assert_suppt;
@@ -579,6 +594,11 @@ static void ipmi_sim_handle_command(IPMIBmc *b,
/* Set up the response, set the low bit of NETFN. */
/* Note that max_rsp_len must be at least 3 */
+ if (max_rsp_len < 3) {
+ rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
+ goto out;
+ }
+
IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
IPMI_ADD_RSP_DATA(cmd[1]);
IPMI_ADD_RSP_DATA(0); /* Assume success */
@@ -696,8 +716,6 @@ static void chassis_capabilities(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
- out:
- return;
}
static void chassis_status(IPMIBmcSim *ibs,
@@ -709,8 +727,6 @@ static void chassis_status(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA(0);
IPMI_ADD_RSP_DATA(0);
IPMI_ADD_RSP_DATA(0);
- out:
- return;
}
static void chassis_control(IPMIBmcSim *ibs,
@@ -744,10 +760,17 @@ static void chassis_control(IPMIBmcSim *ibs,
break;
default:
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
- out:
- return;
+}
+
+static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ uint8_t *rsp, unsigned int *rsp_len,
+ unsigned int max_rsp_len)
+{
+ IPMI_ADD_RSP_DATA(ibs->restart_cause & 0xf); /* Restart Cause */
+ IPMI_ADD_RSP_DATA(0); /* Channel 0 */
}
static void get_device_id(IPMIBmcSim *ibs,
@@ -766,8 +789,6 @@ static void get_device_id(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
IPMI_ADD_RSP_DATA(ibs->product_id[0]);
IPMI_ADD_RSP_DATA(ibs->product_id[1]);
- out:
- return;
}
static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
@@ -812,6 +833,36 @@ static void warm_reset(IPMIBmcSim *ibs,
k->reset(s, false);
}
}
+static void set_acpi_power_state(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ uint8_t *rsp, unsigned int *rsp_len,
+ unsigned int max_rsp_len)
+{
+ IPMI_CHECK_CMD_LEN(4);
+ ibs->acpi_power_state[0] = cmd[2];
+ ibs->acpi_power_state[1] = cmd[3];
+}
+
+static void get_acpi_power_state(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ uint8_t *rsp, unsigned int *rsp_len,
+ unsigned int max_rsp_len)
+{
+ IPMI_ADD_RSP_DATA(ibs->acpi_power_state[0]);
+ IPMI_ADD_RSP_DATA(ibs->acpi_power_state[1]);
+}
+
+static void get_device_guid(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ uint8_t *rsp, unsigned int *rsp_len,
+ unsigned int max_rsp_len)
+{
+ unsigned int i;
+
+ for (i = 0; i < 16; i++) {
+ IPMI_ADD_RSP_DATA(ibs->uuid[i]);
+ }
+}
static void set_bmc_global_enables(IPMIBmcSim *ibs,
uint8_t *cmd, unsigned int cmd_len,
@@ -820,8 +871,6 @@ static void set_bmc_global_enables(IPMIBmcSim *ibs,
{
IPMI_CHECK_CMD_LEN(3);
set_global_enables(ibs, cmd[2]);
- out:
- return;
}
static void get_bmc_global_enables(IPMIBmcSim *ibs,
@@ -830,8 +879,6 @@ static void get_bmc_global_enables(IPMIBmcSim *ibs,
unsigned int max_rsp_len)
{
IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
- out:
- return;
}
static void clr_msg_flags(IPMIBmcSim *ibs,
@@ -845,8 +892,6 @@ static void clr_msg_flags(IPMIBmcSim *ibs,
IPMI_CHECK_CMD_LEN(3);
ibs->msg_flags &= ~cmd[2];
k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
- out:
- return;
}
static void get_msg_flags(IPMIBmcSim *ibs,
@@ -855,8 +900,6 @@ static void get_msg_flags(IPMIBmcSim *ibs,
unsigned int max_rsp_len)
{
IPMI_ADD_RSP_DATA(ibs->msg_flags);
- out:
- return;
}
static void read_evt_msg_buf(IPMIBmcSim *ibs,
@@ -870,15 +913,13 @@ static void read_evt_msg_buf(IPMIBmcSim *ibs,
if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
rsp[2] = 0x80;
- goto out;
+ return;
}
for (i = 0; i < 16; i++) {
IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
}
ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
- out:
- return;
}
static void get_msg(IPMIBmcSim *ibs,
@@ -909,7 +950,7 @@ static void get_msg(IPMIBmcSim *ibs,
k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
}
- out:
+out:
qemu_mutex_unlock(&ibs->lock);
return;
}
@@ -940,14 +981,14 @@ static void send_msg(IPMIBmcSim *ibs,
if (cmd[2] != 0) {
/* We only handle channel 0 with no options */
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
IPMI_CHECK_CMD_LEN(10);
if (cmd[3] != 0x40) {
/* We only emulate a MC at address 0x40. */
rsp[2] = 0x83; /* NAK on write */
- goto out;
+ return;
}
cmd += 3; /* Skip the header. */
@@ -959,7 +1000,7 @@ static void send_msg(IPMIBmcSim *ibs,
*/
if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
cmd[3] != 0x20) { /* Improper response address */
- goto out; /* No response */
+ return; /* No response */
}
netfn = cmd[1] >> 2;
@@ -969,7 +1010,7 @@ static void send_msg(IPMIBmcSim *ibs,
if (rqLun != 2) {
/* We only support LUN 2 coming back to us. */
- goto out;
+ return;
}
msg = g_malloc(sizeof(*msg));
@@ -1009,9 +1050,6 @@ static void send_msg(IPMIBmcSim *ibs,
ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
k->set_atn(s, 1, attn_irq_enabled(ibs));
qemu_mutex_unlock(&ibs->lock);
-
- out:
- return;
}
static void do_watchdog_reset(IPMIBmcSim *ibs)
@@ -1040,11 +1078,9 @@ static void reset_watchdog_timer(IPMIBmcSim *ibs,
{
if (!ibs->watchdog_initialized) {
rsp[2] = 0x80;
- goto out;
+ return;
}
do_watchdog_reset(ibs);
- out:
- return;
}
static void set_watchdog_timer(IPMIBmcSim *ibs,
@@ -1060,7 +1096,7 @@ static void set_watchdog_timer(IPMIBmcSim *ibs,
val = cmd[2] & 0x7; /* Validate use */
if (val == 0 || val > 5) {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
val = cmd[3] & 0x7; /* Validate action */
switch (val) {
@@ -1084,7 +1120,7 @@ static void set_watchdog_timer(IPMIBmcSim *ibs,
}
if (rsp[2]) {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
@@ -1097,12 +1133,12 @@ static void set_watchdog_timer(IPMIBmcSim *ibs,
if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
/* NMI not supported. */
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
default:
/* We don't support PRE_SMI */
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
ibs->watchdog_initialized = 1;
@@ -1116,8 +1152,6 @@ static void set_watchdog_timer(IPMIBmcSim *ibs,
} else {
ibs->watchdog_running = 0;
}
- out:
- return;
}
static void get_watchdog_timer(IPMIBmcSim *ibs,
@@ -1139,8 +1173,6 @@ static void get_watchdog_timer(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA(0);
IPMI_ADD_RSP_DATA(0);
}
- out:
- return;
}
static void get_sdr_rep_info(IPMIBmcSim *ibs,
@@ -1163,8 +1195,6 @@ static void get_sdr_rep_info(IPMIBmcSim *ibs,
}
/* Only modal support, reserve supported */
IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
- out:
- return;
}
static void reserve_sdr_rep(IPMIBmcSim *ibs,
@@ -1174,8 +1204,6 @@ static void reserve_sdr_rep(IPMIBmcSim *ibs,
{
IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
- out:
- return;
}
static void get_sdr(IPMIBmcSim *ibs,
@@ -1185,6 +1213,7 @@ static void get_sdr(IPMIBmcSim *ibs,
{
unsigned int pos;
uint16_t nextrec;
+ struct ipmi_sdr_header *sdrh;
IPMI_CHECK_CMD_LEN(8);
if (cmd[6]) {
@@ -1194,28 +1223,29 @@ static void get_sdr(IPMIBmcSim *ibs,
if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
&pos, &nextrec)) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
- if (cmd[6] > (ibs->sdr.sdr[pos + 4])) {
+
+ sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
+
+ if (cmd[6] > ipmi_sdr_length(sdrh)) {
rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
- goto out;
+ return;
}
IPMI_ADD_RSP_DATA(nextrec & 0xff);
IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
if (cmd[7] == 0xff) {
- cmd[7] = ibs->sdr.sdr[pos + 4] - cmd[6];
+ cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
}
if ((cmd[7] + *rsp_len) > max_rsp_len) {
rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
- goto out;
+ return;
}
memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
*rsp_len += cmd[7];
- out:
- return;
}
static void add_sdr(IPMIBmcSim *ibs,
@@ -1224,15 +1254,14 @@ static void add_sdr(IPMIBmcSim *ibs,
unsigned int max_rsp_len)
{
uint16_t recid;
+ struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
- if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) {
+ if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
IPMI_ADD_RSP_DATA(recid & 0xff);
IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
- out:
- return;
}
static void clear_sdr_rep(IPMIBmcSim *ibs,
@@ -1244,7 +1273,7 @@ static void clear_sdr_rep(IPMIBmcSim *ibs,
IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
if (cmd[7] == 0xaa) {
ibs->sdr.next_free = 0;
@@ -1256,10 +1285,8 @@ static void clear_sdr_rep(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA(1); /* Erasure complete */
} else {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
- out:
- return;
}
static void get_sel_info(IPMIBmcSim *ibs,
@@ -1283,8 +1310,6 @@ static void get_sel_info(IPMIBmcSim *ibs,
}
/* Only support Reserve SEL */
IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
- out:
- return;
}
static void reserve_sel(IPMIBmcSim *ibs,
@@ -1294,8 +1319,6 @@ static void reserve_sel(IPMIBmcSim *ibs,
{
IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
- out:
- return;
}
static void get_sel_entry(IPMIBmcSim *ibs,
@@ -1311,17 +1334,17 @@ static void get_sel_entry(IPMIBmcSim *ibs,
}
if (ibs->sel.next_free == 0) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
if (cmd[6] > 15) {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
if (cmd[7] == 0xff) {
cmd[7] = 16;
} else if ((cmd[7] + cmd[6]) > 16) {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
} else {
cmd[7] += cmd[6];
}
@@ -1331,7 +1354,7 @@ static void get_sel_entry(IPMIBmcSim *ibs,
val = ibs->sel.next_free - 1;
} else if (val >= ibs->sel.next_free) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
if ((val + 1) == ibs->sel.next_free) {
IPMI_ADD_RSP_DATA(0xff);
@@ -1343,8 +1366,6 @@ static void get_sel_entry(IPMIBmcSim *ibs,
for (; cmd[6] < cmd[7]; cmd[6]++) {
IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
}
- out:
- return;
}
static void add_sel_entry(IPMIBmcSim *ibs,
@@ -1355,13 +1376,11 @@ static void add_sel_entry(IPMIBmcSim *ibs,
IPMI_CHECK_CMD_LEN(18);
if (sel_add_event(ibs, cmd + 2)) {
rsp[2] = IPMI_CC_OUT_OF_SPACE;
- goto out;
+ return;
}
/* sel_add_event fills in the record number. */
IPMI_ADD_RSP_DATA(cmd[2]);
IPMI_ADD_RSP_DATA(cmd[3]);
- out:
- return;
}
static void clear_sel(IPMIBmcSim *ibs,
@@ -1373,7 +1392,7 @@ static void clear_sel(IPMIBmcSim *ibs,
IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
if (cmd[7] == 0xaa) {
ibs->sel.next_free = 0;
@@ -1385,10 +1404,8 @@ static void clear_sel(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA(1); /* Erasure complete */
} else {
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
- out:
- return;
}
static void get_sel_time(IPMIBmcSim *ibs,
@@ -1405,8 +1422,6 @@ static void get_sel_time(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
- out:
- return;
}
static void set_sel_time(IPMIBmcSim *ibs,
@@ -1421,8 +1436,6 @@ static void set_sel_time(IPMIBmcSim *ibs,
val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
ipmi_gettime(&now);
ibs->sel.time_offset = now.tv_sec - ((long) val);
- out:
- return;
}
static void set_sensor_evt_enable(IPMIBmcSim *ibs,
@@ -1436,7 +1449,7 @@ static void set_sensor_evt_enable(IPMIBmcSim *ibs,
if ((cmd[2] > MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
sens = ibs->sensors + cmd[2];
switch ((cmd[3] >> 4) & 0x3) {
@@ -1472,11 +1485,9 @@ static void set_sensor_evt_enable(IPMIBmcSim *ibs,
break;
case 3:
rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
- goto out;
+ return;
}
IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
- out:
- return;
}
static void get_sensor_evt_enable(IPMIBmcSim *ibs,
@@ -1490,7 +1501,7 @@ static void get_sensor_evt_enable(IPMIBmcSim *ibs,
if ((cmd[2] > MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
sens = ibs->sensors + cmd[2];
IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
@@ -1498,8 +1509,6 @@ static void get_sensor_evt_enable(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
- out:
- return;
}
static void rearm_sensor_evts(IPMIBmcSim *ibs,
@@ -1513,17 +1522,15 @@ static void rearm_sensor_evts(IPMIBmcSim *ibs,
if ((cmd[2] > MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
sens = ibs->sensors + cmd[2];
if ((cmd[3] & 0x80) == 0) {
/* Just clear everything */
sens->states = 0;
- goto out;
+ return;
}
- out:
- return;
}
static void get_sensor_evt_status(IPMIBmcSim *ibs,
@@ -1537,7 +1544,7 @@ static void get_sensor_evt_status(IPMIBmcSim *ibs,
if ((cmd[2] > MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
sens = ibs->sensors + cmd[2];
IPMI_ADD_RSP_DATA(sens->reading);
@@ -1546,8 +1553,6 @@ static void get_sensor_evt_status(IPMIBmcSim *ibs,
IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
- out:
- return;
}
static void get_sensor_reading(IPMIBmcSim *ibs,
@@ -1561,7 +1566,7 @@ static void get_sensor_reading(IPMIBmcSim *ibs,
if ((cmd[2] > MAX_SENSORS) ||
!IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
- goto out;
+ return;
}
sens = ibs->sensors + cmd[2];
IPMI_ADD_RSP_DATA(sens->reading);
@@ -1570,37 +1575,79 @@ static void get_sensor_reading(IPMIBmcSim *ibs,
if (IPMI_SENSOR_IS_DISCRETE(sens)) {
IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
}
- out:
- return;
}
-static const IPMICmdHandler chassis_cmds[IPMI_NETFN_CHASSIS_MAXCMD] = {
+static void set_sensor_type(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ uint8_t *rsp, unsigned int *rsp_len,
+ unsigned int max_rsp_len)
+{
+ IPMISensor *sens;
+
+
+ IPMI_CHECK_CMD_LEN(5);
+ if ((cmd[2] > MAX_SENSORS) ||
+ !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
+ rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
+ return;
+ }
+ sens = ibs->sensors + cmd[2];
+ sens->sensor_type = cmd[3];
+ sens->evt_reading_type_code = cmd[4] & 0x7f;
+}
+
+static void get_sensor_type(IPMIBmcSim *ibs,
+ uint8_t *cmd, unsigned int cmd_len,
+ uint8_t *rsp, unsigned int *rsp_len,
+ unsigned int max_rsp_len)
+{
+ IPMISensor *sens;
+
+
+ IPMI_CHECK_CMD_LEN(3);
+ if ((cmd[2] > MAX_SENSORS) ||
+ !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
+ rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
+ return;
+ }
+ sens = ibs->sensors + cmd[2];
+ IPMI_ADD_RSP_DATA(sens->sensor_type);
+ IPMI_ADD_RSP_DATA(sens->evt_reading_type_code);
+}
+
+
+static const IPMICmdHandler chassis_cmds[] = {
[IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
[IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
- [IPMI_CMD_CHASSIS_CONTROL] = chassis_control
+ [IPMI_CMD_CHASSIS_CONTROL] = chassis_control,
+ [IPMI_CMD_GET_SYS_RESTART_CAUSE] = chassis_get_sys_restart_cause
};
static const IPMINetfn chassis_netfn = {
- .cmd_nums = IPMI_NETFN_CHASSIS_MAXCMD,
+ .cmd_nums = ARRAY_SIZE(chassis_cmds),
.cmd_handlers = chassis_cmds
};
-static const IPMICmdHandler
-sensor_event_cmds[IPMI_NETFN_SENSOR_EVENT_MAXCMD] = {
+static const IPMICmdHandler sensor_event_cmds[] = {
[IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
[IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
[IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
[IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
- [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading
+ [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading,
+ [IPMI_CMD_SET_SENSOR_TYPE] = set_sensor_type,
+ [IPMI_CMD_GET_SENSOR_TYPE] = get_sensor_type,
};
static const IPMINetfn sensor_event_netfn = {
- .cmd_nums = IPMI_NETFN_SENSOR_EVENT_MAXCMD,
+ .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
.cmd_handlers = sensor_event_cmds
};
-static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = {
+static const IPMICmdHandler app_cmds[] = {
[IPMI_CMD_GET_DEVICE_ID] = get_device_id,
[IPMI_CMD_COLD_RESET] = cold_reset,
[IPMI_CMD_WARM_RESET] = warm_reset,
+ [IPMI_CMD_SET_ACPI_POWER_STATE] = set_acpi_power_state,
+ [IPMI_CMD_GET_ACPI_POWER_STATE] = get_acpi_power_state,
+ [IPMI_CMD_GET_DEVICE_GUID] = get_device_guid,
[IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
[IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
[IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
@@ -1613,11 +1660,11 @@ static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = {
[IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
};
static const IPMINetfn app_netfn = {
- .cmd_nums = IPMI_NETFN_APP_MAXCMD,
+ .cmd_nums = ARRAY_SIZE(app_cmds),
.cmd_handlers = app_cmds
};
-static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
+static const IPMICmdHandler storage_cmds[] = {
[IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
[IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
[IPMI_CMD_GET_SDR] = get_sdr,
@@ -1633,7 +1680,7 @@ static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
};
static const IPMINetfn storage_netfn = {
- .cmd_nums = IPMI_NETFN_STORAGE_MAXCMD,
+ .cmd_nums = ARRAY_SIZE(storage_cmds),
.cmd_handlers = storage_cmds
};
@@ -1697,6 +1744,7 @@ static void ipmi_sim_init(Object *obj)
ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
ibs->device_id = 0x20;
ibs->ipmi_version = 0x02; /* IPMI 2.0 */
+ ibs->restart_cause = 0;
for (i = 0; i < 4; i++) {
ibs->sel.last_addition[i] = 0xff;
ibs->sel.last_clear[i] = 0xff;
@@ -1705,22 +1753,33 @@ static void ipmi_sim_init(Object *obj)
}
for (i = 0;;) {
+ struct ipmi_sdr_header *sdrh;
int len;
- if ((i + 5) > sizeof(init_sdrs)) {
- error_report("Problem with recid 0x%4.4x: \n", i);
+ if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) {
+ error_report("Problem with recid 0x%4.4x", i);
return;
}
- len = init_sdrs[i + 4];
- recid = init_sdrs[i] | (init_sdrs[i + 1] << 8);
+ sdrh = (struct ipmi_sdr_header *) &init_sdrs[i];
+ len = ipmi_sdr_length(sdrh);
+ recid = ipmi_sdr_recid(sdrh);
if (recid == 0xffff) {
break;
}
- if ((i + len + 5) > sizeof(init_sdrs)) {
- error_report("Problem with recid 0x%4.4x\n", i);
+ if ((i + len) > sizeof(init_sdrs)) {
+ error_report("Problem with recid 0x%4.4x", i);
return;
}
- sdr_add_entry(ibs, init_sdrs + i, len, NULL);
- i += len + 5;
+ sdr_add_entry(ibs, sdrh, len, NULL);
+ i += len;
+ }
+
+ ibs->acpi_power_state[0] = 0;
+ ibs->acpi_power_state[1] = 0;
+
+ if (qemu_uuid_set) {
+ memcpy(&ibs->uuid, qemu_uuid, 16);
+ } else {
+ memset(&ibs->uuid, 0, 16);
}
ipmi_init_sensors_from_sdrs(ibs);
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 0bd5131fdb..3940a04b65 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -298,21 +298,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int r, e, i;
+ int r, e, i, j;
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
- r = -ENOSYS;
- goto err;
+ return -ENOSYS;
}
- r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true);
- if (r < 0) {
- goto err;
- }
-
- for (i = 0; i < total_queues; i++) {
- vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
+ for (j = 0; j < total_queues; j++) {
+ r = vhost_net_set_vnet_endian(dev, ncs[j].peer, true);
+ if (r < 0) {
+ goto err_endian;
+ }
+ vhost_net_set_vq_index(get_vhost_net(ncs[j].peer), j * 2);
}
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
@@ -341,8 +339,9 @@ err_start:
fflush(stderr);
}
err_endian:
- vhost_net_set_vnet_endian(dev, ncs[0].peer, false);
-err:
+ while (--j >= 0) {
+ vhost_net_set_vnet_endian(dev, ncs[j].peer, false);
+ }
return r;
}
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index fde8dd3157..de696e8dd0 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -819,20 +819,24 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = VIRTIO_NET(vdev);
struct virtio_net_ctrl_hdr ctrl;
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
- VirtQueueElement elem;
+ VirtQueueElement *elem;
size_t s;
struct iovec *iov, *iov2;
unsigned int iov_cnt;
- while (virtqueue_pop(vq, &elem)) {
- if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) ||
- iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) {
+ for (;;) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+ if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) ||
+ iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) {
error_report("virtio-net ctrl missing headers");
exit(1);
}
- iov_cnt = elem.out_num;
- iov2 = iov = g_memdup(elem.out_sg, sizeof(struct iovec) * elem.out_num);
+ iov_cnt = elem->out_num;
+ iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num);
s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
if (s != sizeof(ctrl)) {
@@ -851,12 +855,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt);
}
- s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
+ s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status));
assert(s == sizeof(status));
- virtqueue_push(vq, &elem, sizeof(status));
+ virtqueue_push(vq, elem, sizeof(status));
virtio_notify(vdev, vq);
g_free(iov2);
+ g_free(elem);
}
}
@@ -1045,13 +1050,14 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
offset = i = 0;
while (offset < size) {
- VirtQueueElement elem;
+ VirtQueueElement *elem;
int len, total;
- const struct iovec *sg = elem.in_sg;
+ const struct iovec *sg;
total = 0;
- if (virtqueue_pop(q->rx_vq, &elem) == 0) {
+ elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement));
+ if (!elem) {
if (i == 0)
return -1;
error_report("virtio-net unexpected empty queue: "
@@ -1064,21 +1070,22 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
exit(1);
}
- if (elem.in_num < 1) {
+ if (elem->in_num < 1) {
error_report("virtio-net receive queue contains no in buffers");
exit(1);
}
+ sg = elem->in_sg;
if (i == 0) {
assert(offset == 0);
if (n->mergeable_rx_bufs) {
mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
- sg, elem.in_num,
+ sg, elem->in_num,
offsetof(typeof(mhdr), num_buffers),
sizeof(mhdr.num_buffers));
}
- receive_header(n, sg, elem.in_num, buf, size);
+ receive_header(n, sg, elem->in_num, buf, size);
offset = n->host_hdr_len;
total += n->guest_hdr_len;
guest_offset = n->guest_hdr_len;
@@ -1087,7 +1094,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
}
/* copy in packet. ugh */
- len = iov_from_buf(sg, elem.in_num, guest_offset,
+ len = iov_from_buf(sg, elem->in_num, guest_offset,
buf + offset, size - offset);
total += len;
offset += len;
@@ -1095,12 +1102,14 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
* must have consumed the complete packet.
* Otherwise, drop it. */
if (!n->mergeable_rx_bufs && offset < size) {
- virtqueue_discard(q->rx_vq, &elem, total);
+ virtqueue_discard(q->rx_vq, elem, total);
+ g_free(elem);
return size;
}
/* signal other side */
- virtqueue_fill(q->rx_vq, &elem, total, i++);
+ virtqueue_fill(q->rx_vq, elem, total, i++);
+ g_free(elem);
}
if (mhdr_cnt) {
@@ -1124,10 +1133,11 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
VirtIONetQueue *q = virtio_net_get_subqueue(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- virtqueue_push(q->tx_vq, &q->async_tx.elem, 0);
+ virtqueue_push(q->tx_vq, q->async_tx.elem, 0);
virtio_notify(vdev, q->tx_vq);
- q->async_tx.elem.out_num = 0;
+ g_free(q->async_tx.elem);
+ q->async_tx.elem = NULL;
virtio_queue_set_notification(q->tx_vq, 1);
virtio_net_flush_tx(q);
@@ -1138,25 +1148,31 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
{
VirtIONet *n = q->n;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- VirtQueueElement elem;
+ VirtQueueElement *elem;
int32_t num_packets = 0;
int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return num_packets;
}
- if (q->async_tx.elem.out_num) {
+ if (q->async_tx.elem) {
virtio_queue_set_notification(q->tx_vq, 0);
return num_packets;
}
- while (virtqueue_pop(q->tx_vq, &elem)) {
+ for (;;) {
ssize_t ret;
- unsigned int out_num = elem.out_num;
- struct iovec *out_sg = &elem.out_sg[0];
- struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1];
+ unsigned int out_num;
+ struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg;
struct virtio_net_hdr_mrg_rxbuf mhdr;
+ elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+
+ out_num = elem->out_num;
+ out_sg = elem->out_sg;
if (out_num < 1) {
error_report("virtio-net header not in first element");
exit(1);
@@ -1208,8 +1224,9 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
}
drop:
- virtqueue_push(q->tx_vq, &elem, 0);
+ virtqueue_push(q->tx_vq, elem, 0);
virtio_notify(vdev, q->tx_vq);
+ g_free(elem);
if (++num_packets >= n->tx_burst) {
break;
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 62fd29d891..d23b8da488 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -302,6 +302,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
dc->desc = "PCI Expander Bridge";
dc->props = pxb_dev_properties;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
static const TypeInfo pxb_dev_info = {
@@ -334,6 +335,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
dc->desc = "PCI Express Expander Bridge";
dc->props = pxb_dev_properties;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
static const TypeInfo pxb_pcie_dev_info = {
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index 8efa23d376..85f21b8c4b 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "hw/pci/msi.h"
+#include "hw/xen/xen.h"
#include "qemu/range.h"
/* PCI_MSI_ADDRESS_LO */
@@ -254,13 +255,19 @@ void msi_reset(PCIDevice *dev)
static bool msi_is_masked(const PCIDevice *dev, unsigned int vector)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- uint32_t mask;
+ uint32_t mask, data;
+ bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
assert(vector < PCI_MSI_VECTORS_MAX);
if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
return false;
}
+ data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
+ if (xen_is_pirq_msi(data)) {
+ return false;
+ }
+
mask = pci_get_long(dev->config +
msi_mask_off(dev, flags & PCI_MSI_FLAGS_64BIT));
return mask & (1U << vector);
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 4fea7edc89..eb4ef113d1 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -19,6 +19,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci.h"
+#include "hw/xen/xen.h"
#include "qemu/range.h"
#define MSIX_CAP_LENGTH 12
@@ -78,8 +79,15 @@ static void msix_clr_pending(PCIDevice *dev, int vector)
static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask)
{
- unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
- return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ unsigned offset = vector * PCI_MSIX_ENTRY_SIZE;
+ uint32_t *data = (uint32_t *)&dev->msix_table[offset + PCI_MSIX_ENTRY_DATA];
+ /* MSIs on Xen can be remapped into pirqs. In those cases, masking
+ * and unmasking go through the PV evtchn path. */
+ if (xen_is_pirq_msi(*data)) {
+ return false;
+ }
+ return fmask || dev->msix_table[offset + PCI_MSIX_ENTRY_VECTOR_CTRL] &
+ PCI_MSIX_ENTRY_CTRL_MASKBIT;
}
bool msix_is_masked(PCIDevice *dev, unsigned int vector)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index d940f79de0..b282120b12 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -851,6 +851,13 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
DeviceState *dev = DEVICE(pci_dev);
pci_dev->bus = bus;
+ /* Only pci bridges can be attached to extra PCI root buses */
+ if (pci_bus_is_root(bus) && bus->parent_dev && !pc->is_bridge) {
+ error_setg(errp,
+ "PCI: Only PCI/PCIe bridges can be plugged into %s",
+ bus->parent_dev->name);
+ return NULL;
+ }
if (devfn < 0) {
for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index c77b3a1058..8340326a50 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -81,15 +81,16 @@ fail_vring:
VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s,
VirtIOSCSIVring *vring)
{
- VirtIOSCSIReq *req = virtio_scsi_init_req(s, NULL);
- int r;
+ VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
+ VirtIOSCSIReq *req;
- req->vring = vring;
- r = vring_pop((VirtIODevice *)s, &vring->vring, &req->elem);
- if (r < 0) {
- virtio_scsi_free_req(req);
- req = NULL;
+ req = vring_pop((VirtIODevice *)s, &vring->vring,
+ sizeof(VirtIOSCSIReq) + vs->cdb_size);
+ if (!req) {
+ return NULL;
}
+ virtio_scsi_init_req(s, NULL, req);
+ req->vring = vring;
return req;
}
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 1500c42728..5b29baccf3 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -41,20 +41,15 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
}
-VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq)
+void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
{
- VirtIOSCSIReq *req;
- VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
- const size_t zero_skip = offsetof(VirtIOSCSIReq, elem)
- + sizeof(VirtQueueElement);
+ const size_t zero_skip = offsetof(VirtIOSCSIReq, vring);
- req = g_malloc(sizeof(*req) + vs->cdb_size);
req->vq = vq;
req->dev = s;
qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory);
qemu_iovec_init(&req->resp_iov, 1);
memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip);
- return req;
}
void virtio_scsi_free_req(VirtIOSCSIReq *req)
@@ -175,11 +170,14 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
{
- VirtIOSCSIReq *req = virtio_scsi_init_req(s, vq);
- if (!virtqueue_pop(vq, &req->elem)) {
- virtio_scsi_free_req(req);
+ VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
+ VirtIOSCSIReq *req;
+
+ req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size);
+ if (!req) {
return NULL;
}
+ virtio_scsi_init_req(s, vq, req);
return req;
}
@@ -191,7 +189,7 @@ static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
assert(n < vs->conf.num_queues);
qemu_put_be32s(f, &n);
- qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
+ qemu_put_virtqueue_element(f, &req->elem);
}
static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
@@ -204,10 +202,8 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
qemu_get_be32s(f, &n);
assert(n < vs->conf.num_queues);
- req = virtio_scsi_init_req(s, vs->cmd_vqs[n]);
- qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
-
- virtqueue_map(&req->elem);
+ req = qemu_get_virtqueue_element(f, sizeof(VirtIOSCSIReq) + vs->cdb_size);
+ virtio_scsi_init_req(s, vs->cmd_vqs[n], req);
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) {
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
index 1a78df10fa..4308d9f055 100644
--- a/hw/virtio/dataplane/vring.c
+++ b/hw/virtio/dataplane/vring.c
@@ -218,8 +218,14 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
new, old);
}
-
-static int get_desc(Vring *vring, VirtQueueElement *elem,
+typedef struct VirtQueueCurrentElement {
+ unsigned in_num;
+ unsigned out_num;
+ hwaddr addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec iov[VIRTQUEUE_MAX_SIZE];
+} VirtQueueCurrentElement;
+
+static int get_desc(Vring *vring, VirtQueueCurrentElement *elem,
struct vring_desc *desc)
{
unsigned *num;
@@ -230,12 +236,12 @@ static int get_desc(Vring *vring, VirtQueueElement *elem,
if (desc->flags & VRING_DESC_F_WRITE) {
num = &elem->in_num;
- iov = &elem->in_sg[*num];
- addr = &elem->in_addr[*num];
+ iov = &elem->iov[elem->out_num + *num];
+ addr = &elem->addr[elem->out_num + *num];
} else {
num = &elem->out_num;
- iov = &elem->out_sg[*num];
- addr = &elem->out_addr[*num];
+ iov = &elem->iov[*num];
+ addr = &elem->addr[*num];
/* If it's an output descriptor, they're all supposed
* to come before any input descriptors. */
@@ -299,7 +305,8 @@ static bool read_vring_desc(VirtIODevice *vdev,
/* This is stolen from linux/drivers/vhost/vhost.c. */
static int get_indirect(VirtIODevice *vdev, Vring *vring,
- VirtQueueElement *elem, struct vring_desc *indirect)
+ VirtQueueCurrentElement *cur_elem,
+ struct vring_desc *indirect)
{
struct vring_desc desc;
unsigned int i = 0, count, found = 0;
@@ -351,7 +358,7 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring,
return -EFAULT;
}
- ret = get_desc(vring, elem, &desc);
+ ret = get_desc(vring, cur_elem, &desc);
if (ret < 0) {
vring->broken |= (ret == -EFAULT);
return ret;
@@ -389,23 +396,23 @@ static void vring_unmap_element(VirtQueueElement *elem)
*
* Stolen from linux/drivers/vhost/vhost.c.
*/
-int vring_pop(VirtIODevice *vdev, Vring *vring,
- VirtQueueElement *elem)
+void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz)
{
struct vring_desc desc;
unsigned int i, head, found = 0, num = vring->vr.num;
uint16_t avail_idx, last_avail_idx;
+ VirtQueueCurrentElement cur_elem;
+ VirtQueueElement *elem = NULL;
int ret;
- /* Initialize elem so it can be safely unmapped */
- elem->in_num = elem->out_num = 0;
-
/* If there was a fatal error then refuse operation */
if (vring->broken) {
ret = -EFAULT;
goto out;
}
+ cur_elem.in_num = cur_elem.out_num = 0;
+
/* Check it isn't doing very strange things with descriptor numbers. */
last_avail_idx = vring->last_avail_idx;
avail_idx = vring_get_avail_idx(vdev, vring);
@@ -431,8 +438,6 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
* the index we've seen. */
head = vring_get_avail_ring(vdev, vring, last_avail_idx % num);
- elem->index = head;
-
/* If their number is silly, that's an error. */
if (unlikely(head >= num)) {
error_report("Guest says index %u > %u is available", head, num);
@@ -459,14 +464,14 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
barrier();
if (desc.flags & VRING_DESC_F_INDIRECT) {
- ret = get_indirect(vdev, vring, elem, &desc);
+ ret = get_indirect(vdev, vring, &cur_elem, &desc);
if (ret < 0) {
goto out;
}
continue;
}
- ret = get_desc(vring, elem, &desc);
+ ret = get_desc(vring, &cur_elem, &desc);
if (ret < 0) {
goto out;
}
@@ -481,15 +486,32 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
virtio_tswap16(vdev, vring->last_avail_idx);
}
- return head;
+ /* Now copy what we have collected and mapped */
+ elem = virtqueue_alloc_element(sz, cur_elem.out_num, cur_elem.in_num);
+ elem->index = head;
+ for (i = 0; i < cur_elem.out_num; i++) {
+ elem->out_addr[i] = cur_elem.addr[i];
+ elem->out_sg[i] = cur_elem.iov[i];
+ }
+ for (i = 0; i < cur_elem.in_num; i++) {
+ elem->in_addr[i] = cur_elem.addr[cur_elem.out_num + i];
+ elem->in_sg[i] = cur_elem.iov[cur_elem.out_num + i];
+ }
+
+ return elem;
out:
assert(ret < 0);
if (ret == -EFAULT) {
vring->broken = true;
}
- vring_unmap_element(elem);
- return ret;
+
+ for (i = 0; i < cur_elem.out_num + cur_elem.in_num; i++) {
+ vring_unmap(cur_elem.iov[i].iov_base, false);
+ }
+
+ g_free(elem);
+ return NULL;
}
/* After we've used one of their buffers, we tell them about it.
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index f5f25a95fc..5c3020331c 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -107,8 +107,10 @@ static void balloon_stats_poll_cb(void *opaque)
return;
}
- virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset);
+ virtqueue_push(s->svq, s->stats_vq_elem, s->stats_vq_offset);
virtio_notify(vdev, s->svq);
+ g_free(s->stats_vq_elem);
+ s->stats_vq_elem = NULL;
}
static void balloon_stats_get_all(Object *obj, struct Visitor *v,
@@ -206,14 +208,18 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
- VirtQueueElement elem;
+ VirtQueueElement *elem;
MemoryRegionSection section;
- while (virtqueue_pop(vq, &elem)) {
+ for (;;) {
size_t offset = 0;
uint32_t pfn;
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ return;
+ }
- 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 addr;
int p = virtio_ldl_p(vdev, &pfn);
@@ -236,20 +242,22 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
memory_region_unref(section.mr);
}
- virtqueue_push(vq, &elem, offset);
+ virtqueue_push(vq, elem, offset);
virtio_notify(vdev, vq);
+ g_free(elem);
}
}
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
- VirtQueueElement *elem = &s->stats_vq_elem;
+ VirtQueueElement *elem;
VirtIOBalloonStat stat;
size_t offset = 0;
qemu_timeval tv;
- if (!virtqueue_pop(vq, elem)) {
+ s->stats_vq_elem = elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
goto out;
}
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index a80fb89069..17da2f8f3d 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -44,7 +44,7 @@ static void chr_read(void *opaque, const void *buf, size_t size)
{
VirtIORNG *vrng = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
- VirtQueueElement elem;
+ VirtQueueElement *elem;
size_t len;
int offset;
@@ -56,15 +56,17 @@ static void chr_read(void *opaque, const void *buf, size_t size)
offset = 0;
while (offset < size) {
- if (!virtqueue_pop(vrng->vq, &elem)) {
+ elem = virtqueue_pop(vrng->vq, sizeof(VirtQueueElement));
+ if (!elem) {
break;
}
- len = iov_from_buf(elem.in_sg, elem.in_num,
+ len = iov_from_buf(elem->in_sg, elem->in_num,
0, buf + offset, size - offset);
offset += len;
- virtqueue_push(vrng->vq, &elem, len);
+ virtqueue_push(vrng->vq, elem, len);
trace_virtio_rng_pushed(vrng, len);
+ g_free(elem);
}
virtio_notify(vdev, vrng->vq);
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 63a7b6d7ba..90f25451d0 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -70,7 +70,15 @@ typedef struct VRing
struct VirtQueue
{
VRing vring;
+
+ /* Next head to pop */
uint16_t last_avail_idx;
+
+ /* Last avail_idx read from VQ. */
+ uint16_t shadow_avail_idx;
+
+ uint16_t used_idx;
+
/* Last used index value we have signalled on */
uint16_t signalled_used;
@@ -107,35 +115,15 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
vring->align);
}
-static inline uint64_t vring_desc_addr(VirtIODevice *vdev, hwaddr desc_pa,
- int i)
+static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc,
+ hwaddr desc_pa, int i)
{
- hwaddr pa;
- pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
- return virtio_ldq_phys(vdev, pa);
-}
-
-static inline uint32_t vring_desc_len(VirtIODevice *vdev, hwaddr desc_pa, int i)
-{
- hwaddr pa;
- pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
- return virtio_ldl_phys(vdev, pa);
-}
-
-static inline uint16_t vring_desc_flags(VirtIODevice *vdev, hwaddr desc_pa,
- int i)
-{
- hwaddr pa;
- pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
- return virtio_lduw_phys(vdev, pa);
-}
-
-static inline uint16_t vring_desc_next(VirtIODevice *vdev, hwaddr desc_pa,
- int i)
-{
- hwaddr pa;
- pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
- return virtio_lduw_phys(vdev, pa);
+ address_space_read(&address_space_memory, desc_pa + i * sizeof(VRingDesc),
+ MEMTXATTRS_UNSPECIFIED, (void *)desc, sizeof(VRingDesc));
+ virtio_tswap64s(vdev, &desc->addr);
+ virtio_tswap32s(vdev, &desc->len);
+ virtio_tswap16s(vdev, &desc->flags);
+ virtio_tswap16s(vdev, &desc->next);
}
static inline uint16_t vring_avail_flags(VirtQueue *vq)
@@ -149,7 +137,8 @@ static inline uint16_t vring_avail_idx(VirtQueue *vq)
{
hwaddr pa;
pa = vq->vring.avail + offsetof(VRingAvail, idx);
- return virtio_lduw_phys(vq->vdev, pa);
+ vq->shadow_avail_idx = virtio_lduw_phys(vq->vdev, pa);
+ return vq->shadow_avail_idx;
}
static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
@@ -164,18 +153,15 @@ static inline uint16_t vring_get_used_event(VirtQueue *vq)
return vring_avail_ring(vq, vq->vring.num);
}
-static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
-{
- hwaddr pa;
- pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
- 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_write(VirtQueue *vq, VRingUsedElem *uelem,
+ int i)
{
hwaddr pa;
- pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
- virtio_stl_phys(vq->vdev, pa, val);
+ virtio_tswap32s(vq->vdev, &uelem->id);
+ virtio_tswap32s(vq->vdev, &uelem->len);
+ pa = vq->vring.used + offsetof(VRingUsed, ring[i]);
+ address_space_write(&address_space_memory, pa, MEMTXATTRS_UNSPECIFIED,
+ (void *)uelem, sizeof(VRingUsedElem));
}
static uint16_t vring_used_idx(VirtQueue *vq)
@@ -190,6 +176,7 @@ static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
hwaddr pa;
pa = vq->vring.used + offsetof(VRingUsed, idx);
virtio_stw_phys(vq->vdev, pa, val);
+ vq->used_idx = val;
}
static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
@@ -239,8 +226,14 @@ int virtio_queue_ready(VirtQueue *vq)
return vq->vring.avail != 0;
}
+/* Fetch avail_idx from VQ memory only when we really need to know if
+ * guest has added some buffers. */
int virtio_queue_empty(VirtQueue *vq)
{
+ if (vq->shadow_avail_idx != vq->last_avail_idx) {
+ return 0;
+ }
+
return vring_avail_idx(vq) == vq->last_avail_idx;
}
@@ -277,15 +270,17 @@ void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len, unsigned int idx)
{
+ VRingUsedElem uelem;
+
trace_virtqueue_fill(vq, elem, len, idx);
virtqueue_unmap_sg(vq, elem, len);
- idx = (idx + vring_used_idx(vq)) % vq->vring.num;
+ idx = (idx + vq->used_idx) % vq->vring.num;
- /* Get a pointer to the next entry in the used ring. */
- vring_used_ring_id(vq, idx, elem->index);
- vring_used_ring_len(vq, idx, len);
+ uelem.id = elem->index;
+ uelem.len = len;
+ vring_used_write(vq, &uelem, idx);
}
void virtqueue_flush(VirtQueue *vq, unsigned int count)
@@ -294,7 +289,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
/* Make sure buffer is written before we update index. */
smp_wmb();
trace_virtqueue_flush(vq, count);
- old = vring_used_idx(vq);
+ old = vq->used_idx;
new = old + count;
vring_used_idx_set(vq, new);
vq->inuse -= count;
@@ -316,7 +311,7 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
/* Check it isn't doing very strange things with descriptor numbers. */
if (num_heads > vq->vring.num) {
error_report("Guest moved used index from %u to %u",
- idx, vring_avail_idx(vq));
+ idx, vq->shadow_avail_idx);
exit(1);
}
/* On success, callers read a descriptor at vq->last_avail_idx.
@@ -345,18 +340,18 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
return head;
}
-static unsigned virtqueue_next_desc(VirtIODevice *vdev, hwaddr desc_pa,
- unsigned int i, unsigned int max)
+static unsigned virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc,
+ hwaddr desc_pa, unsigned int max)
{
unsigned int next;
/* If this descriptor says it doesn't chain, we're done. */
- if (!(vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_NEXT)) {
+ if (!(desc->flags & VRING_DESC_F_NEXT)) {
return max;
}
/* Check they're not leading us off end of descriptors. */
- next = vring_desc_next(vdev, desc_pa, i);
+ next = desc->next;
/* Make sure compiler knows to grab that: we don't want it changing! */
smp_wmb();
@@ -365,6 +360,7 @@ static unsigned virtqueue_next_desc(VirtIODevice *vdev, hwaddr desc_pa,
exit(1);
}
+ vring_desc_read(vdev, desc, desc_pa, next);
return next;
}
@@ -381,6 +377,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
while (virtqueue_num_heads(vq, idx)) {
VirtIODevice *vdev = vq->vdev;
unsigned int max, num_bufs, indirect = 0;
+ VRingDesc desc;
hwaddr desc_pa;
int i;
@@ -388,9 +385,10 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
num_bufs = total_bufs;
i = virtqueue_get_head(vq, idx++);
desc_pa = vq->vring.desc;
+ vring_desc_read(vdev, &desc, desc_pa, i);
- if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) {
- if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) {
+ if (desc.flags & VRING_DESC_F_INDIRECT) {
+ if (desc.len % sizeof(VRingDesc)) {
error_report("Invalid size for indirect buffer table");
exit(1);
}
@@ -403,9 +401,10 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
/* loop over the indirect descriptor table */
indirect = 1;
- max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc);
- desc_pa = vring_desc_addr(vdev, desc_pa, i);
+ max = desc.len / sizeof(VRingDesc);
+ desc_pa = desc.addr;
num_bufs = i = 0;
+ vring_desc_read(vdev, &desc, desc_pa, i);
}
do {
@@ -415,15 +414,15 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
exit(1);
}
- if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) {
- in_total += vring_desc_len(vdev, desc_pa, i);
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ in_total += desc.len;
} else {
- out_total += vring_desc_len(vdev, desc_pa, i);
+ out_total += desc.len;
}
if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
goto done;
}
- } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max);
+ } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max);
if (!indirect)
total_bufs = num_bufs;
@@ -448,6 +447,32 @@ int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
return in_bytes <= in_total && out_bytes <= out_total;
}
+static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iovec *iov,
+ unsigned int max_num_sg, bool is_write,
+ hwaddr pa, size_t sz)
+{
+ unsigned num_sg = *p_num_sg;
+ assert(num_sg <= max_num_sg);
+
+ while (sz) {
+ hwaddr len = sz;
+
+ if (num_sg == max_num_sg) {
+ error_report("virtio: too many write descriptors in indirect table");
+ exit(1);
+ }
+
+ iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write);
+ iov[num_sg].iov_len = len;
+ addr[num_sg] = pa;
+
+ sz -= len;
+ pa += len;
+ num_sg++;
+ }
+ *p_num_sg = num_sg;
+}
+
static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
unsigned int *num_sg, unsigned int max_size,
int is_write)
@@ -474,44 +499,62 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
error_report("virtio: error trying to map MMIO memory");
exit(1);
}
- if (len == sg[i].iov_len) {
- continue;
- }
- if (*num_sg >= max_size) {
- error_report("virtio: memory split makes iovec too large");
+ if (len != sg[i].iov_len) {
+ error_report("virtio: unexpected memory split");
exit(1);
}
- memmove(sg + i + 1, sg + i, sizeof(*sg) * (*num_sg - i));
- memmove(addr + i + 1, addr + i, sizeof(*addr) * (*num_sg - i));
- assert(len < sg[i + 1].iov_len);
- sg[i].iov_len = len;
- addr[i + 1] += len;
- sg[i + 1].iov_len -= len;
- ++*num_sg;
}
}
void virtqueue_map(VirtQueueElement *elem)
{
virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num,
- MIN(ARRAY_SIZE(elem->in_sg), ARRAY_SIZE(elem->in_addr)),
- 1);
+ VIRTQUEUE_MAX_SIZE, 1);
virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num,
- MIN(ARRAY_SIZE(elem->out_sg), ARRAY_SIZE(elem->out_addr)),
- 0);
+ VIRTQUEUE_MAX_SIZE, 0);
}
-int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
+void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
+{
+ VirtQueueElement *elem;
+ size_t in_addr_ofs = QEMU_ALIGN_UP(sz, __alignof__(elem->in_addr[0]));
+ size_t out_addr_ofs = in_addr_ofs + in_num * sizeof(elem->in_addr[0]);
+ size_t out_addr_end = out_addr_ofs + out_num * sizeof(elem->out_addr[0]);
+ size_t in_sg_ofs = QEMU_ALIGN_UP(out_addr_end, __alignof__(elem->in_sg[0]));
+ size_t out_sg_ofs = in_sg_ofs + in_num * sizeof(elem->in_sg[0]);
+ size_t out_sg_end = out_sg_ofs + out_num * sizeof(elem->out_sg[0]);
+
+ assert(sz >= sizeof(VirtQueueElement));
+ elem = g_malloc(out_sg_end);
+ elem->out_num = out_num;
+ elem->in_num = in_num;
+ elem->in_addr = (void *)elem + in_addr_ofs;
+ elem->out_addr = (void *)elem + out_addr_ofs;
+ elem->in_sg = (void *)elem + in_sg_ofs;
+ elem->out_sg = (void *)elem + out_sg_ofs;
+ return elem;
+}
+
+void *virtqueue_pop(VirtQueue *vq, size_t sz)
{
unsigned int i, head, max;
hwaddr desc_pa = vq->vring.desc;
VirtIODevice *vdev = vq->vdev;
+ VirtQueueElement *elem;
+ unsigned out_num, in_num;
+ hwaddr addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec iov[VIRTQUEUE_MAX_SIZE];
+ VRingDesc desc;
- if (!virtqueue_num_heads(vq, vq->last_avail_idx))
- return 0;
+ if (virtio_queue_empty(vq)) {
+ return NULL;
+ }
+ /* Needed after virtio_queue_empty(), see comment in
+ * virtqueue_num_heads(). */
+ smp_rmb();
/* When we start there are none of either input nor output. */
- elem->out_num = elem->in_num = 0;
+ out_num = in_num = 0;
max = vq->vring.num;
@@ -520,56 +563,140 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
vring_set_avail_event(vq, vq->last_avail_idx);
}
- if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_INDIRECT) {
- if (vring_desc_len(vdev, desc_pa, i) % sizeof(VRingDesc)) {
+ vring_desc_read(vdev, &desc, desc_pa, i);
+ if (desc.flags & VRING_DESC_F_INDIRECT) {
+ if (desc.len % sizeof(VRingDesc)) {
error_report("Invalid size for indirect buffer table");
exit(1);
}
/* loop over the indirect descriptor table */
- max = vring_desc_len(vdev, desc_pa, i) / sizeof(VRingDesc);
- desc_pa = vring_desc_addr(vdev, desc_pa, i);
+ max = desc.len / sizeof(VRingDesc);
+ desc_pa = desc.addr;
i = 0;
+ vring_desc_read(vdev, &desc, desc_pa, i);
}
/* Collect all the descriptors */
do {
- struct iovec *sg;
-
- if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) {
- if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
- error_report("Too many write descriptors in indirect table");
- exit(1);
- }
- elem->in_addr[elem->in_num] = vring_desc_addr(vdev, desc_pa, i);
- sg = &elem->in_sg[elem->in_num++];
+ if (desc.flags & VRING_DESC_F_WRITE) {
+ virtqueue_map_desc(&in_num, addr + out_num, iov + out_num,
+ VIRTQUEUE_MAX_SIZE - out_num, true, desc.addr, desc.len);
} else {
- if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
- error_report("Too many read descriptors in indirect table");
+ if (in_num) {
+ error_report("Incorrect order for descriptors");
exit(1);
}
- elem->out_addr[elem->out_num] = vring_desc_addr(vdev, desc_pa, i);
- sg = &elem->out_sg[elem->out_num++];
+ virtqueue_map_desc(&out_num, addr, iov,
+ VIRTQUEUE_MAX_SIZE, false, desc.addr, desc.len);
}
- sg->iov_len = vring_desc_len(vdev, desc_pa, i);
-
/* If we've got too many, that implies a descriptor loop. */
- if ((elem->in_num + elem->out_num) > max) {
+ if ((in_num + out_num) > max) {
error_report("Looped descriptor");
exit(1);
}
- } while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max);
-
- /* Now map what we have collected */
- virtqueue_map(elem);
+ } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max);
+ /* Now copy what we have collected and mapped */
+ elem = virtqueue_alloc_element(sz, out_num, in_num);
elem->index = head;
+ for (i = 0; i < out_num; i++) {
+ elem->out_addr[i] = addr[i];
+ elem->out_sg[i] = iov[i];
+ }
+ for (i = 0; i < in_num; i++) {
+ elem->in_addr[i] = addr[out_num + i];
+ elem->in_sg[i] = iov[out_num + i];
+ }
vq->inuse++;
trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
- return elem->in_num + elem->out_num;
+ return elem;
+}
+
+/* Reading and writing a structure directly to QEMUFile is *awful*, but
+ * it is what QEMU has always done by mistake. We can change it sooner
+ * or later by bumping the version number of the affected vm states.
+ * In the meanwhile, since the in-memory layout of VirtQueueElement
+ * has changed, we need to marshal to and from the layout that was
+ * used before the change.
+ */
+typedef struct VirtQueueElementOld {
+ unsigned int index;
+ unsigned int out_num;
+ unsigned int in_num;
+ hwaddr in_addr[VIRTQUEUE_MAX_SIZE];
+ hwaddr out_addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
+ struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
+} VirtQueueElementOld;
+
+void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
+{
+ VirtQueueElement *elem;
+ VirtQueueElementOld data;
+ int i;
+
+ qemu_get_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld));
+
+ elem = virtqueue_alloc_element(sz, data.out_num, data.in_num);
+ elem->index = data.index;
+
+ for (i = 0; i < elem->in_num; i++) {
+ elem->in_addr[i] = data.in_addr[i];
+ }
+
+ for (i = 0; i < elem->out_num; i++) {
+ elem->out_addr[i] = data.out_addr[i];
+ }
+
+ for (i = 0; i < elem->in_num; i++) {
+ /* Base is overwritten by virtqueue_map. */
+ elem->in_sg[i].iov_base = 0;
+ elem->in_sg[i].iov_len = data.in_sg[i].iov_len;
+ }
+
+ for (i = 0; i < elem->out_num; i++) {
+ /* Base is overwritten by virtqueue_map. */
+ elem->out_sg[i].iov_base = 0;
+ elem->out_sg[i].iov_len = data.out_sg[i].iov_len;
+ }
+
+ virtqueue_map(elem);
+ return elem;
+}
+
+void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem)
+{
+ VirtQueueElementOld data;
+ int i;
+
+ memset(&data, 0, sizeof(data));
+ data.index = elem->index;
+ data.in_num = elem->in_num;
+ data.out_num = elem->out_num;
+
+ for (i = 0; i < elem->in_num; i++) {
+ data.in_addr[i] = elem->in_addr[i];
+ }
+
+ for (i = 0; i < elem->out_num; i++) {
+ data.out_addr[i] = elem->out_addr[i];
+ }
+
+ for (i = 0; i < elem->in_num; i++) {
+ /* Base is overwritten by virtqueue_map when loading. Do not
+ * save it, as it would leak the QEMU address space layout. */
+ data.in_sg[i].iov_len = elem->in_sg[i].iov_len;
+ }
+
+ for (i = 0; i < elem->out_num; i++) {
+ /* Do not save iov_base as above. */
+ data.out_sg[i].iov_len = elem->out_sg[i].iov_len;
+ }
+ qemu_put_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld));
}
/* virtio device */
@@ -673,6 +800,8 @@ void virtio_reset(void *opaque)
vdev->vq[i].vring.avail = 0;
vdev->vq[i].vring.used = 0;
vdev->vq[i].last_avail_idx = 0;
+ vdev->vq[i].shadow_avail_idx = 0;
+ vdev->vq[i].used_idx = 0;
virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
vdev->vq[i].signalled_used = 0;
vdev->vq[i].signalled_used_valid = false;
@@ -1041,7 +1170,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
smp_mb();
/* Always notify when queue is empty (when feature acknowledge) */
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
- !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx) {
+ !vq->inuse && virtio_queue_empty(vq)) {
return true;
}
@@ -1052,7 +1181,7 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
v = vq->signalled_used_valid;
vq->signalled_used_valid = true;
old = vq->signalled_used;
- new = vq->signalled_used = vring_used_idx(vq);
+ new = vq->signalled_used = vq->used_idx;
return !v || vring_need_event(vring_get_used_event(vq), new, old);
}
@@ -1143,8 +1272,8 @@ static const VMStateDescription vmstate_virtio_virtqueues = {
.minimum_version_id = 1,
.needed = &virtio_virtqueue_needed,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_KNOWN(vq, struct VirtIODevice, VIRTIO_QUEUE_MAX,
- 0, vmstate_virtqueue, VirtQueue),
+ VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(vq, struct VirtIODevice,
+ VIRTIO_QUEUE_MAX, 0, vmstate_virtqueue, VirtQueue),
VMSTATE_END_OF_LIST()
}
};
@@ -1165,8 +1294,8 @@ static const VMStateDescription vmstate_virtio_ringsize = {
.minimum_version_id = 1,
.needed = &virtio_ringsize_needed,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_KNOWN(vq, struct VirtIODevice, VIRTIO_QUEUE_MAX,
- 0, vmstate_ringsize, VirtQueue),
+ VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(vq, struct VirtIODevice,
+ VIRTIO_QUEUE_MAX, 0, vmstate_ringsize, VirtQueue),
VMSTATE_END_OF_LIST()
}
};
@@ -1464,6 +1593,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
vdev->vq[i].last_avail_idx, nheads);
return -1;
}
+ vdev->vq[i].used_idx = vring_used_idx(&vdev->vq[i]);
+ vdev->vq[i].shadow_avail_idx = vring_avail_idx(&vdev->vq[i]);
}
}
@@ -1599,6 +1730,7 @@ uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
{
vdev->vq[n].last_avail_idx = idx;
+ vdev->vq[n].shadow_avail_idx = idx;
}
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n)
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index 5624685b20..9a16f2bff1 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -115,9 +115,7 @@ static int msi_msix_setup(XenPCIPassthroughState *s,
assert((!is_msix && msix_entry == 0) || is_msix);
- if (gvec == 0) {
- /* if gvec is 0, the guest is asking for a particular pirq that
- * is passed as dest_id */
+ if (xen_is_pirq_msi(data)) {
*ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
if (!*ppirq) {
/* this probably identifies an misconfiguration of the guest,