From 3e996cc58334be1c3f1be524b4f048566eccbb1d Mon Sep 17 00:00:00 2001 From: Dr. David Alan Gilbert Date: Fri, 29 Jan 2016 13:18:56 +0000 Subject: Fix virtio migration I misunderstood the vmstate macro definition when I reworked the virtio .get/.put. The VMSTATE_STRUCT_VARRAY_KNOWN, was described as being for "a variable length array (i.e. _type *_field) but we know the length". However it actually specified operation for arrays embedded in the struct (i.e. _type _field[]) since it lacked the VMS_POINTER flag. This caused offset calculation to be completely off, examining and potentially sending random data instead of the VirtQueue content. Replace the otherwise unused VMSTATE_STRUCT_VARRAY_KNOWN with a VMSTATE_STRUCT_VARRAY_POINTER_KNOWN that includes the VMS_POINTER flag (so now actually doing what it advertises) and use it in the virtio migration code. Fixes and description as per Sascha's suggestions/debug. Signed-off-by: Dr. David Alan Gilbert Reported-by: Sascha Silbe Tested-By: Sascha Silbe Reviewed-By: Sascha Silbe Fixes: 50e5ae4dc3e4f21e874512f9e87b93b5472d26e0 Fixes: 2cf0148674430b6693c60d42b7eef721bfa9509f Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Cornelia Huck --- include/migration/vmstate.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index a4b81bb5f6..7246f29afe 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -386,26 +386,26 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_array(_state, _field, _type, _num),\ } -/* a variable length array (i.e. _type *_field) but we know the - * length - */ -#define VMSTATE_STRUCT_VARRAY_KNOWN(_field, _state, _num, _version, _vmsd, _type) { \ +#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \ .name = (stringify(_field)), \ - .num = (_num), \ + .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ .version_id = (_version), \ .vmsd = &(_vmsd), \ .size = sizeof(_type), \ - .flags = VMS_STRUCT|VMS_ARRAY, \ + .flags = VMS_STRUCT|VMS_VARRAY_UINT8, \ .offset = offsetof(_state, _field), \ } -#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \ +/* a variable length array (i.e. _type *_field) but we know the + * length + */ +#define VMSTATE_STRUCT_VARRAY_POINTER_KNOWN(_field, _state, _num, _version, _vmsd, _type) { \ .name = (stringify(_field)), \ - .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ + .num = (_num), \ .version_id = (_version), \ .vmsd = &(_vmsd), \ .size = sizeof(_type), \ - .flags = VMS_STRUCT|VMS_VARRAY_UINT8, \ + .flags = VMS_STRUCT|VMS_ARRAY|VMS_POINTER, \ .offset = offsetof(_state, _field), \ } -- cgit v1.2.3-55-g7522 From 6aa46d8ff1ee7e9ca0c4a54d75c74108bee22124 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:28:57 +0100 Subject: virtio: move VirtQueueElement at the beginning of the structs The next patch will make virtqueue_pop/vring_pop allocate memory for the VirtQueueElement. In some cases (blk, scsi, gpu) the device wants to extend VirtQueueElement with device-specific fields and, until now, the place of the VirtQueueElement within the containing struct didn't matter. When allocating the entire block in virtqueue_pop/vring_pop, however, the containing struct must basically be a "subclass" of VirtQueueElement, with the VirtQueueElement as the first field. Make that the case for blk and scsi; gpu is already doing it. Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/scsi/virtio-scsi.c | 3 +-- include/hw/virtio/virtio-blk.h | 2 +- include/hw/virtio/virtio-scsi.h | 13 ++++++------- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 1500c42728..7fdf6ade98 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -45,8 +45,7 @@ VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) { 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; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index ae11a63934..403ab86166 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -60,9 +60,9 @@ typedef struct VirtIOBlock { } VirtIOBlock; typedef struct VirtIOBlockReq { + VirtQueueElement elem; int64_t sector_num; VirtIOBlock *dev; - VirtQueueElement elem; struct virtio_blk_inhdr *in; struct virtio_blk_outhdr out; QEMUIOVector qiov; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 0394eb23de..eb9d25b9fb 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -112,18 +112,17 @@ typedef struct VirtIOSCSI { } VirtIOSCSI; typedef struct VirtIOSCSIReq { + /* Note: + * - fields up to resp_iov are initialized by virtio_scsi_init_req; + * - fields starting at vring are zeroed by virtio_scsi_init_req. + * */ + VirtQueueElement elem; + VirtIOSCSI *dev; VirtQueue *vq; QEMUSGList qsgl; QEMUIOVector resp_iov; - /* Note: - * - fields before elem are initialized by virtio_scsi_init_req; - * - elem is uninitialized at the time of allocation. - * - fields after elem are zeroed by virtio_scsi_init_req. - * */ - - VirtQueueElement elem; /* Set by dataplane code. */ VirtIOSCSIVring *vring; -- cgit v1.2.3-55-g7522 From 51b19ebe4320f3dcd93cea71235c1219318ddfd2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Feb 2016 16:26:51 +0200 Subject: virtio: move allocation to virtqueue_pop/vring_pop The return code of virtqueue_pop/vring_pop is unused except to check for errors or 0. We can thus easily move allocation inside the functions and just return a pointer to the VirtQueueElement. The advantage is that we will be able to allocate only the space that is needed for the actual size of the s/g list instead of the full VIRTQUEUE_MAX_SIZE items. Currently VirtQueueElement takes about 48K of memory, and this kind of allocation puts a lot of stress on malloc. By cutting the size by two or three orders of magnitude, malloc can use much more efficient algorithms. The patch is pretty large, but changes to each device are testable more or less independently. Splitting it would mostly add churn. Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/9pfs/9p.c | 2 +- hw/9pfs/virtio-9p-device.c | 17 ++++---- hw/9pfs/virtio-9p.h | 2 +- hw/block/dataplane/virtio-blk.c | 11 +++-- hw/block/virtio-blk.c | 15 +++---- hw/char/virtio-serial-bus.c | 80 +++++++++++++++++++++++-------------- hw/display/virtio-gpu.c | 21 ++++++---- hw/input/virtio-input.c | 24 +++++++---- hw/net/virtio-net.c | 69 ++++++++++++++++++++------------ hw/scsi/virtio-scsi-dataplane.c | 15 +++---- hw/scsi/virtio-scsi.c | 18 ++++----- hw/virtio/dataplane/vring.c | 18 +++++---- hw/virtio/virtio-balloon.c | 22 ++++++---- hw/virtio/virtio-rng.c | 10 +++-- hw/virtio/virtio.c | 12 ++++-- include/hw/virtio/dataplane/vring.h | 2 +- include/hw/virtio/virtio-balloon.h | 2 +- include/hw/virtio/virtio-blk.h | 3 +- include/hw/virtio/virtio-net.h | 2 +- include/hw/virtio/virtio-scsi.h | 2 +- include/hw/virtio/virtio-serial.h | 2 +- include/hw/virtio/virtio.h | 2 +- 22 files changed, 209 insertions(+), 142 deletions(-) (limited to 'include') 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/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..bf70b52dfd 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; } @@ -836,7 +832,8 @@ 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); + VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1); + virtio_blk_init_request(s, req); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(VirtQueueElement)); req->next = s->rq; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 8d5c740558..cf3d12b9d5 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,7 +639,7 @@ 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); @@ -628,8 +647,8 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) 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_buffer(f, (unsigned char *)port->elem, + sizeof(VirtQueueElement)); } } } @@ -704,9 +723,10 @@ 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 = g_new(VirtQueueElement, 1); + qemu_get_buffer(f, (unsigned char *)port->elem, + sizeof(VirtQueueElement)); + virtqueue_map(port->elem); /* * Port was throttled on source machine. Let's @@ -928,7 +948,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/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/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/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 7fdf6ade98..50a3cb28b5 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -41,19 +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, 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) @@ -174,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; } @@ -203,8 +202,9 @@ 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]); + req = g_malloc(sizeof(VirtIOSCSIReq) + vs->cdb_size); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + virtio_scsi_init_req(s, vs->cmd_vqs[n], req); virtqueue_map(&req->elem); diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 1a78df10fa..4fb84bb00a 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -389,23 +389,26 @@ 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; + 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; } + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(sz); + + /* Initialize elem so it can be safely unmapped */ + elem->in_num = 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); @@ -481,7 +484,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, virtio_tswap16(vdev, vring->last_avail_idx); } - return head; + return elem; out: assert(ret < 0); @@ -489,7 +492,8 @@ out: vring->broken = true; } vring_unmap_element(elem); - return ret; + 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 0603793e34..229a092c83 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -501,16 +501,20 @@ void virtqueue_map(VirtQueueElement *elem) 0); } -int virtqueue_pop(VirtQueue *vq, VirtQueueElement *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; - if (!virtqueue_num_heads(vq, vq->last_avail_idx)) - return 0; + if (!virtqueue_num_heads(vq, vq->last_avail_idx)) { + return NULL; + } /* When we start there are none of either input nor output. */ + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(sz); elem->out_num = elem->in_num = 0; max = vq->vring.num; @@ -569,7 +573,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) vq->inuse++; trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num); - return elem->in_num + elem->out_num; + return elem; } /* virtio device */ diff --git a/include/hw/virtio/dataplane/vring.h b/include/hw/virtio/dataplane/vring.h index a596e4c175..e80985ee4c 100644 --- a/include/hw/virtio/dataplane/vring.h +++ b/include/hw/virtio/dataplane/vring.h @@ -44,7 +44,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n); void vring_disable_notification(VirtIODevice *vdev, Vring *vring); bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); bool vring_should_notify(VirtIODevice *vdev, Vring *vring); -int vring_pop(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem); +void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz); void vring_push(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem, int len); diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h index 09c2ce4dcd..35f62ac119 100644 --- a/include/hw/virtio/virtio-balloon.h +++ b/include/hw/virtio/virtio-balloon.h @@ -37,7 +37,7 @@ typedef struct VirtIOBalloon { uint32_t num_pages; uint32_t actual; uint64_t stats[VIRTIO_BALLOON_S_NR]; - VirtQueueElement stats_vq_elem; + VirtQueueElement *stats_vq_elem; size_t stats_vq_offset; QEMUTimer *stats_timer; int64_t stats_last_update; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 403ab86166..199bb0ebd5 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -80,8 +80,7 @@ typedef struct MultiReqBuffer { bool is_write; } MultiReqBuffer; -VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s); - +void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req); void virtio_blk_free_request(VirtIOBlockReq *req); void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index f3cc25feca..2ce3b03bd4 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -47,7 +47,7 @@ typedef struct VirtIONetQueue { QEMUBH *tx_bh; int tx_waiting; struct { - VirtQueueElement elem; + VirtQueueElement *elem; } async_tx; struct VirtIONet *n; } VirtIONetQueue; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index eb9d25b9fb..a8029aa017 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -160,7 +160,7 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req); -VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason); diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h index 527d0bf624..12a55a19e9 100644 --- a/include/hw/virtio/virtio-serial.h +++ b/include/hw/virtio/virtio-serial.h @@ -122,7 +122,7 @@ struct VirtIOSerialPort { * element popped and continue consuming it once the backend * becomes writable again. */ - VirtQueueElement elem; + VirtQueueElement *elem; /* * The index and the offset into the iov buffer that was popped in diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 205fadf234..21fda17807 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -152,7 +152,7 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); void virtqueue_map(VirtQueueElement *elem); -int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem); +void *virtqueue_pop(VirtQueue *vq, size_t sz); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes); void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, -- cgit v1.2.3-55-g7522 From ab281c1781add112a257c15924d670616a99c41a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:28:59 +0100 Subject: virtio: introduce qemu_get/put_virtqueue_element Move allocation to virtio functions also when loading/saving a VirtQueueElement. This will also let the load/save functions keep backwards compatibility when the VirtQueueElement layout is changed. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 10 +++------- hw/char/virtio-serial-bus.c | 10 +++------- hw/scsi/virtio-scsi.c | 7 ++----- hw/virtio/virtio.c | 13 +++++++++++++ include/hw/virtio/virtio.h | 2 ++ 5 files changed, 23 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index bf70b52dfd..c427698fcb 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -808,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); @@ -832,14 +831,11 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, VirtIOBlock *s = VIRTIO_BLK(vdev); while (qemu_get_sbyte(f)) { - VirtIOBlockReq *req = g_new(VirtIOBlockReq, 1); + VirtIOBlockReq *req; + req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq)); virtio_blk_init_request(s, req); - qemu_get_buffer(f, (unsigned char *)&req->elem, - sizeof(VirtQueueElement)); 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 cf3d12b9d5..99cb6836ad 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -646,9 +646,7 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) 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(VirtQueueElement)); + qemu_put_virtqueue_element(f, port->elem); } } } @@ -723,10 +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); - port->elem = g_new(VirtQueueElement, 1); - qemu_get_buffer(f, (unsigned char *)port->elem, - sizeof(VirtQueueElement)); - virtqueue_map(port->elem); + port->elem = + qemu_get_virtqueue_element(f, sizeof(VirtQueueElement)); /* * Port was throttled on source machine. Let's diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 50a3cb28b5..5b29baccf3 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -189,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) @@ -202,12 +202,9 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); - req = g_malloc(sizeof(VirtIOSCSIReq) + vs->cdb_size); - qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + req = qemu_get_virtqueue_element(f, sizeof(VirtIOSCSIReq) + vs->cdb_size); virtio_scsi_init_req(s, vs->cmd_vqs[n], req); - virtqueue_map(&req->elem); - if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) { error_report("invalid SCSI request migration data"); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 229a092c83..28fa7fe760 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -576,6 +576,19 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) return elem; } +void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz) +{ + VirtQueueElement *elem = g_malloc(sz); + qemu_get_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); + virtqueue_map(elem); + return elem; +} + +void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem) +{ + qemu_put_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); +} + /* virtio device */ static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 21fda17807..44da9a8433 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -153,6 +153,8 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, void virtqueue_map(VirtQueueElement *elem); void *virtqueue_pop(VirtQueue *vq, size_t sz); +void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz); +void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes); void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, -- cgit v1.2.3-55-g7522 From 3724650db07057333879484c8bc7d900b5c1bf8e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 31 Jan 2016 11:29:00 +0100 Subject: virtio: introduce virtqueue_alloc_element Allocate the arrays for in_addr/out_addr/in_sg/out_sg outside the VirtQueueElement. For now, virtqueue_pop and vring_pop keep allocating a very large VirtQueueElement. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/dataplane/vring.c | 3 +- hw/virtio/virtio.c | 110 +++++++++++++++++++++++++++++++++++++++----- include/hw/virtio/virtio.h | 9 ++-- 3 files changed, 105 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 4fb84bb00a..57ada3bcbe 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -403,8 +403,7 @@ void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) goto out; } - assert(sz >= sizeof(VirtQueueElement)); - elem = g_malloc(sz); + elem = virtqueue_alloc_element(sz, VIRTQUEUE_MAX_SIZE, VIRTQUEUE_MAX_SIZE); /* Initialize elem so it can be safely unmapped */ elem->in_num = elem->out_num = 0; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 28fa7fe760..661a1e1536 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -494,11 +494,30 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, 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); +} + +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) @@ -513,8 +532,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) } /* When we start there are none of either input nor output. */ - assert(sz >= sizeof(VirtQueueElement)); - elem = g_malloc(sz); + elem = virtqueue_alloc_element(sz, VIRTQUEUE_MAX_SIZE, VIRTQUEUE_MAX_SIZE); elem->out_num = elem->in_num = 0; max = vq->vring.num; @@ -541,14 +559,14 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) struct iovec *sg; if (vring_desc_flags(vdev, desc_pa, i) & VRING_DESC_F_WRITE) { - if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) { + if (elem->in_num >= VIRTQUEUE_MAX_SIZE) { 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++]; } else { - if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) { + if (elem->out_num >= VIRTQUEUE_MAX_SIZE) { error_report("Too many read descriptors in indirect table"); exit(1); } @@ -576,17 +594,87 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) 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 = g_malloc(sz); - qemu_get_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); + 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) { - qemu_put_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement)); + 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 */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 44da9a8433..108cdb0f48 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -46,10 +46,10 @@ typedef struct VirtQueueElement 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]; + hwaddr *in_addr; + hwaddr *out_addr; + struct iovec *in_sg; + struct iovec *out_sg; } VirtQueueElement; #define VIRTIO_QUEUE_MAX 1024 @@ -143,6 +143,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, void virtio_del_queue(VirtIODevice *vdev, int n); +void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num); void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len); void virtqueue_flush(VirtQueue *vq, unsigned int count); -- cgit v1.2.3-55-g7522 From a2295f0a5871e2b9d8ea24bc3a1d2e02bda6ef2d Mon Sep 17 00:00:00 2001 From: Cédric Le Goater Date: Mon, 25 Jan 2016 15:07:31 +0100 Subject: ipmi: introduce a struct ipmi_sdr_compact Currently, sdr attributes are identified using byte offsets and this can be a bit confusing. This patch adds a struct ipmi_sdr_compact conforming to the IPMI specs and replaces byte offsets with names. It also introduces and uses a struct ipmi_sdr_header in sections of the code where no assumption is made on the type of SDR. This leave rooms to potential usage of other types in the future. Signed-off-by: Cédric Le Goater Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/ipmi/ipmi_bmc_sim.c | 72 ++++++++++++++++++++++++++++++-------------------- include/hw/ipmi/ipmi.h | 45 +++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 73a4f6a7ab..84fbcd2638 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -318,14 +318,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; } @@ -334,10 +338,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; @@ -355,8 +359,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] + 5; + 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) { @@ -505,29 +511,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; @@ -1153,6 +1162,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]) { @@ -1164,7 +1174,10 @@ static void get_sdr(IPMIBmcSim *ibs, rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; return; } - if (cmd[6] > (ibs->sdr.sdr[pos + 4] + 5)) { + + sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; + + if (cmd[6] > ipmi_sdr_length(sdrh)) { rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; return; } @@ -1173,7 +1186,7 @@ static void get_sdr(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); if (cmd[7] == 0xff) { - cmd[7] = ibs->sdr.sdr[pos + 4] + 5 - cmd[6]; + cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; } if ((cmd[7] + *rsp_len) > max_rsp_len) { @@ -1190,8 +1203,9 @@ 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; return; } @@ -1642,13 +1656,15 @@ static void ipmi_sim_init(Object *obj) } for (i = 0;;) { + struct ipmi_sdr_header *sdrh; int len; - if ((i + 5) > sizeof(init_sdrs)) { + if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) { error_report("Problem with recid 0x%4.4x", i); return; } - len = init_sdrs[i + 4] + 5; - 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; } @@ -1656,7 +1672,7 @@ static void ipmi_sim_init(Object *obj) error_report("Problem with recid 0x%4.4x", i); return; } - sdr_add_entry(ibs, init_sdrs + i, len, NULL); + sdr_add_entry(ibs, sdrh, len, NULL); i += len; } diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h index 32bac0fa88..74a2b5af96 100644 --- a/include/hw/ipmi/ipmi.h +++ b/include/hw/ipmi/ipmi.h @@ -210,4 +210,49 @@ IPMIFwInfo *ipmi_next_fwinfo(IPMIFwInfo *current); #define ipmi_debug(fs, ...) #endif +struct ipmi_sdr_header { + uint8_t rec_id[2]; + uint8_t sdr_version; /* 0x51 */ + uint8_t rec_type; + uint8_t rec_length; +}; +#define IPMI_SDR_HEADER_SIZE sizeof(struct ipmi_sdr_header) + +#define ipmi_sdr_recid(sdr) ((sdr)->rec_id[0] | ((sdr)->rec_id[1] << 8)) +#define ipmi_sdr_length(sdr) ((sdr)->rec_length + IPMI_SDR_HEADER_SIZE) + +/* + * 43.2 SDR Type 02h. Compact Sensor Record + */ +#define IPMI_SDR_COMPACT_TYPE 2 + +struct ipmi_sdr_compact { + struct ipmi_sdr_header header; + + uint8_t sensor_owner_id; + uint8_t sensor_owner_lun; + uint8_t sensor_owner_number; /* byte 8 */ + uint8_t entity_id; + uint8_t entity_instance; + uint8_t sensor_init; + uint8_t sensor_caps; + uint8_t sensor_type; + uint8_t reading_type; + uint8_t assert_mask[2]; /* byte 16 */ + uint8_t deassert_mask[2]; + uint8_t discrete_mask[2]; + uint8_t sensor_unit1; + uint8_t sensor_unit2; + uint8_t sensor_unit3; + uint8_t sensor_direction[2]; /* byte 24 */ + uint8_t positive_threshold; + uint8_t negative_threshold; + uint8_t reserved[3]; + uint8_t oem; + uint8_t id_str_len; /* byte 32 */ + uint8_t id_string[16]; +}; + +typedef uint8_t ipmi_sdr_compact_buffer[sizeof(struct ipmi_sdr_compact)]; + #endif -- cgit v1.2.3-55-g7522 From 281b104702af40b08b29b621995830c0c0177a41 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:22 -0200 Subject: pc: Move PcGuestInfo declaration to top of file The struct will be used inside PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- include/hw/i386/pc.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 65e8f245a8..212eb7dcfa 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -33,6 +33,22 @@ #define kvm_ioapic_in_kernel() 0 #endif +/* Machine info for ACPI build: */ +struct PcGuestInfo { + bool isapc_ram_fw; + hwaddr ram_size, ram_size_below_4g; + unsigned apic_id_limit; + bool apic_xrupt_override; + uint64_t numa_nodes; + uint64_t *node_mem; + uint64_t *node_cpu; + FWCfgState *fw_cfg; + int legacy_acpi_table_size; + bool has_acpi_build; + bool has_reserved_memory; + bool rsdp_in_ram; +}; + /** * PCMachineState: * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling @@ -151,21 +167,6 @@ typedef struct PcPciInfo { #define ACPI_PM_PROP_GPE0_BLK_LEN "gpe0_blk_len" #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" -struct PcGuestInfo { - bool isapc_ram_fw; - hwaddr ram_size, ram_size_below_4g; - unsigned apic_id_limit; - bool apic_xrupt_override; - uint64_t numa_nodes; - uint64_t *node_mem; - uint64_t *node_cpu; - FWCfgState *fw_cfg; - int legacy_acpi_table_size; - bool has_acpi_build; - bool has_reserved_memory; - bool rsdp_in_ram; -}; - /* parallel.c */ void parallel_hds_isa_init(ISABus *bus, int n); -- cgit v1.2.3-55-g7522 From 9ebeed0c1efe4994c7c129e8469a797bcde9f81a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:23 -0200 Subject: pc: Eliminate struct PcGuestInfoState Instead of allocating a new struct just for PcGuestInfo and the mchine_done Notifier, place them inside PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 27 ++++++++++----------------- include/hw/i386/pc.h | 2 ++ 2 files changed, 12 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 942ac0659a..c421d2c30d 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,21 +1172,20 @@ 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->acpi_guest_info.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->acpi_guest_info.fw_cfg, "etc/extra-pci-roots", val, sizeof(*val)); } } - acpi_setup(&guest_info_state->info); + acpi_setup(&pcms->acpi_guest_info); } PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) { - PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); - PcGuestInfo *guest_info = &guest_info_state->info; + PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; guest_info->ram_size_below_4g = pcms->below_4g_mem_size; @@ -1220,8 +1213,8 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) } } - guest_info_state->machine_done.notify = pc_guest_info_machine_done; - qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); + pcms->machine_done.notify = pc_machine_done; + qemu_add_machine_init_done_notifier(&pcms->machine_done); return guest_info; } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 212eb7dcfa..9d0b004d74 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -61,6 +61,8 @@ struct PCMachineState { /* State for other subsystems/APIs: */ MemoryHotplugState hotplug_memory; + PcGuestInfo acpi_guest_info; + Notifier machine_done; /* Pointers to devices and objects: */ HotplugHandler *acpi_dev; -- cgit v1.2.3-55-g7522 From 5934e2169a383cdb059f8ccd83f7e1c4d410c9b3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:24 -0200 Subject: pc: Simplify pc_memory_init() signature We can get the PcGuestInfo struct directly from PCMachineState, and the return value is not needed at all. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 11 +++++------ hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 9 ++++----- 4 files changed, 11 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c421d2c30d..fbdad8813f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1276,12 +1276,12 @@ FWCfgState *xen_load_linux(PCMachineState *pcms, return 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) { + PcGuestInfo *guest_info = &pcms->acpi_guest_info; int linux_boot, i; MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; @@ -1403,7 +1403,6 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, rom_add_option(option_rom[i].name, option_rom[i].bootindex); } guest_info->fw_cfg = fw_cfg; - return 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..ad51fd674b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -162,7 +162,7 @@ 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); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 56be9b1d16..0c156e21b6 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -156,7 +156,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/include/hw/i386/pc.h b/include/hw/i386/pc.h index 9d0b004d74..5b21d0120d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -250,11 +250,10 @@ void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info); -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); qemu_irq pc_allocate_cpu_irq(void); DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, -- cgit v1.2.3-55-g7522 From 7bc35e0f20a1e6f1b00edc85618437a495873bbd Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:25 -0200 Subject: pc: Simplify xen_load_linux() signature We can get the PcGuestInfo struct directly from PCMachineState, and the return value is not needed at all. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 5 ++--- hw/i386/pc_piix.c | 2 +- include/hw/i386/pc.h | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index fbdad8813f..9745dcaec4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1255,11 +1255,11 @@ 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; + PcGuestInfo *guest_info = &pcms->acpi_guest_info; assert(MACHINE(pcms)->kernel_filename != NULL); @@ -1273,7 +1273,6 @@ FWCfgState *xen_load_linux(PCMachineState *pcms, rom_add_option(option_rom[i].name, option_rom[i].bootindex); } guest_info->fw_cfg = fw_cfg; - return fw_cfg; } void pc_memory_init(PCMachineState *pcms, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ad51fd674b..4262c32575 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -165,7 +165,7 @@ static void pc_init1(MachineState *machine, 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/include/hw/i386/pc.h b/include/hw/i386/pc.h index 5b21d0120d..223621a30c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -248,8 +248,7 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms); void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, MemoryRegion *pci_address_space); -FWCfgState *xen_load_linux(PCMachineState *pcms, - PcGuestInfo *guest_info); +void xen_load_linux(PCMachineState *pcms); void pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, MemoryRegion *rom_memory, -- cgit v1.2.3-55-g7522 From bb292f5a9b944e47fae88a20767967e7e20122b4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:28 -0200 Subject: pc: Remove compat fields from PcGuestInfo Remove the fields: legacy_acpi_table_size, has_acpi_build, has_reserved_memory, and rsdp_in_ram from PcGuestInfo, and let the existing code use the PCMachineClass fields directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 10 ++++++---- hw/i386/acpi-build.h | 2 +- hw/i386/pc.c | 8 ++++---- hw/i386/pc_piix.c | 5 ----- hw/i386/pc_q35.c | 8 -------- include/hw/i386/pc.h | 4 ---- 6 files changed, 11 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 45c07caed4..7f574f28c3 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2593,6 +2593,7 @@ static void acpi_build(AcpiBuildTables *tables) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); PcGuestInfo *guest_info = &pcms->acpi_guest_info; GArray *table_offsets; unsigned facs, dsdt, rsdt, fadt; @@ -2706,12 +2707,12 @@ void acpi_build(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, @@ -2804,6 +2805,7 @@ static const VMStateDescription vmstate_acpi_build = { void acpi_setup(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); PcGuestInfo *guest_info = &pcms->acpi_guest_info; AcpiBuildTables tables; AcpiBuildState *build_state; @@ -2813,7 +2815,7 @@ void acpi_setup(void) return; } - if (!guest_info->has_acpi_build) { + if (!pcmc->has_acpi_build) { ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n"); return; } @@ -2842,7 +2844,7 @@ void acpi_setup(void) fw_cfg_add_file(guest_info->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 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/pc.c b/hw/i386/pc.c index 9745dcaec4..3c59500d84 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1180,7 +1180,7 @@ void pc_machine_done(Notifier *notifier, void *data) } } - acpi_setup(&pcms->acpi_guest_info); + acpi_setup(); } PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) @@ -1316,7 +1316,7 @@ void 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); @@ -1327,7 +1327,7 @@ void 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; @@ -1382,7 +1382,7 @@ void 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; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 4262c32575..584441a832 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -143,12 +143,7 @@ static void pc_init1(MachineState *machine, 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; if (pcmc->smbios_defaults) { MachineClass *mc = MACHINE_GET_CLASS(machine); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0c156e21b6..45e05f4a03 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -136,14 +136,6 @@ static void pc_q35_init(MachineState *machine) 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; if (pcmc->smbios_defaults) { /* These values are guest ABI, do not change */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 223621a30c..4480409e77 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -43,10 +43,6 @@ struct PcGuestInfo { uint64_t *node_mem; uint64_t *node_cpu; FWCfgState *fw_cfg; - int legacy_acpi_table_size; - bool has_acpi_build; - bool has_reserved_memory; - bool rsdp_in_ram; }; /** -- cgit v1.2.3-55-g7522 From 5299f1c70aa7ebc89383363cd3d47fc4f5dc2163 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:29 -0200 Subject: pc: Remove RAM size fields from PcGuestInfo The ACPI code can use the PCMachineState fields directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 10 +++++----- hw/i386/pc.c | 2 -- include/hw/i386/pc.h | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 7f574f28c3..dac7137471 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2421,17 +2421,17 @@ build_srat(GArray *table_data, GArray *linker) 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, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3c59500d84..f3fd0ed47c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1188,8 +1188,6 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) PcGuestInfo *guest_info = &pcms->acpi_guest_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; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4480409e77..c27e680ee0 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -36,7 +36,6 @@ /* Machine info for ACPI build: */ struct PcGuestInfo { bool isapc_ram_fw; - hwaddr ram_size, ram_size_below_4g; unsigned apic_id_limit; bool apic_xrupt_override; uint64_t numa_nodes; -- cgit v1.2.3-55-g7522 From 5db3f0deaf165bd0ff247fcea042cb2e60671e43 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:30 -0200 Subject: pc: Remove PcGuestInfo.isapc_ram_fw field The code can use the PCMachineClass.pci_enabled field directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/pc.c | 2 +- hw/i386/pc_piix.c | 5 +---- hw/i386/pc_q35.c | 4 +--- include/hw/i386/pc.h | 1 - 4 files changed, 3 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index f3fd0ed47c..dc0ade4a8c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1365,7 +1365,7 @@ void 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, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 584441a832..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,9 +140,7 @@ static void pc_init1(MachineState *machine, rom_memory = system_memory; } - guest_info = pc_guest_info_init(pcms); - - guest_info->isapc_ram_fw = !pcmc->pci_enabled; + pc_guest_info_init(pcms); if (pcmc->smbios_defaults) { MachineClass *mc = MACHINE_GET_CLASS(machine); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 45e05f4a03..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,8 +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; + pc_guest_info_init(pcms); if (pcmc->smbios_defaults) { /* These values are guest ABI, do not change */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c27e680ee0..6a5c4da053 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -35,7 +35,6 @@ /* Machine info for ACPI build: */ struct PcGuestInfo { - bool isapc_ram_fw; unsigned apic_id_limit; bool apic_xrupt_override; uint64_t numa_nodes; -- cgit v1.2.3-55-g7522 From f264d360e0bebf4fae054e624bf7204788aff99d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:31 -0200 Subject: pc: Move PcGuestInfo.fw_cfg to PCMachineState Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 7 +++---- hw/i386/pc.c | 10 ++++------ include/hw/i386/pc.h | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index dac7137471..86baf63a1d 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2806,11 +2806,10 @@ void acpi_setup(void) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; AcpiBuildTables tables; AcpiBuildState *build_state; - if (!guest_info->fw_cfg) { + if (!pcms->fw_cfg) { ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); return; } @@ -2841,7 +2840,7 @@ void acpi_setup(void) 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 (!pcmc->rsdp_in_ram) { @@ -2853,7 +2852,7 @@ void acpi_setup(void) 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/pc.c b/hw/i386/pc.c index dc0ade4a8c..a47784a38e 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1172,10 +1172,10 @@ void pc_machine_done(Notifier *notifier, void *data) extra_hosts++; } } - if (extra_hosts && pcms->acpi_guest_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(pcms->acpi_guest_info.fw_cfg, + fw_cfg_add_file(pcms->fw_cfg, "etc/extra-pci-roots", val, sizeof(*val)); } } @@ -1257,7 +1257,6 @@ void xen_load_linux(PCMachineState *pcms) { int i; FWCfgState *fw_cfg; - PcGuestInfo *guest_info = &pcms->acpi_guest_info; assert(MACHINE(pcms)->kernel_filename != NULL); @@ -1270,7 +1269,7 @@ void 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; + pcms->fw_cfg = fw_cfg; } void pc_memory_init(PCMachineState *pcms, @@ -1278,7 +1277,6 @@ void pc_memory_init(PCMachineState *pcms, MemoryRegion *rom_memory, MemoryRegion **ram_memory) { - PcGuestInfo *guest_info = &pcms->acpi_guest_info; int linux_boot, i; MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; @@ -1399,7 +1397,7 @@ void 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; + pcms->fw_cfg = fw_cfg; } qemu_irq pc_allocate_cpu_irq(void) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 6a5c4da053..40249b6b02 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -40,7 +40,6 @@ struct PcGuestInfo { uint64_t numa_nodes; uint64_t *node_mem; uint64_t *node_cpu; - FWCfgState *fw_cfg; }; /** @@ -62,6 +61,7 @@ struct PCMachineState { HotplugHandler *acpi_dev; ISADevice *rtc; PCIBus *bus; + FWCfgState *fw_cfg; /* Configuration options: */ uint64_t max_ram_below_4g; -- cgit v1.2.3-55-g7522 From dd4c2f01ab92ae0a158958a8fc61fcd09e34987a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:32 -0200 Subject: pc: Move APIC and NUMA data from PcGuestInfo to PCMachineState Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/i386/acpi-build.c | 22 +++++++++------------- hw/i386/pc.c | 20 ++++++++++---------- include/hw/i386/pc.h | 14 +++++++++----- 3 files changed, 28 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 86baf63a1d..35582a761d 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -364,7 +364,6 @@ static void build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; int madt_start = table_data->len; AcpiMultipleApicTable *madt; @@ -377,7 +376,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); @@ -397,7 +396,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); @@ -1946,7 +1945,6 @@ build_dsdt(GArray *table_data, GArray *linker, GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free); MachineState *machine = MACHINE(qdev_get_machine()); PCMachineState *pcms = PC_MACHINE(machine); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; uint32_t nr_mem = machine->ram_slots; int root_bus_limit = 0xFF; PCIBus *bus = NULL; @@ -2247,7 +2245,7 @@ build_dsdt(GArray *table_data, GArray *linker, 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); @@ -2379,7 +2377,6 @@ build_srat(GArray *table_data, GArray *linker) int srat_start, numa_start, slots; uint64_t mem_len, mem_base, next_base; PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; ram_addr_t hotplugabble_address_space_size = object_property_get_int(OBJECT(pcms), PC_MACHINE_MEMHP_REGION_SIZE, NULL); @@ -2390,12 +2387,12 @@ build_srat(GArray *table_data, GArray *linker) 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; @@ -2412,9 +2409,9 @@ build_srat(GArray *table_data, GArray *linker) 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; } @@ -2438,7 +2435,7 @@ build_srat(GArray *table_data, GArray *linker) 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); } @@ -2594,7 +2591,6 @@ void acpi_build(AcpiBuildTables *tables) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); - PcGuestInfo *guest_info = &pcms->acpi_guest_info; GArray *table_offsets; unsigned facs, dsdt, rsdt, fadt; AcpiCpuInfo cpu; @@ -2658,7 +2654,7 @@ void acpi_build(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); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a47784a38e..66f7bb9bc0 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1188,24 +1188,24 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; - 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; } } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 40249b6b02..0cf67ed6f3 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -35,11 +35,6 @@ /* Machine info for ACPI build: */ struct PcGuestInfo { - unsigned apic_id_limit; - bool apic_xrupt_override; - uint64_t numa_nodes; - uint64_t *node_mem; - uint64_t *node_cpu; }; /** @@ -71,6 +66,15 @@ struct PCMachineState { /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; + + /* CPU and apic information: */ + bool apic_xrupt_override; + unsigned apic_id_limit; + + /* NUMA information: */ + uint64_t numa_nodes; + uint64_t *node_mem; + uint64_t *node_cpu; }; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" -- cgit v1.2.3-55-g7522 From e4e8ba04c2007d3d05d8a29857f95ae80951f5a3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Dec 2015 16:42:33 -0200 Subject: pc: Eliminate PcGuestInfo struct The struct is not used for anything, now. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 4 +--- include/hw/i386/pc.h | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 66f7bb9bc0..ce185bbee9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1183,9 +1183,8 @@ void pc_machine_done(Notifier *notifier, void *data) acpi_setup(); } -PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) +void pc_guest_info_init(PCMachineState *pcms) { - PcGuestInfo *guest_info = &pcms->acpi_guest_info; int i, j; pcms->apic_id_limit = pc_apic_id_limit(max_cpus); @@ -1213,7 +1212,6 @@ PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) pcms->machine_done.notify = pc_machine_done; qemu_add_machine_init_done_notifier(&pcms->machine_done); - return guest_info; } /* setup pci memory address space mapping into system address space */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0cf67ed6f3..8b3546ed5c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -33,10 +33,6 @@ #define kvm_ioapic_in_kernel() 0 #endif -/* Machine info for ACPI build: */ -struct PcGuestInfo { -}; - /** * PCMachineState: * @acpi_dev: link to ACPI PM device that performs ACPI hotplug handling @@ -49,7 +45,6 @@ struct PCMachineState { /* State for other subsystems/APIs: */ MemoryHotplugState hotplug_memory; - PcGuestInfo acpi_guest_info; Notifier machine_done; /* Pointers to devices and objects: */ @@ -233,7 +228,7 @@ void pc_cpus_init(PCMachineState *pcms); void pc_hot_add_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); -PcGuestInfo *pc_guest_info_init(PCMachineState *pcms); +void pc_guest_info_init(PCMachineState *pcms); #define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" #define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end" -- cgit v1.2.3-55-g7522 From 37ad223c515da2fe9f1c679768cb5ccaa42e57e1 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:10 +0100 Subject: acpi: take oem_id in build_header(), optionally This patch is the continuation of commit 8870ca0e94f2 ("acpi: support specified oem table id for build_header"). It will allow us to control the OEM ID field too in the SDT header. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Xiao Guangrong (maintainer:NVDIMM) Cc: Shannon Zhao (maintainer:ARM ACPI Subsystem) Cc: Paolo Bonzini (maintainer:X86) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Shannon Zhao --- hw/acpi/aml-build.c | 11 ++++++++--- hw/acpi/nvdimm.c | 4 ++-- hw/arm/virt-acpi-build.c | 12 ++++++------ hw/i386/acpi-build.c | 18 +++++++++--------- include/hw/acpi/aml-build.h | 2 +- 5 files changed, 26 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 21d2ea0c9c..e4b6c0caa9 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)); @@ -1506,5 +1511,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, NULL, NULL); } 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 87fbe7c97d..8017b12e6c 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -408,7 +408,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 @@ -427,7 +427,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 */ @@ -453,7 +453,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 */ @@ -515,7 +515,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 */ @@ -540,7 +540,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 */ @@ -579,7 +579,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(); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 35582a761d..061a9cbb21 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -357,7 +357,7 @@ 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, NULL, NULL); } static void @@ -427,7 +427,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 @@ -2286,7 +2286,7 @@ build_dsdt(GArray *table_data, GArray *linker, 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); + "DSDT", dsdt->buf->len, 1, NULL, NULL); free_aml_allocator(); } @@ -2302,7 +2302,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 @@ -2325,7 +2325,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); } @@ -2342,7 +2342,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 { @@ -2456,7 +2456,7 @@ build_srat(GArray *table_data, GArray *linker) 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 @@ -2485,7 +2485,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 @@ -2509,7 +2509,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); + "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } static GArray * diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 6d6f705b0c..c460bdd255 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -357,7 +357,7 @@ Aml *aml_sizeof(Aml *arg); 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); void *acpi_data_push(GArray *table_data, unsigned size); unsigned acpi_data_len(GArray *table); void acpi_add_table(GArray *table_offsets, GArray *table_data); -- cgit v1.2.3-55-g7522 From 5151355898699eb66fad0a710b8b6011690a0dfc Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:11 +0100 Subject: acpi: expose oem_id and oem_table_id in build_rsdt() Since build_rsdt() is implemented as common utility code (in "hw/acpi/aml-build.c"), it should expose -- and forward -- the oem_id and oem_table_id parameters between board code and the generic build_header() function. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Shannon Zhao (maintainer:ARM ACPI Subsystem) Cc: Paolo Bonzini (maintainer:X86) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Shannon Zhao --- hw/acpi/aml-build.c | 5 +++-- hw/arm/virt-acpi-build.c | 2 +- hw/i386/acpi-build.c | 2 +- include/hw/acpi/aml-build.h | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index e4b6c0caa9..603068b5ea 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1492,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; @@ -1511,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, NULL); + (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); } diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 8017b12e6c..560764fab1 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -643,7 +643,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/i386/acpi-build.c b/hw/i386/acpi-build.c index 061a9cbb21..705d12f3b3 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2681,7 +2681,7 @@ void acpi_build(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/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index c460bdd255..aa29d30d1f 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -364,6 +364,7 @@ void acpi_add_table(GArray *table_offsets, GArray *table_data); void acpi_build_tables_init(AcpiBuildTables *tables); void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre); 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); #endif -- cgit v1.2.3-55-g7522 From 88594e4fd1e916b778968b2bdd8d7375ca2fe8d8 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Mon, 18 Jan 2016 15:12:12 +0100 Subject: acpi: add function to extract oem_id and oem_table_id from the user's SLIC The acpi_get_slic_oem() function stores pointers to these fields in the (first) SLIC table that the user passes in with the -acpitable switch. Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) Cc: Igor Mammedov (supporter:ACPI/SMBIOS) Cc: Richard W.M. Jones Cc: Aleksei Kovura Cc: Michael Tokarev Cc: Steven Newbury RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 LP: https://bugs.launchpad.net/qemu/+bug/1533848 Signed-off-by: Laszlo Ersek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Steven Newbury --- hw/acpi/core.c | 16 ++++++++++++++++ include/hw/acpi/acpi.h | 7 +++++++ 2 files changed, 23 insertions(+) (limited to 'include') 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/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index b20bd55a67..2de30211f2 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -196,4 +196,11 @@ unsigned acpi_table_len(void *current); void acpi_table_add(const QemuOpts *opts, Error **errp); void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); +typedef struct AcpiSlicOem AcpiSlicOem; +struct AcpiSlicOem { + char *id; + char *table_id; +}; +int acpi_get_slic_oem(AcpiSlicOem *oem); + #endif /* !QEMU_HW_ACPI_H */ -- cgit v1.2.3-55-g7522 From adcb4ee660cf579f003e9d4afd61b608259091c6 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 21 Jan 2016 12:37:51 +1100 Subject: dimm: Correct type of MemoryHotplugState->base The 'base' field of MemoryHotplugState is ram_addr_t, which indicates that it exists in the abstract address space of RAM regions. However, the actual usage of this field indicates that it is a concrete physical address (it's passed as an offset to memory_region_add_subgregion for example). So, correct its type to 'hwaddr'. Signed-off-by: David Gibson Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov Acked-by: Eduardo Habkost --- include/hw/mem/pc-dimm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h index d83bf30ea9..218dfb0eda 100644 --- a/include/hw/mem/pc-dimm.h +++ b/include/hw/mem/pc-dimm.h @@ -77,7 +77,7 @@ typedef struct PCDIMMDeviceClass { * @mr: hotplug memory address space container */ typedef struct MemoryHotplugState { - ram_addr_t base; + hwaddr base; MemoryRegion mr; } MemoryHotplugState; -- cgit v1.2.3-55-g7522 From d66b969b0d9c8eefdcbff4b48535b0fe1501d139 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 14 Jan 2016 00:47:24 -0500 Subject: intel_iommu: large page support Current intel_iommu only supports 4K page which may not be sufficient to cover guest working set. This patch tries to enable 2M and 1G mapping for intel_iommu. This is also useful for future device IOTLB implementation to have a better hit rate. Major work is adding a page mask field on IOTLB entry to make it support large page. And also use the slpte level as key to do IOTLB lookup. MAMV was increased to 18 to support direct invalidation for 1G mapping. Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 76 ++++++++++++++++++++++++++++++------------ hw/i386/intel_iommu_internal.h | 6 ++-- include/hw/i386/intel_iommu.h | 1 + 3 files changed, 59 insertions(+), 24 deletions(-) (limited to 'include') 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/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 5dbadb785c..b024ffa720 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -83,6 +83,7 @@ struct VTDIOTLBEntry { uint64_t gfn; uint16_t domain_id; uint64_t slpte; + uint64_t mask; bool read_flags; bool write_flags; }; -- cgit v1.2.3-55-g7522 From 428c3ece97179557f2753071fb0ca97a03437267 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 13 Jan 2016 14:59:09 +0000 Subject: fix MSI injection on Xen On Xen MSIs can be remapped into pirqs, which are a type of event channels. It's mostly for the benefit of PCI passthrough devices, to avoid the overhead of interacting with the emulated lapic. However remapping interrupts and MSIs is also supported for emulated devices, such as the e1000 and virtio-net. When an interrupt or an MSI is remapped into a pirq, masking and unmasking is done by masking and unmasking the event channel. The masking bit on the PCI config space or MSI-X table should be ignored, but it isn't at the moment. As a consequence emulated devices which use MSI or MSI-X, such as virtio-net, don't work properly (the guest doesn't receive any notifications). The mechanism was working properly when xen_apic was introduced, but I haven't narrowed down which commit in particular is causing the regression. Fix the issue by ignoring the masking bit for MSI and MSI-X which have been remapped into pirqs. Signed-off-by: Stefano Stabellini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/msi.c | 9 ++++++++- hw/pci/msix.c | 12 ++++++++++-- hw/xen/xen_pt_msi.c | 4 +--- include/hw/xen/xen.h | 1 + xen-hvm-stub.c | 5 +++++ xen-hvm.c | 9 +++++++++ 6 files changed, 34 insertions(+), 6 deletions(-) (limited to 'include') 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/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, diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 1b81b4be9a..c57735419c 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -33,6 +33,7 @@ int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); void xen_piix3_set_irq(void *opaque, int irq_num, int level); void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); void xen_hvm_inject_msi(uint64_t addr, uint32_t data); +int xen_is_pirq_msi(uint32_t msi_data); qemu_irq *xen_interrupt_controller_init(void); diff --git a/xen-hvm-stub.c b/xen-hvm-stub.c index a6cb5d358f..c5003251cb 100644 --- a/xen-hvm-stub.c +++ b/xen-hvm-stub.c @@ -31,6 +31,11 @@ void xen_hvm_inject_msi(uint64_t addr, uint32_t data) { } +int xen_is_pirq_msi(uint32_t msi_data) +{ + return 0; +} + void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr, Error **errp) { diff --git a/xen-hvm.c b/xen-hvm.c index 1c9fb12955..6861c51ef9 100644 --- a/xen-hvm.c +++ b/xen-hvm.c @@ -13,6 +13,7 @@ #include "hw/pci/pci.h" #include "hw/i386/pc.h" +#include "hw/i386/apic-msidef.h" #include "hw/xen/xen_common.h" #include "hw/xen/xen_backend.h" #include "qmp-commands.h" @@ -158,6 +159,14 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) } } +int xen_is_pirq_msi(uint32_t msi_data) +{ + /* If vector is 0, the msi is remapped into a pirq, passed as + * dest_id. + */ + return ((msi_data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT) == 0; +} + void xen_hvm_inject_msi(uint64_t addr, uint32_t data) { xen_xc_hvm_inject_msi(xen_xc, xen_domid, addr, data); -- cgit v1.2.3-55-g7522