diff options
| -rw-r--r-- | MAINTAINERS | 11 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | accel/kvm/kvm-all.c | 15 | ||||
| -rw-r--r-- | disas/nanomips.c | 194 | ||||
| -rw-r--r-- | docs/system/device-emulation.rst | 1 | ||||
| -rw-r--r-- | docs/system/devices/vdpa-net.rst | 121 | ||||
| -rw-r--r-- | hw/audio/virtio-snd.c | 129 | ||||
| -rw-r--r-- | hw/block/vhost-user-blk.c | 11 | ||||
| -rw-r--r-- | hw/block/virtio-blk.c | 3 | ||||
| -rw-r--r-- | hw/display/vga.c | 146 | ||||
| -rw-r--r-- | hw/i386/pc_q35.c | 1 | ||||
| -rw-r--r-- | hw/net/virtio-net.c | 16 | ||||
| -rw-r--r-- | hw/scsi/esp.c | 223 | ||||
| -rw-r--r-- | hw/scsi/lsi53c895a.c | 19 | ||||
| -rw-r--r-- | hw/virtio/vdpa-dev.c | 7 | ||||
| -rw-r--r-- | hw/virtio/virtio-pci.c | 189 | ||||
| -rw-r--r-- | hw/virtio/virtio.c | 51 | ||||
| -rw-r--r-- | include/hw/audio/virtio-snd.h | 16 | ||||
| -rw-r--r-- | include/hw/virtio/virtio-pci.h | 5 | ||||
| -rw-r--r-- | include/hw/virtio/virtio.h | 19 | ||||
| -rw-r--r-- | include/standard-headers/linux/virtio_pci.h | 7 | ||||
| -rw-r--r-- | migration/savevm.c | 21 | ||||
| -rw-r--r-- | system/qdev-monitor.c | 2 | ||||
| -rw-r--r-- | target/arm/helper.c | 10 |
24 files changed, 466 insertions, 753 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e71183eef9..f1f6922025 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2170,7 +2170,7 @@ S: Supported F: hw/vfio/* F: include/hw/vfio/ F: docs/igd-assign.txt -F: docs/devel/vfio-migration.rst +F: docs/devel/migration/vfio.rst vfio-ccw M: Eric Farman <farman@linux.ibm.com> @@ -2231,6 +2231,7 @@ F: qapi/virtio.json F: net/vhost-user.c F: include/hw/virtio/ F: docs/devel/virtio* +F: docs/devel/migration/virtio.rst virtio-balloon M: Michael S. Tsirkin <mst@redhat.com> @@ -2370,11 +2371,6 @@ F: hw/virtio/vhost-user-scmi* F: include/hw/virtio/vhost-user-scmi.h F: tests/qtest/libqos/virtio-scmi.* -vdpa-net -M: Hao Chen <chenh@yusur.tech> -S: Maintained -F: docs/system/devices/vdpa-net.rst - virtio-crypto M: Gonglei <arei.gonglei@huawei.com> S: Supported @@ -3422,7 +3418,7 @@ F: migration/ F: scripts/vmstate-static-checker.py F: tests/vmstate-static-checker-data/ F: tests/qtest/migration-test.c -F: docs/devel/migration.rst +F: docs/devel/migration/ F: qapi/migration.json F: tests/migration/ F: util/userfaultfd.c @@ -3442,6 +3438,7 @@ F: include/sysemu/dirtylimit.h F: migration/dirtyrate.c F: migration/dirtyrate.h F: include/sysemu/dirtyrate.h +F: docs/devel/migration/dirty-limit.rst Detached LUKS header M: Hyman Huang <yong.huang@smartx.com> diff --git a/Makefile b/Makefile index 8f36990335..183756018f 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ MAKE.k = $(findstring k,$(firstword $(filter-out --%,$(MAKEFLAGS)))) MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS)))) MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq) NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ - $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \ + $(or $(filter -l% -j%, $(MAKEFLAGS)), $(if $(filter --jobserver-auth=%, $(MAKEFLAGS)),, -j1)) \ -d keepdepfile ninja-cmd-goals = $(or $(MAKECMDGOALS), all) ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g)) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index a8cecd040e..931f74256e 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1999,12 +1999,17 @@ int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev) return -EINVAL; } - trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A", - vector, virq); + if (s->irq_routes->nr < s->gsi_count) { + trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A", + vector, virq); - kvm_add_routing_entry(s, &kroute); - kvm_arch_add_msi_route_post(&kroute, vector, dev); - c->changes++; + kvm_add_routing_entry(s, &kroute); + kvm_arch_add_msi_route_post(&kroute, vector, dev); + c->changes++; + } else { + kvm_irqchip_release_virq(s, virq); + return -ENOSPC; + } return virq; } diff --git a/disas/nanomips.c b/disas/nanomips.c index a0253598dd..db0c297b8d 100644 --- a/disas/nanomips.c +++ b/disas/nanomips.c @@ -36,35 +36,6 @@ typedef uint32_t uint32; typedef uint16_t uint16; typedef uint64_t img_address; -typedef enum { - instruction, - call_instruction, - branch_instruction, - return_instruction, - reserved_block, - pool, -} TABLE_ENTRY_TYPE; - -typedef enum { - MIPS64_ = 0x00000001, - XNP_ = 0x00000002, - XMMS_ = 0x00000004, - EVA_ = 0x00000008, - DSP_ = 0x00000010, - MT_ = 0x00000020, - EJTAG_ = 0x00000040, - TLBINV_ = 0x00000080, - CP0_ = 0x00000100, - CP1_ = 0x00000200, - CP2_ = 0x00000400, - UDI_ = 0x00000800, - MCU_ = 0x00001000, - VZ_ = 0x00002000, - TLB_ = 0x00004000, - MVH_ = 0x00008000, - ALL_ATTRIBUTES = 0xffffffffull, -} TABLE_ATTRIBUTE_TYPE; - typedef struct Dis_info { img_address m_pc; fprintf_function fprintf_func; @@ -72,22 +43,6 @@ typedef struct Dis_info { sigjmp_buf buf; } Dis_info; -typedef bool (*conditional_function)(uint64 instruction); -typedef char * (*disassembly_function)(uint64 instruction, - Dis_info *info); - -typedef struct Pool { - TABLE_ENTRY_TYPE type; - const struct Pool *next_table; - int next_table_size; - int instructions_size; - uint64 mask; - uint64 value; - disassembly_function disassembly; - conditional_function condition; - uint64 attributes; -} Pool; - #define IMGASSERTONCE(test) @@ -544,58 +499,6 @@ static uint64 extract_op_code_value(const uint16 *data, int size) } -/* - * Recurse through tables until the instruction is found then return - * the string and size - * - * inputs: - * pointer to a word stream, - * disassember table and size - * returns: - * instruction size - negative is error - * disassembly string - on error will constain error string - */ -static int Disassemble(const uint16 *data, char **dis, - TABLE_ENTRY_TYPE *type, const Pool *table, - int table_size, Dis_info *info) -{ - for (int i = 0; i < table_size; i++) { - uint64 op_code = extract_op_code_value(data, - table[i].instructions_size); - if ((op_code & table[i].mask) == table[i].value) { - /* possible match */ - conditional_function cond = table[i].condition; - if ((cond == NULL) || cond(op_code)) { - if (table[i].type == pool) { - return Disassemble(data, dis, type, - table[i].next_table, - table[i].next_table_size, - info); - } else if ((table[i].type == instruction) || - (table[i].type == call_instruction) || - (table[i].type == branch_instruction) || - (table[i].type == return_instruction)) { - disassembly_function dis_fn = table[i].disassembly; - if (dis_fn == 0) { - *dis = g_strdup( - "disassembler failure - bad table entry"); - return -6; - } - *type = table[i].type; - *dis = dis_fn(op_code, info); - return table[i].instructions_size; - } else { - *dis = g_strdup("reserved instruction"); - return -2; - } - } - } - } - *dis = g_strdup("failed to disassemble"); - return -1; /* failed to disassemble */ -} - - static uint64 extract_code_18_to_0(uint64 instruction) { uint64 value = 0; @@ -16213,6 +16116,51 @@ static char *YIELD(uint64 instruction, Dis_info *info) * */ +typedef enum { + instruction, + call_instruction, + branch_instruction, + return_instruction, + reserved_block, + pool, +} TABLE_ENTRY_TYPE; + +typedef enum { + MIPS64_ = 0x00000001, + XNP_ = 0x00000002, + XMMS_ = 0x00000004, + EVA_ = 0x00000008, + DSP_ = 0x00000010, + MT_ = 0x00000020, + EJTAG_ = 0x00000040, + TLBINV_ = 0x00000080, + CP0_ = 0x00000100, + CP1_ = 0x00000200, + CP2_ = 0x00000400, + UDI_ = 0x00000800, + MCU_ = 0x00001000, + VZ_ = 0x00002000, + TLB_ = 0x00004000, + MVH_ = 0x00008000, + ALL_ATTRIBUTES = 0xffffffffull, +} TABLE_ATTRIBUTE_TYPE; + +typedef bool (*conditional_function)(uint64 instruction); +typedef char * (*disassembly_function)(uint64 instruction, + Dis_info *info); + +typedef struct Pool { + TABLE_ENTRY_TYPE type; + const struct Pool *next_table; + int next_table_size; + int instructions_size; + uint64 mask; + uint64 value; + disassembly_function disassembly; + conditional_function condition; + uint64 attributes; +} Pool; + static const Pool P_SYSCALL[2] = { { instruction , 0 , 0 , 32, 0xfffc0000, 0x00080000, &SYSCALL_32_ , 0, @@ -21907,6 +21855,58 @@ static const Pool MAJOR[2] = { 0x0 }, /* P16 */ }; +/* + * Recurse through tables until the instruction is found then return + * the string and size + * + * inputs: + * pointer to a word stream, + * disassember table and size + * returns: + * instruction size - negative is error + * disassembly string - on error will constain error string + */ +static int Disassemble(const uint16 *data, char **dis, + TABLE_ENTRY_TYPE *type, const Pool *table, + int table_size, Dis_info *info) +{ + for (int i = 0; i < table_size; i++) { + uint64 op_code = extract_op_code_value(data, + table[i].instructions_size); + if ((op_code & table[i].mask) == table[i].value) { + /* possible match */ + conditional_function cond = table[i].condition; + if ((cond == NULL) || cond(op_code)) { + if (table[i].type == pool) { + return Disassemble(data, dis, type, + table[i].next_table, + table[i].next_table_size, + info); + } else if ((table[i].type == instruction) || + (table[i].type == call_instruction) || + (table[i].type == branch_instruction) || + (table[i].type == return_instruction)) { + disassembly_function dis_fn = table[i].disassembly; + if (dis_fn == 0) { + *dis = g_strdup( + "disassembler failure - bad table entry"); + return -6; + } + *type = table[i].type; + *dis = dis_fn(op_code, info); + return table[i].instructions_size; + } else { + *dis = g_strdup("reserved instruction"); + return -2; + } + } + } + } + *dis = g_strdup("failed to disassemble"); + return -1; /* failed to disassemble */ +} + + static bool nanomips_dis(const uint16_t *data, char **buf, Dis_info *info) { TABLE_ENTRY_TYPE type; diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst index e4a27f53c8..f19777411c 100644 --- a/docs/system/device-emulation.rst +++ b/docs/system/device-emulation.rst @@ -99,4 +99,3 @@ Emulated Devices devices/canokey.rst devices/usb-u2f.rst devices/igb.rst - devices/vdpa-net.rst diff --git a/docs/system/devices/vdpa-net.rst b/docs/system/devices/vdpa-net.rst deleted file mode 100644 index 323d8c926a..0000000000 --- a/docs/system/devices/vdpa-net.rst +++ /dev/null @@ -1,121 +0,0 @@ -vdpa net -============ - -This document explains the setup and usage of the vdpa network device. -The vdpa network device is a paravirtualized vdpa emulate device. - -Description ------------ - -VDPA net devices support dirty page bitmap mark and vring state saving and recovery. - -Users can use this VDPA device for live migration simulation testing in a nested virtualization environment. - -Registers layout ----------------- - -The vdpa device add live migrate registers layout as follow:: - - Offset Register Name Bitwidth Associated vq - 0x0 LM_LOGGING_CTRL 4bits - 0x10 LM_BASE_ADDR_LOW 32bits - 0x14 LM_BASE_ADDR_HIGH 32bits - 0x18 LM_END_ADDR_LOW 32bits - 0x1c LM_END_ADDR_HIGH 32bits - 0x20 LM_RING_STATE_OFFSET 32bits vq0 - 0x24 LM_RING_STATE_OFFSET 32bits vq1 - 0x28 LM_RING_STATE_OFFSET 32bits vq2 - ...... - 0x20+1023*4 LM_RING_STATE_OFFSET 32bits vq1023 - -These registers are extended at the end of the notify bar space. - -Architecture diagram --------------------- -:: - - |------------------------------------------------------------------------| - | guest-L1-user-space | - | | - | |----------------------------------------| - | | [virtio-net driver] | - | | ^ guest-L2-src(iommu=on) | - | |--------------|-------------------------| - | | | qemu-L2-src(viommu) | - | [dpdk-vdpa]<->[vhost socket]<-+->[vhost-user backend(iommu=on)] | - -------------------------------------------------------------------------- - -------------------------------------------------------------------------- - | ^ guest-L1-kernel-space | - | | | - | [VFIO] | - | ^ | - | | guest-L1-src(iommu=on) | - --------|----------------------------------------------------------------- - --------|----------------------------------------------------------------- - | [vdpa net device(iommu=on)] [manager nic device] | - | | | | - | | | | - | [tap device] qemu-L1-src(viommu) | | - ------------------------------------------------+------------------------- - | - | - --------------------- | - | kernel net bridge |<----- - | virbr0 |<---------------------------------- - --------------------- | - | - | - -------------------------------------------------------------------------- | - | guest-L1-user-space | | - | | | - | |----------------------------------------| | - | | [virtio-net driver] | | - | | ^ guest-L2-dst(iommu=on) | | - | |--------------|-------------------------| | - | | | qemu-L2-dst(viommu) | | - | [dpdk-vdpa]<->[vhost socket]<-+->[vhost-user backend(iommu=on)] | | - -------------------------------------------------------------------------- | - -------------------------------------------------------------------------- | - | ^ guest-L1-kernel-space | | - | | | | - | [VFIO] | | - | ^ | | - | | guest-L1-dst(iommu=on) | | - --------|----------------------------------------------------------------- | - --------|----------------------------------------------------------------- | - | [vdpa net device(iommu=on)] [manager nic device]----------------+---- - | | | - | | | - | [tap device] qemu-L1-dst(viommu) | - -------------------------------------------------------------------------- - - -Device properties ------------------ - -The Virtio vdpa device can be configured with the following properties: - - * ``vdpa=on`` open vdpa device emulated. - -Usages --------- -This patch add virtio sriov support and vdpa live migrate support. -You can open vdpa by set xml file as follow:: - - <qemu:commandline xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> - <qemu:arg value='-device'/> - <qemu:arg value='intel-iommu,intremap=on,device-iotlb=on,aw-bits=48'/> - <qemu:arg value='-netdev'/> - <qemu:arg value='tap,id=hostnet1,script=no,downscript=no,vhost=off'/> - <qemu:arg value='-device'/> - <qemu:arg value='virtio-net-pci,netdev=hostnet1,id=net1,mac=56:4a:b7:4f:4d:a9,bus=pci.6,addr=0x0,iommu_platform=on,ats=on,vdpa=on'/> - </qemu:commandline> - -Limitations ------------ -1. Dependent on tap device with param ``vhost=off``. -2. Nested virtualization environment only supports ``q35`` machines. -3. Current only support split vring live migrate. - - - diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c index e604d8f30c..90d9a2796e 100644 --- a/hw/audio/virtio-snd.c +++ b/hw/audio/virtio-snd.c @@ -456,7 +456,6 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id) stream->s = s; qemu_mutex_init(&stream->queue_mutex); QSIMPLEQ_INIT(&stream->queue); - QSIMPLEQ_INIT(&stream->invalid); /* * stream_id >= s->snd_conf.streams was checked before so this is @@ -611,9 +610,6 @@ static size_t virtio_snd_pcm_get_io_msgs_count(VirtIOSoundPCMStream *stream) QSIMPLEQ_FOREACH_SAFE(buffer, &stream->queue, entry, next) { count += 1; } - QSIMPLEQ_FOREACH_SAFE(buffer, &stream->invalid, entry, next) { - count += 1; - } } return count; } @@ -831,47 +827,36 @@ static void virtio_snd_handle_event(VirtIODevice *vdev, VirtQueue *vq) trace_virtio_snd_handle_event(); } +/* + * Must only be called if vsnd->invalid is not empty. + */ static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSoundPCMBuffer *buffer = NULL; - VirtIOSoundPCMStream *stream = NULL; virtio_snd_pcm_status resp = { 0 }; VirtIOSound *vsnd = VIRTIO_SND(vdev); - bool any = false; - for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { - stream = vsnd->pcm->streams[i]; - if (stream) { - any = false; - WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { - while (!QSIMPLEQ_EMPTY(&stream->invalid)) { - buffer = QSIMPLEQ_FIRST(&stream->invalid); - if (buffer->vq != vq) { - break; - } - any = true; - resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); - iov_from_buf(buffer->elem->in_sg, - buffer->elem->in_num, - 0, - &resp, - sizeof(virtio_snd_pcm_status)); - virtqueue_push(vq, - buffer->elem, - sizeof(virtio_snd_pcm_status)); - QSIMPLEQ_REMOVE_HEAD(&stream->invalid, entry); - virtio_snd_pcm_buffer_free(buffer); - } - if (any) { - /* - * Notify vq about virtio_snd_pcm_status responses. - * Buffer responses must be notified separately later. - */ - virtio_notify(vdev, vq); - } - } - } + g_assert(!QSIMPLEQ_EMPTY(&vsnd->invalid)); + + while (!QSIMPLEQ_EMPTY(&vsnd->invalid)) { + buffer = QSIMPLEQ_FIRST(&vsnd->invalid); + /* If buffer->vq != vq, our logic is fundamentally wrong, so bail out */ + g_assert(buffer->vq == vq); + + resp.status = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + iov_from_buf(buffer->elem->in_sg, + buffer->elem->in_num, + 0, + &resp, + sizeof(virtio_snd_pcm_status)); + virtqueue_push(vq, + buffer->elem, + sizeof(virtio_snd_pcm_status)); + QSIMPLEQ_REMOVE_HEAD(&vsnd->invalid, entry); + virtio_snd_pcm_buffer_free(buffer); } + /* Notify vq about virtio_snd_pcm_status responses. */ + virtio_notify(vdev, vq); } /* @@ -883,15 +868,14 @@ static inline void empty_invalid_queue(VirtIODevice *vdev, VirtQueue *vq) */ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq) { - VirtIOSound *s = VIRTIO_SND(vdev); - VirtIOSoundPCMStream *stream = NULL; + VirtIOSound *vsnd = VIRTIO_SND(vdev); VirtIOSoundPCMBuffer *buffer; VirtQueueElement *elem; size_t msg_sz, size; virtio_snd_pcm_xfer hdr; uint32_t stream_id; /* - * If any of the I/O messages are invalid, put them in stream->invalid and + * If any of the I/O messages are invalid, put them in vsnd->invalid and * return them after the for loop. */ bool must_empty_invalid_queue = false; @@ -901,7 +885,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq) } trace_virtio_snd_handle_tx_xfer(); - for (;;) { + for (VirtIOSoundPCMStream *stream = NULL;; stream = NULL) { elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { break; @@ -917,12 +901,12 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq) } stream_id = le32_to_cpu(hdr.stream_id); - if (stream_id >= s->snd_conf.streams - || s->pcm->streams[stream_id] == NULL) { + if (stream_id >= vsnd->snd_conf.streams + || vsnd->pcm->streams[stream_id] == NULL) { goto tx_err; } - stream = s->pcm->streams[stream_id]; + stream = vsnd->pcm->streams[stream_id]; if (stream->info.direction != VIRTIO_SND_D_OUTPUT) { goto tx_err; } @@ -942,13 +926,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq) continue; tx_err: - WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { - must_empty_invalid_queue = true; - buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); - buffer->elem = elem; - buffer->vq = vq; - QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry); - } + must_empty_invalid_queue = true; + buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); + buffer->elem = elem; + buffer->vq = vq; + QSIMPLEQ_INSERT_TAIL(&vsnd->invalid, buffer, entry); } if (must_empty_invalid_queue) { @@ -965,15 +947,14 @@ tx_err: */ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq) { - VirtIOSound *s = VIRTIO_SND(vdev); - VirtIOSoundPCMStream *stream = NULL; + VirtIOSound *vsnd = VIRTIO_SND(vdev); VirtIOSoundPCMBuffer *buffer; VirtQueueElement *elem; size_t msg_sz, size; virtio_snd_pcm_xfer hdr; uint32_t stream_id; /* - * if any of the I/O messages are invalid, put them in stream->invalid and + * if any of the I/O messages are invalid, put them in vsnd->invalid and * return them after the for loop. */ bool must_empty_invalid_queue = false; @@ -983,7 +964,7 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq) } trace_virtio_snd_handle_rx_xfer(); - for (;;) { + for (VirtIOSoundPCMStream *stream = NULL;; stream = NULL) { elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { break; @@ -999,12 +980,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq) } stream_id = le32_to_cpu(hdr.stream_id); - if (stream_id >= s->snd_conf.streams - || !s->pcm->streams[stream_id]) { + if (stream_id >= vsnd->snd_conf.streams + || !vsnd->pcm->streams[stream_id]) { goto rx_err; } - stream = s->pcm->streams[stream_id]; + stream = vsnd->pcm->streams[stream_id]; if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) { goto rx_err; } @@ -1021,13 +1002,11 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq) continue; rx_err: - WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) { - must_empty_invalid_queue = true; - buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); - buffer->elem = elem; - buffer->vq = vq; - QSIMPLEQ_INSERT_TAIL(&stream->invalid, buffer, entry); - } + must_empty_invalid_queue = true; + buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer)); + buffer->elem = elem; + buffer->vq = vq; + QSIMPLEQ_INSERT_TAIL(&vsnd->invalid, buffer, entry); } if (must_empty_invalid_queue) { @@ -1127,6 +1106,7 @@ static void virtio_snd_realize(DeviceState *dev, Error **errp) virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer); qemu_mutex_init(&vsnd->cmdq_mutex); QTAILQ_INIT(&vsnd->cmdq); + QSIMPLEQ_INIT(&vsnd->invalid); for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) { status = virtio_snd_set_pcm_params(vsnd, i, &default_params); @@ -1376,13 +1356,20 @@ static void virtio_snd_unrealize(DeviceState *dev) static void virtio_snd_reset(VirtIODevice *vdev) { - VirtIOSound *s = VIRTIO_SND(vdev); + VirtIOSound *vsnd = VIRTIO_SND(vdev); virtio_snd_ctrl_command *cmd; - WITH_QEMU_LOCK_GUARD(&s->cmdq_mutex) { - while (!QTAILQ_EMPTY(&s->cmdq)) { - cmd = QTAILQ_FIRST(&s->cmdq); - QTAILQ_REMOVE(&s->cmdq, cmd, next); + /* + * Sanity check that the invalid buffer message queue is emptied at the end + * of every virtio_snd_handle_tx_xfer/virtio_snd_handle_rx_xfer call, and + * must be empty otherwise. + */ + g_assert(QSIMPLEQ_EMPTY(&vsnd->invalid)); + + WITH_QEMU_LOCK_GUARD(&vsnd->cmdq_mutex) { + while (!QTAILQ_EMPTY(&vsnd->cmdq)) { + cmd = QTAILQ_FIRST(&vsnd->cmdq); + QTAILQ_REMOVE(&vsnd->cmdq, cmd, next); virtio_snd_ctrl_cmd_free(cmd); } } diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 6a856ad51a..9e6bbc6950 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -91,7 +91,6 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) { int ret; - struct virtio_blk_config blkcfg; VirtIODevice *vdev = dev->vdev; VHostUserBlk *s = VHOST_USER_BLK(dev->vdev); Error *local_err = NULL; @@ -100,19 +99,15 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) return 0; } - ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg, + ret = vhost_dev_get_config(dev, (uint8_t *)&s->blkcfg, vdev->config_len, &local_err); if (ret < 0) { error_report_err(local_err); return ret; } - /* valid for resize only */ - if (blkcfg.capacity != s->blkcfg.capacity) { - s->blkcfg.capacity = blkcfg.capacity; - memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len); - virtio_notify_config(dev->vdev); - } + memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len); + virtio_notify_config(dev->vdev); return 0; } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 92de315f17..bb86e65f65 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -768,7 +768,8 @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq *req, sizeof(struct virtio_blk_zone_report) + sizeof(struct virtio_blk_zone_descriptor)) { virtio_error(vdev, "in buffer too small for zone report"); - return; + err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD; + goto out; } /* start byte offset of the zone report */ diff --git a/hw/display/vga.c b/hw/display/vga.c index bc5b83421b..77f59e8c11 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1501,31 +1501,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) disp_width = width; depth = s->get_bpp(s); - region_start = (s->params.start_addr * 4); - region_end = region_start + (ram_addr_t)s->params.line_offset * height; - region_end += width * depth / 8; /* scanline length */ - region_end -= s->params.line_offset; - if (region_end > s->vbe_size || depth == 0 || depth == 15) { - /* - * We land here on: - * - wraps around (can happen with cirrus vbe modes) - * - depth == 0 (256 color palette video mode) - * - depth == 15 - * - * Take the safe and slow route: - * - create a dirty bitmap snapshot for all vga memory. - * - force shadowing (so all vga memory access goes - * through vga_read_*() helpers). - * - * Given this affects only vga features which are pretty much - * unused by modern guests there should be no performance - * impact. - */ - region_start = 0; - region_end = s->vbe_size; - force_shadow = true; - } - /* bits 5-6: 0 = 16-color mode, 1 = 4-color mode, 2 = 256-color mode. */ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); @@ -1546,13 +1521,86 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } if (shift_control == 0) { + full_update |= update_palette16(s); if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) { disp_width <<= 1; + v = VGA_DRAW_LINE4D2; + } else { + v = VGA_DRAW_LINE4; } + bits = 4; + } else if (shift_control == 1) { + full_update |= update_palette16(s); if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) { disp_width <<= 1; + v = VGA_DRAW_LINE2D2; + } else { + v = VGA_DRAW_LINE2; } + bits = 4; + + } else { + switch (depth) { + default: + case 0: + full_update |= update_palette256(s); + v = VGA_DRAW_LINE8D2; + bits = 4; + break; + case 8: + full_update |= update_palette256(s); + v = VGA_DRAW_LINE8; + bits = 8; + break; + case 15: + v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE; + bits = 16; + break; + case 16: + v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE; + bits = 16; + break; + case 24: + v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE; + bits = 24; + break; + case 32: + v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE; + bits = 32; + break; + } + } + + /* Horizontal pel panning bit 3 is only used in text mode. */ + hpel = bits <= 8 ? s->params.hpel & 7 : 0; + + region_start = (s->params.start_addr * 4); + region_end = region_start + (ram_addr_t)s->params.line_offset * height; + region_end += width * depth / 8; /* scanline length */ + region_end -= s->params.line_offset; + if (hpel) { + region_end += 4; + } + if (region_end > s->vbe_size || depth == 0 || depth == 15) { + /* + * We land here on: + * - wraps around (can happen with cirrus vbe modes) + * - depth == 0 (256 color palette video mode) + * - depth == 15 + * + * Take the safe and slow route: + * - create a dirty bitmap snapshot for all vga memory. + * - force shadowing (so all vga memory access goes + * through vga_read_*() helpers). + * + * Given this affects only vga features which are pretty much + * unused by modern guests there should be no performance + * impact. + */ + region_start = 0; + region_end = s->vbe_size; + force_shadow = true; } /* @@ -1607,53 +1655,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } } - if (shift_control == 0) { - full_update |= update_palette16(s); - if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) { - v = VGA_DRAW_LINE4D2; - } else { - v = VGA_DRAW_LINE4; - } - bits = 4; - } else if (shift_control == 1) { - full_update |= update_palette16(s); - if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) { - v = VGA_DRAW_LINE2D2; - } else { - v = VGA_DRAW_LINE2; - } - bits = 4; - } else { - switch(s->get_bpp(s)) { - default: - case 0: - full_update |= update_palette256(s); - v = VGA_DRAW_LINE8D2; - bits = 4; - break; - case 8: - full_update |= update_palette256(s); - v = VGA_DRAW_LINE8; - bits = 8; - break; - case 15: - v = s->big_endian_fb ? VGA_DRAW_LINE15_BE : VGA_DRAW_LINE15_LE; - bits = 16; - break; - case 16: - v = s->big_endian_fb ? VGA_DRAW_LINE16_BE : VGA_DRAW_LINE16_LE; - bits = 16; - break; - case 24: - v = s->big_endian_fb ? VGA_DRAW_LINE24_BE : VGA_DRAW_LINE24_LE; - bits = 24; - break; - case 32: - v = s->big_endian_fb ? VGA_DRAW_LINE32_BE : VGA_DRAW_LINE32_LE; - bits = 32; - break; - } - } vga_draw_line = vga_draw_line_table[v]; if (!is_buffer_shared(surface) && s->cursor_invalidate) { @@ -1665,7 +1666,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE], s->params.line_compare, sr(s, VGA_SEQ_CLOCK_MODE)); #endif - hpel = bits <= 8 ? s->params.hpel : 0; addr1 = (s->params.start_addr * 4); bwidth = DIV_ROUND_UP(width * bits, 8); if (hpel) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index b5922b44af..c7bc8a2041 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -393,7 +393,6 @@ static void pc_q35_8_1_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_8_2_machine_options(m); - m->alias = NULL; pcmc->broken_32bit_mem_addr_check = true; compat_props_add(m->compat_props, hw_compat_8_1, hw_compat_8_1_len); compat_props_add(m->compat_props, pc_compat_8_1, pc_compat_8_1_len); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 58014a92ad..24e5e7d347 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -2039,22 +2039,6 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, goto err; } - /* Mark dirty page's bitmap of guest memory */ - if (vdev->lm_logging_ctrl == LM_ENABLE) { - uint64_t chunk = elem->in_addr[i] / VHOST_LOG_CHUNK; - /* Get chunk index */ - BitmapMemoryRegionCaches *caches = qatomic_rcu_read(&vdev->caches); - uint64_t index = chunk / 8; - uint64_t shift = chunk % 8; - uint8_t val = 0; - address_space_read_cached(&caches->bitmap, index, &val, - sizeof(val)); - val |= 1 << shift; - address_space_write_cached(&caches->bitmap, index, &val, - sizeof(val)); - address_space_cache_invalidate(&caches->bitmap, index, sizeof(val)); - } - elems[i] = elem; lens[i] = total; i++; diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 590ff99744..5d9b52632e 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -79,6 +79,24 @@ static void esp_lower_drq(ESPState *s) } } +static const char *esp_phase_names[8] = { + "DATA OUT", "DATA IN", "COMMAND", "STATUS", + "(reserved)", "(reserved)", "MESSAGE OUT", "MESSAGE IN" +}; + +static void esp_set_phase(ESPState *s, uint8_t phase) +{ + s->rregs[ESP_RSTAT] &= ~7; + s->rregs[ESP_RSTAT] |= phase; + + trace_esp_set_phase(esp_phase_names[phase]); +} + +static uint8_t esp_get_phase(ESPState *s) +{ + return s->rregs[ESP_RSTAT] & 7; +} + void esp_dma_enable(ESPState *s, int irq, int level) { if (level) { @@ -106,26 +124,80 @@ void esp_request_cancelled(SCSIRequest *req) } } -static void esp_fifo_push(Fifo8 *fifo, uint8_t val) +static void esp_update_drq(ESPState *s) { - if (fifo8_num_used(fifo) == fifo->capacity) { - trace_esp_error_fifo_overrun(); + bool to_device; + + switch (esp_get_phase(s)) { + case STAT_MO: + case STAT_CD: + case STAT_DO: + to_device = true; + break; + + case STAT_DI: + case STAT_ST: + case STAT_MI: + to_device = false; + break; + + default: return; } - fifo8_push(fifo, val); + if (s->dma) { + /* DMA request so update DRQ according to transfer direction */ + if (to_device) { + if (fifo8_num_free(&s->fifo) < 2) { + esp_lower_drq(s); + } else { + esp_raise_drq(s); + } + } else { + if (fifo8_num_used(&s->fifo) < 2) { + esp_lower_drq(s); + } else { + esp_raise_drq(s); + } + } + } else { + /* Not a DMA request */ + esp_lower_drq(s); + } } -static uint8_t esp_fifo_pop(Fifo8 *fifo) +static void esp_fifo_push(ESPState *s, uint8_t val) { - if (fifo8_is_empty(fifo)) { - return 0; + if (fifo8_num_used(&s->fifo) == s->fifo.capacity) { + trace_esp_error_fifo_overrun(); + } else { + fifo8_push(&s->fifo, val); } - return fifo8_pop(fifo); + esp_update_drq(s); } -static uint32_t esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen) +static void esp_fifo_push_buf(ESPState *s, uint8_t *buf, int len) +{ + fifo8_push_all(&s->fifo, buf, len); + esp_update_drq(s); +} + +static uint8_t esp_fifo_pop(ESPState *s) +{ + uint8_t val; + + if (fifo8_is_empty(&s->fifo)) { + val = 0; + } else { + val = fifo8_pop(&s->fifo); + } + + esp_update_drq(s); + return val; +} + +static uint32_t esp_fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen) { const uint8_t *buf; uint32_t n, n2; @@ -155,6 +227,14 @@ static uint32_t esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen) return n; } +static uint32_t esp_fifo_pop_buf(ESPState *s, uint8_t *dest, int maxlen) +{ + uint32_t len = esp_fifo8_pop_buf(&s->fifo, dest, maxlen); + + esp_update_drq(s); + return len; +} + static uint32_t esp_get_tc(ESPState *s) { uint32_t dmalen; @@ -190,29 +270,11 @@ static uint32_t esp_get_stc(ESPState *s) return dmalen; } -static const char *esp_phase_names[8] = { - "DATA OUT", "DATA IN", "COMMAND", "STATUS", - "(reserved)", "(reserved)", "MESSAGE OUT", "MESSAGE IN" -}; - -static void esp_set_phase(ESPState *s, uint8_t phase) -{ - s->rregs[ESP_RSTAT] &= ~7; - s->rregs[ESP_RSTAT] |= phase; - - trace_esp_set_phase(esp_phase_names[phase]); -} - -static uint8_t esp_get_phase(ESPState *s) -{ - return s->rregs[ESP_RSTAT] & 7; -} - static uint8_t esp_pdma_read(ESPState *s) { uint8_t val; - val = esp_fifo_pop(&s->fifo); + val = esp_fifo_pop(s); return val; } @@ -220,14 +282,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val) { uint32_t dmalen = esp_get_tc(s); - if (dmalen == 0) { - return; - } - - esp_fifo_push(&s->fifo, val); + esp_fifo_push(s, val); - dmalen--; - esp_set_tc(s, dmalen); + if (dmalen && s->drq_state) { + dmalen--; + esp_set_tc(s, dmalen); + } } static int esp_select(ESPState *s) @@ -275,7 +335,7 @@ static void do_command_phase(ESPState *s) if (!cmdlen || !s->current_dev) { return; } - esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen); + esp_fifo8_pop_buf(&s->cmdfifo, buf, cmdlen); current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun); if (!current_lun) { @@ -310,7 +370,8 @@ static void do_command_phase(ESPState *s) static void do_message_phase(ESPState *s) { if (s->cmdfifo_cdb_offset) { - uint8_t message = esp_fifo_pop(&s->cmdfifo); + uint8_t message = fifo8_is_empty(&s->cmdfifo) ? 0 : + fifo8_pop(&s->cmdfifo); trace_esp_do_identify(message); s->lun = message & 7; @@ -320,7 +381,7 @@ static void do_message_phase(ESPState *s) /* Ignore extended messages for now */ if (s->cmdfifo_cdb_offset) { int len = MIN(s->cmdfifo_cdb_offset, fifo8_num_used(&s->cmdfifo)); - esp_fifo_pop_buf(&s->cmdfifo, NULL, len); + esp_fifo8_pop_buf(&s->cmdfifo, NULL, len); s->cmdfifo_cdb_offset = 0; } } @@ -414,20 +475,30 @@ static void write_response(ESPState *s) } } -static int esp_cdb_length(ESPState *s) +static bool esp_cdb_ready(ESPState *s) { + int len = fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset; const uint8_t *pbuf; - int cmdlen, len; + uint32_t n; + int cdblen; - cmdlen = fifo8_num_used(&s->cmdfifo); - if (cmdlen < s->cmdfifo_cdb_offset) { - return 0; + if (len <= 0) { + return false; } - pbuf = fifo8_peek_buf(&s->cmdfifo, cmdlen, NULL); - len = scsi_cdb_length((uint8_t *)&pbuf[s->cmdfifo_cdb_offset]); + pbuf = fifo8_peek_buf(&s->cmdfifo, len, &n); + if (n < len) { + /* + * In normal use the cmdfifo should never wrap, but include this check + * to prevent a malicious guest from reading past the end of the + * cmdfifo data buffer below + */ + return false; + } - return len; + cdblen = scsi_cdb_length((uint8_t *)&pbuf[s->cmdfifo_cdb_offset]); + + return cdblen < 0 ? false : (len >= cdblen); } static void esp_dma_ti_check(ESPState *s) @@ -435,7 +506,6 @@ static void esp_dma_ti_check(ESPState *s) if (esp_get_tc(s) == 0 && fifo8_num_used(&s->fifo) < 2) { s->rregs[ESP_RINTR] |= INTR_BS; esp_raise_irq(s); - esp_lower_drq(s); } } @@ -453,9 +523,8 @@ static void esp_do_dma(ESPState *s) s->dma_memory_read(s->dma_opaque, buf, len); esp_set_tc(s, esp_get_tc(s) - len); } else { - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); - esp_raise_drq(s); } fifo8_push_all(&s->cmdfifo, buf, len); @@ -509,10 +578,9 @@ static void esp_do_dma(ESPState *s) fifo8_push_all(&s->cmdfifo, buf, len); esp_set_tc(s, esp_get_tc(s) - len); } else { - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); - esp_raise_drq(s); } trace_esp_handle_ti_cmd(cmdlen); s->ti_size = 0; @@ -543,8 +611,7 @@ static void esp_do_dma(ESPState *s) /* Copy FIFO data to device */ len = MIN(s->async_len, ESP_FIFO_SZ); len = MIN(len, fifo8_num_used(&s->fifo)); - len = esp_fifo_pop_buf(&s->fifo, s->async_buf, len); - esp_raise_drq(s); + len = esp_fifo_pop_buf(s, s->async_buf, len); } s->async_buf += len; @@ -595,8 +662,7 @@ static void esp_do_dma(ESPState *s) } else { /* Copy device data to FIFO */ len = MIN(len, fifo8_num_free(&s->fifo)); - fifo8_push_all(&s->fifo, s->async_buf, len); - esp_raise_drq(s); + esp_fifo_push_buf(s, s->async_buf, len); } s->async_buf += len; @@ -644,7 +710,7 @@ static void esp_do_dma(ESPState *s) if (s->dma_memory_write) { s->dma_memory_write(s->dma_opaque, buf, len); } else { - fifo8_push_all(&s->fifo, buf, len); + esp_fifo_push_buf(s, buf, len); } esp_set_tc(s, esp_get_tc(s) - len); @@ -662,7 +728,6 @@ static void esp_do_dma(ESPState *s) if (fifo8_num_used(&s->fifo) < 2) { s->rregs[ESP_RINTR] |= INTR_BS; esp_raise_irq(s); - esp_lower_drq(s); } break; } @@ -679,7 +744,7 @@ static void esp_do_dma(ESPState *s) if (s->dma_memory_write) { s->dma_memory_write(s->dma_opaque, buf, len); } else { - fifo8_push_all(&s->fifo, buf, len); + esp_fifo_push_buf(s, buf, len); } esp_set_tc(s, esp_get_tc(s) - len); @@ -707,7 +772,7 @@ static void esp_nodma_ti_dataout(ESPState *s) } len = MIN(s->async_len, ESP_FIFO_SZ); len = MIN(len, fifo8_num_used(&s->fifo)); - esp_fifo_pop_buf(&s->fifo, s->async_buf, len); + esp_fifo_pop_buf(s, s->async_buf, len); s->async_buf += len; s->async_len -= len; s->ti_size += len; @@ -732,7 +797,7 @@ static void esp_do_nodma(ESPState *s) switch (s->rregs[ESP_CMD]) { case CMD_SELATN: /* Copy FIFO into cmdfifo */ - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); @@ -751,7 +816,8 @@ static void esp_do_nodma(ESPState *s) case CMD_SELATNS: /* Copy one byte from FIFO into cmdfifo */ - len = esp_fifo_pop_buf(&s->fifo, buf, 1); + len = esp_fifo_pop_buf(s, buf, + MIN(fifo8_num_used(&s->fifo), 1)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); @@ -768,7 +834,7 @@ static void esp_do_nodma(ESPState *s) case CMD_TI: /* Copy FIFO into cmdfifo */ - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); @@ -786,7 +852,7 @@ static void esp_do_nodma(ESPState *s) switch (s->rregs[ESP_CMD]) { case CMD_TI: /* Copy FIFO into cmdfifo */ - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); @@ -794,10 +860,9 @@ static void esp_do_nodma(ESPState *s) trace_esp_handle_ti_cmd(cmdlen); /* CDB may be transferred in one or more TI commands */ - if (esp_cdb_length(s) && esp_cdb_length(s) == - fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset) { - /* Command has been received */ - do_cmd(s); + if (esp_cdb_ready(s)) { + /* Command has been received */ + do_cmd(s); } else { /* * If data was transferred from the FIFO then raise bus @@ -815,22 +880,21 @@ static void esp_do_nodma(ESPState *s) case CMD_SEL | CMD_DMA: case CMD_SELATN | CMD_DMA: /* Copy FIFO into cmdfifo */ - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); /* Handle when DMA transfer is terminated by non-DMA FIFO write */ - if (esp_cdb_length(s) && esp_cdb_length(s) == - fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset) { - /* Command has been received */ - do_cmd(s); + if (esp_cdb_ready(s)) { + /* Command has been received */ + do_cmd(s); } break; case CMD_SEL: case CMD_SELATN: /* FIFO already contain entire CDB: copy to cmdfifo and execute */ - len = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo)); + len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); len = MIN(fifo8_num_free(&s->cmdfifo), len); fifo8_push_all(&s->cmdfifo, buf, len); @@ -852,7 +916,7 @@ static void esp_do_nodma(ESPState *s) return; } if (fifo8_is_empty(&s->fifo)) { - fifo8_push(&s->fifo, s->async_buf[0]); + esp_fifo_push(s, s->async_buf[0]); s->async_buf++; s->async_len--; s->ti_size--; @@ -875,7 +939,7 @@ static void esp_do_nodma(ESPState *s) case STAT_ST: switch (s->rregs[ESP_CMD]) { case CMD_ICCS: - fifo8_push(&s->fifo, s->status); + esp_fifo_push(s, s->status); esp_set_phase(s, STAT_MI); /* Process any message in phase data */ @@ -887,7 +951,7 @@ static void esp_do_nodma(ESPState *s) case STAT_MI: switch (s->rregs[ESP_CMD]) { case CMD_ICCS: - fifo8_push(&s->fifo, 0); + esp_fifo_push(s, 0); /* Raise end of command interrupt */ s->rregs[ESP_RINTR] |= INTR_FC; @@ -951,9 +1015,6 @@ void esp_command_complete(SCSIRequest *req, size_t resid) s->rregs[ESP_RINTR] |= INTR_BS; esp_raise_irq(s); - /* Ensure DRQ is set correctly for TC underflow or normal completion */ - esp_dma_ti_check(s); - if (s->current_req) { scsi_req_unref(s->current_req); s->current_req = NULL; @@ -1178,7 +1239,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) switch (saddr) { case ESP_FIFO: - s->rregs[ESP_FIFO] = esp_fifo_pop(&s->fifo); + s->rregs[ESP_FIFO] = esp_fifo_pop(s); val = s->rregs[ESP_FIFO]; break; case ESP_RINTR: @@ -1234,7 +1295,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) break; case ESP_FIFO: if (!fifo8_is_full(&s->fifo)) { - esp_fifo_push(&s->fifo, val); + esp_fifo_push(s, val); } esp_do_nodma(s); break; diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 71f759a59d..eb9828dd5e 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -927,13 +927,18 @@ static void lsi_do_msgin(LSIState *s) assert(len > 0 && len <= LSI_MAX_MSGIN_LEN); if (len > s->dbc) len = s->dbc; - pci_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len); - /* Linux drivers rely on the last byte being in the SIDL. */ - s->sidl = s->msg[len - 1]; - s->msg_len -= len; - if (s->msg_len) { - memmove(s->msg, s->msg + len, s->msg_len); - } else { + + if (len) { + pci_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len); + /* Linux drivers rely on the last byte being in the SIDL. */ + s->sidl = s->msg[len - 1]; + s->msg_len -= len; + if (s->msg_len) { + memmove(s->msg, s->msg + len, s->msg_len); + } + } + + if (!s->msg_len) { /* ??? Check if ATN (not yet implemented) is asserted and maybe switch to PHASE_MO. */ switch (s->msg_action) { diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c index 13e87f06f6..64b96b226c 100644 --- a/hw/virtio/vdpa-dev.c +++ b/hw/virtio/vdpa-dev.c @@ -195,7 +195,14 @@ static void vhost_vdpa_device_get_config(VirtIODevice *vdev, uint8_t *config) { VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); + int ret; + ret = vhost_dev_get_config(&s->dev, s->config, s->config_size, + NULL); + if (ret < 0) { + error_report("get device config space failed"); + return; + } memcpy(config, s->config, s->config_size); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index eaaf86402c..cb6940fc0e 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1442,155 +1442,6 @@ int virtio_pci_add_shm_cap(VirtIOPCIProxy *proxy, return virtio_pci_add_mem_cap(proxy, &cap.cap); } -/* Called within call_rcu(). */ -static void bitmap_free_region_cache(BitmapMemoryRegionCaches *caches) -{ - assert(caches != NULL); - address_space_cache_destroy(&caches->bitmap); - g_free(caches); -} - -static void lm_disable(VirtIODevice *vdev) -{ - BitmapMemoryRegionCaches *caches; - caches = qatomic_read(&vdev->caches); - qatomic_rcu_set(&vdev->caches, NULL); - if (caches) { - call_rcu(caches, bitmap_free_region_cache, rcu); - } -} - -static void lm_enable(VirtIODevice *vdev) -{ - BitmapMemoryRegionCaches *old = vdev->caches; - BitmapMemoryRegionCaches *new = NULL; - hwaddr addr, end, size; - int64_t len; - - addr = vdev->lm_base_addr_low | ((hwaddr)(vdev->lm_base_addr_high) << 32); - end = vdev->lm_end_addr_low | ((hwaddr)(vdev->lm_end_addr_high) << 32); - size = end - addr; - if (size <= 0) { - error_report("Invalid lm size."); - return; - } - - new = g_new0(BitmapMemoryRegionCaches, 1); - len = address_space_cache_init(&new->bitmap, vdev->dma_as, addr, size, - true); - if (len < size) { - virtio_error(vdev, "Cannot map bitmap"); - goto err_bitmap; - } - qatomic_rcu_set(&vdev->caches, new); - - if (old) { - call_rcu(old, bitmap_free_region_cache, rcu); - } - - return; - -err_bitmap: - address_space_cache_destroy(&new->bitmap); - g_free(new); -} - -static uint64_t virtio_pci_lm_read(void *opaque, hwaddr addr, - unsigned size) -{ - VirtIOPCIProxy *proxy = opaque; - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - hwaddr offset_end = LM_VRING_STATE_OFFSET + - virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; - uint32_t val; - int qid; - - if (vdev == NULL) { - return UINT64_MAX; - } - switch (addr) { - case LM_LOGGING_CTRL: - val = vdev->lm_logging_ctrl; - break; - case LM_BASE_ADDR_LOW: - val = vdev->lm_base_addr_low; - break; - case LM_BASE_ADDR_HIGH: - val = vdev->lm_base_addr_high; - break; - case LM_END_ADDR_LOW: - val = vdev->lm_end_addr_low; - break; - case LM_END_ADDR_HIGH: - val = vdev->lm_end_addr_high; - break; - default: - if (addr >= LM_VRING_STATE_OFFSET && addr <= offset_end) { - qid = (addr - LM_VRING_STATE_OFFSET) / - virtio_pci_queue_mem_mult(proxy); - val = virtio_queue_get_vring_states(vdev, qid); - } else - val = 0; - - break; - } - - return val; -} - -static void virtio_pci_lm_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - VirtIOPCIProxy *proxy = opaque; - VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - hwaddr offset_end = LM_VRING_STATE_OFFSET + - virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; - int qid; - - if (vdev == NULL) { - return; - } - - switch (addr) { - case LM_LOGGING_CTRL: - vdev->lm_logging_ctrl = val; - switch (val) { - case LM_DISABLE: - lm_disable(vdev); - break; - case LM_ENABLE: - lm_enable(vdev); - break; - default: - virtio_error(vdev, "Unsupport LM_LOGGING_CTRL value: %"PRIx64, - val); - break; - }; - - break; - case LM_BASE_ADDR_LOW: - vdev->lm_base_addr_low = val; - break; - case LM_BASE_ADDR_HIGH: - vdev->lm_base_addr_high = val; - break; - case LM_END_ADDR_LOW: - vdev->lm_end_addr_low = val; - break; - case LM_END_ADDR_HIGH: - vdev->lm_end_addr_high = val; - break; - default: - if (addr >= LM_VRING_STATE_OFFSET && addr <= offset_end) { - qid = (addr - LM_VRING_STATE_OFFSET) / - virtio_pci_queue_mem_mult(proxy); - virtio_queue_set_vring_states(vdev, qid, val); - } else - virtio_error(vdev, "Unsupport addr: %"PRIx64, addr); - break; - } -} - static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, unsigned size) { @@ -1972,15 +1823,6 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy, }, .endianness = DEVICE_LITTLE_ENDIAN, }; - static const MemoryRegionOps lm_ops = { - .read = virtio_pci_lm_read, - .write = virtio_pci_lm_write, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, - }; g_autoptr(GString) name = g_string_new(NULL); g_string_printf(name, "virtio-pci-common-%s", vdev_name); @@ -2017,14 +1859,6 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy, proxy, name->str, proxy->notify_pio.size); - if (proxy->flags & VIRTIO_PCI_FLAG_VDPA) { - g_string_printf(name, "virtio-pci-lm-%s", vdev_name); - memory_region_init_io(&proxy->lm.mr, OBJECT(proxy), - &lm_ops, - proxy, - name->str, - proxy->lm.size); - } } static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, @@ -2187,10 +2021,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) virtio_pci_modern_mem_region_map(proxy, &proxy->isr, &cap); virtio_pci_modern_mem_region_map(proxy, &proxy->device, &cap); virtio_pci_modern_mem_region_map(proxy, &proxy->notify, ¬ify.cap); - if (proxy->flags & VIRTIO_PCI_FLAG_VDPA) { - memory_region_add_subregion(&proxy->modern_bar, - proxy->lm.offset, &proxy->lm.mr); - } if (modern_pio) { memory_region_init(&proxy->io_bar, OBJECT(proxy), @@ -2260,9 +2090,6 @@ static void virtio_pci_device_unplugged(DeviceState *d) virtio_pci_modern_mem_region_unmap(proxy, &proxy->isr); virtio_pci_modern_mem_region_unmap(proxy, &proxy->device); virtio_pci_modern_mem_region_unmap(proxy, &proxy->notify); - if (proxy->flags & VIRTIO_PCI_FLAG_VDPA) { - memory_region_del_subregion(&proxy->modern_bar, &proxy->lm.mr); - } if (modern_pio) { virtio_pci_modern_io_region_unmap(proxy, &proxy->notify_pio); } @@ -2317,17 +2144,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) proxy->notify_pio.type = VIRTIO_PCI_CAP_NOTIFY_CFG; /* subclasses can enforce modern, so do this unconditionally */ - if (!(proxy->flags & VIRTIO_PCI_FLAG_VDPA)) { - memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", - /* PCI BAR regions must be powers of 2 */ - pow2ceil(proxy->notify.offset + proxy->notify.size)); - } else { - proxy->lm.offset = proxy->notify.offset + proxy->notify.size; - proxy->lm.size = 0x20 + VIRTIO_QUEUE_MAX * 4; - memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", - /* PCI BAR regions must be powers of 2 */ - pow2ceil(proxy->lm.offset + proxy->lm.size)); - } + memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", + /* PCI BAR regions must be powers of 2 */ + pow2ceil(proxy->notify.offset + proxy->notify.size)); if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) { proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; @@ -2482,8 +2301,6 @@ static Property virtio_pci_properties[] = { VIRTIO_PCI_FLAG_INIT_FLR_BIT, true), DEFINE_PROP_BIT("aer", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_AER_BIT, false), - DEFINE_PROP_BIT("vdpa", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_VDPA_BIT, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index fb6b4ccd83..c5bedca848 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -957,12 +957,20 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count) return; } + /* + * For indirect element's 'ndescs' is 1. + * For all other elemment's 'ndescs' is the + * number of descriptors chained by NEXT (as set in virtqueue_packed_pop). + * So When the 'elem' be filled into the descriptor ring, + * The 'idx' of this 'elem' shall be + * the value of 'vq->used_idx' plus the 'ndescs'. + */ + ndescs += vq->used_elems[0].ndescs; for (i = 1; i < count; i++) { - virtqueue_packed_fill_desc(vq, &vq->used_elems[i], i, false); + virtqueue_packed_fill_desc(vq, &vq->used_elems[i], ndescs, false); ndescs += vq->used_elems[i].ndescs; } virtqueue_packed_fill_desc(vq, &vq->used_elems[0], 0, true); - ndescs += vq->used_elems[0].ndescs; vq->inuse -= ndescs; vq->used_idx += ndescs; @@ -3368,18 +3376,6 @@ static uint16_t virtio_queue_split_get_last_avail_idx(VirtIODevice *vdev, return vdev->vq[n].last_avail_idx; } -static uint32_t virtio_queue_split_get_vring_states(VirtIODevice *vdev, - int n) -{ - struct VirtQueue *vq = &vdev->vq[n]; - uint16_t avail, used; - - avail = vq->last_avail_idx; - used = vq->used_idx; - - return avail | (uint32_t)used << 16; -} - unsigned int virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n) { if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) { @@ -3389,33 +3385,6 @@ unsigned int virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n) } } -unsigned int virtio_queue_get_vring_states(VirtIODevice *vdev, int n) -{ - if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) { - return -1; - } else { - return virtio_queue_split_get_vring_states(vdev, n); - } -} - -static void virtio_queue_split_set_vring_states(VirtIODevice *vdev, - int n, uint32_t idx) -{ - struct VirtQueue *vq = &vdev->vq[n]; - vq->last_avail_idx = (uint16_t)(idx & 0xffff); - vq->shadow_avail_idx = (uint16_t)(idx & 0xffff); - vq->used_idx = (uint16_t)(idx >> 16); -} - -void virtio_queue_set_vring_states(VirtIODevice *vdev, int n, uint32_t idx) -{ - if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) { - return; - } else { - virtio_queue_split_set_vring_states(vdev, n, idx); - } -} - static void virtio_queue_packed_set_last_avail_idx(VirtIODevice *vdev, int n, unsigned int idx) { diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h index 3d79181364..8dafedb276 100644 --- a/include/hw/audio/virtio-snd.h +++ b/include/hw/audio/virtio-snd.h @@ -151,7 +151,6 @@ struct VirtIOSoundPCMStream { QemuMutex queue_mutex; bool active; QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue; - QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) invalid; }; /* @@ -223,6 +222,21 @@ struct VirtIOSound { QemuMutex cmdq_mutex; QTAILQ_HEAD(, virtio_snd_ctrl_command) cmdq; bool processing_cmdq; + /* + * Convenience queue to keep track of invalid tx/rx queue messages inside + * the tx/rx callbacks. + * + * In the callbacks as a first step we are emptying the virtqueue to handle + * each message and we cannot add an invalid message back to the queue: we + * would re-process it in subsequent loop iterations. + * + * Instead, we add them to this queue and after finishing examining every + * virtqueue element, we inform the guest for each invalid message. + * + * This queue must be empty at all times except for inside the tx/rx + * callbacks. + */ + QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) invalid; }; struct virtio_snd_ctrl_command { diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index 4d57a9c751..59d88018c1 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -43,7 +43,6 @@ enum { VIRTIO_PCI_FLAG_INIT_FLR_BIT, VIRTIO_PCI_FLAG_AER_BIT, VIRTIO_PCI_FLAG_ATS_PAGE_ALIGNED_BIT, - VIRTIO_PCI_FLAG_VDPA_BIT, }; /* Need to activate work-arounds for buggy guests at vmstate load. */ @@ -90,9 +89,6 @@ enum { #define VIRTIO_PCI_FLAG_ATS_PAGE_ALIGNED \ (1 << VIRTIO_PCI_FLAG_ATS_PAGE_ALIGNED_BIT) -/* VDPA supported flags */ -#define VIRTIO_PCI_FLAG_VDPA (1 << VIRTIO_PCI_FLAG_VDPA_BIT) - typedef struct { MSIMessage msg; int virq; @@ -144,7 +140,6 @@ struct VirtIOPCIProxy { }; VirtIOPCIRegion regs[5]; }; - VirtIOPCIRegion lm; MemoryRegion modern_bar; MemoryRegion io_bar; uint32_t legacy_io_bar_idx; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b3c74a1bca..c8f72850bc 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -35,9 +35,6 @@ (0x1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \ (0x1ULL << VIRTIO_F_ANY_LAYOUT)) -#define LM_DISABLE 0x00 -#define LM_ENABLE 0x01 - struct VirtQueue; static inline hwaddr vring_align(hwaddr addr, @@ -98,11 +95,6 @@ enum virtio_device_endian { VIRTIO_DEVICE_ENDIAN_BIG, }; -typedef struct BitmapMemoryRegionCaches { - struct rcu_head rcu; - MemoryRegionCache bitmap; -} BitmapMemoryRegionCaches; - /** * struct VirtIODevice - common VirtIO structure * @name: name of the device @@ -136,14 +128,6 @@ struct VirtIODevice uint32_t generation; int nvectors; VirtQueue *vq; - uint8_t lm_logging_ctrl; - uint32_t lm_base_addr_low; - uint32_t lm_base_addr_high; - uint32_t lm_end_addr_low; - uint32_t lm_end_addr_high; - - BitmapMemoryRegionCaches *caches; - MemoryListener listener; uint16_t device_id; /* @vm_running: current VM running state via virtio_vmstate_change() */ @@ -395,11 +379,8 @@ hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); unsigned int virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); -unsigned int virtio_queue_get_vring_states(VirtIODevice *vdev, int n); void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, unsigned int idx); -void virtio_queue_set_vring_states(VirtIODevice *vdev, int n, - unsigned int idx); void virtio_queue_restore_last_avail_idx(VirtIODevice *vdev, int n); void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n); void virtio_queue_update_used_idx(VirtIODevice *vdev, int n); diff --git a/include/standard-headers/linux/virtio_pci.h b/include/standard-headers/linux/virtio_pci.h index 86733278ba..3e2bc2c97e 100644 --- a/include/standard-headers/linux/virtio_pci.h +++ b/include/standard-headers/linux/virtio_pci.h @@ -221,13 +221,6 @@ struct virtio_pci_cfg_cap { #define VIRTIO_PCI_COMMON_ADM_Q_IDX 60 #define VIRTIO_PCI_COMMON_ADM_Q_NUM 62 -#define LM_LOGGING_CTRL 0 -#define LM_BASE_ADDR_LOW 4 -#define LM_BASE_ADDR_HIGH 8 -#define LM_END_ADDR_LOW 12 -#define LM_END_ADDR_HIGH 16 -#define LM_VRING_STATE_OFFSET 0x20 - #endif /* VIRTIO_PCI_NO_MODERN */ /* Admin command status. */ diff --git a/migration/savevm.c b/migration/savevm.c index 388d7af7cd..e7c1215671 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -2342,6 +2342,27 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) QEMUFile *packf = qemu_file_new_input(QIO_CHANNEL(bioc)); + /* + * Before loading the guest states, ensure that the preempt channel has + * been ready to use, as some of the states (e.g. via virtio_load) might + * trigger page faults that will be handled through the preempt channel. + * So yield to the main thread in the case that the channel create event + * hasn't been dispatched. + * + * TODO: if we can move migration loadvm out of main thread, then we + * won't block main thread from polling the accept() fds. We can drop + * this as a whole when that is done. + */ + do { + if (!migrate_postcopy_preempt() || !qemu_in_coroutine() || + mis->postcopy_qemufile_dst) { + break; + } + + aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); + qemu_coroutine_yield(); + } while (1); + ret = qemu_loadvm_state_main(packf, mis); trace_loadvm_handle_cmd_packaged_main(ret); qemu_fclose(packf); diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index c1243891c3..840177d19f 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -891,7 +891,7 @@ static DeviceState *find_device_state(const char *id, Error **errp) dev = (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE); if (!dev) { - error_setg(errp, "%s is not a hotpluggable device", id); + error_setg(errp, "%s is not a device", id); return NULL; } diff --git a/target/arm/helper.c b/target/arm/helper.c index 3f3a5b55d4..a620481d7c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -3452,7 +3452,8 @@ static CPAccessResult gt_cntpoff_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { - if (arm_current_el(env) == 2 && !(env->cp15.scr_el3 & SCR_ECVEN)) { + if (arm_current_el(env) == 2 && arm_feature(env, ARM_FEATURE_EL3) && + !(env->cp15.scr_el3 & SCR_ECVEN)) { return CP_ACCESS_TRAP_EL3; } return CP_ACCESS_OK; @@ -3878,6 +3879,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, ARMMMUIdx mmu_idx; uint64_t hcr_el2 = arm_hcr_el2_eff(env); bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE); + bool for_el3 = false; + ARMSecuritySpace ss; switch (ri->opc2 & 6) { case 0: @@ -3895,6 +3898,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, break; case 6: /* AT S1E3R, AT S1E3W */ mmu_idx = ARMMMUIdx_E3; + for_el3 = true; break; default: g_assert_not_reached(); @@ -3913,8 +3917,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, g_assert_not_reached(); } - env->cp15.par_el[1] = do_ats_write(env, value, access_type, - mmu_idx, arm_security_space(env)); + ss = for_el3 ? arm_security_space(env) : arm_security_space_below_el3(env); + env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx, ss); #else /* Handled by hardware accelerator. */ g_assert_not_reached(); |