mirror of https://gitee.com/openkylin/qemu.git
memory: emulate ioeventfd
The ioeventfd mechanism is used by vhost, dataplane, and virtio-pci to turn guest MMIO/PIO writes into eventfd file descriptor events. This allows arbitrary threads to be notified when the guest writes to a specific MMIO/PIO address. qtest and TCG do not support ioeventfd because memory writes are not checked against registered ioeventfds in QEMU. This patch implements this in memory_region_dispatch_write() so qtest can use ioeventfd. Also this patch fixes vhost aborting on some misconfigured old kernels like 3.18.0 on ARM. It is possible to explicitly enable CONFIG_EVENTFD in expert settings, while MMIO binding support in KVM will still be missing. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Pavel Fedin <p.fedin@samsung.com> Message-Id: <006e01d12377$0b9c2d40$22d487c0$@samsung.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
bc92e4e97e
commit
8c56c1a592
|
@ -1628,8 +1628,10 @@ static int kvm_init(MachineState *ms)
|
|||
|
||||
kvm_state = s;
|
||||
|
||||
s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add;
|
||||
s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del;
|
||||
if (kvm_eventfds_allowed) {
|
||||
s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add;
|
||||
s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del;
|
||||
}
|
||||
s->memory_listener.listener.coalesced_mmio_add = kvm_coalesce_mmio_region;
|
||||
s->memory_listener.listener.coalesced_mmio_del = kvm_uncoalesce_mmio_region;
|
||||
|
||||
|
|
42
memory.c
42
memory.c
|
@ -18,12 +18,14 @@
|
|||
#include "exec/ioport.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qom/object.h"
|
||||
#include "trace.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include "exec/memory-internal.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
//#define DEBUG_UNASSIGNED
|
||||
|
@ -1136,6 +1138,32 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
|
|||
return r;
|
||||
}
|
||||
|
||||
/* Return true if an eventfd was signalled */
|
||||
static bool memory_region_dispatch_write_eventfds(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
uint64_t data,
|
||||
unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
MemoryRegionIoeventfd ioeventfd = {
|
||||
.addr = addrrange_make(int128_make64(addr), int128_make64(size)),
|
||||
.data = data,
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < mr->ioeventfd_nb; i++) {
|
||||
ioeventfd.match_data = mr->ioeventfds[i].match_data;
|
||||
ioeventfd.e = mr->ioeventfds[i].e;
|
||||
|
||||
if (memory_region_ioeventfd_equal(ioeventfd, mr->ioeventfds[i])) {
|
||||
event_notifier_set(ioeventfd.e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
uint64_t data,
|
||||
|
@ -1149,6 +1177,11 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
|
|||
|
||||
adjust_endianness(mr, &data, size);
|
||||
|
||||
if ((!kvm_eventfds_enabled()) &&
|
||||
memory_region_dispatch_write_eventfds(mr, addr, data, size, attrs)) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
if (mr->ops->write) {
|
||||
return access_with_adjusted_size(addr, &data, size,
|
||||
mr->ops->impl.min_access_size,
|
||||
|
@ -1667,6 +1700,8 @@ void memory_region_clear_global_locking(MemoryRegion *mr)
|
|||
mr->global_locking = false;
|
||||
}
|
||||
|
||||
static bool userspace_eventfd_warning;
|
||||
|
||||
void memory_region_add_eventfd(MemoryRegion *mr,
|
||||
hwaddr addr,
|
||||
unsigned size,
|
||||
|
@ -1683,6 +1718,13 @@ void memory_region_add_eventfd(MemoryRegion *mr,
|
|||
};
|
||||
unsigned i;
|
||||
|
||||
if (kvm_enabled() && (!(kvm_eventfds_enabled() ||
|
||||
userspace_eventfd_warning))) {
|
||||
userspace_eventfd_warning = true;
|
||||
error_report("Using eventfd without MMIO binding in KVM. "
|
||||
"Suboptimal performance expected");
|
||||
}
|
||||
|
||||
if (size) {
|
||||
adjust_endianness(mr, &mrfd.data, size);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue