[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC v5 12/86] memory: add ioeventfd support
From: |
Avi Kivity |
Subject: |
[Qemu-devel] [RFC v5 12/86] memory: add ioeventfd support |
Date: |
Wed, 20 Jul 2011 19:49:22 +0300 |
As with the rest of the memory API, the caller associates an eventfd
with an address, and the memory API takes care of registering or
unregistering when the address is made visible or invisible to the
guest.
Signed-off-by: Avi Kivity <address@hidden>
---
memory.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
memory.h | 20 ++++++
2 files changed, 238 insertions(+), 0 deletions(-)
diff --git a/memory.c b/memory.c
index e4446a0..cc5a0a4 100644
--- a/memory.c
+++ b/memory.c
@@ -15,6 +15,7 @@
#include "exec-memory.h"
#include "ioport.h"
#include "bitops.h"
+#include "kvm.h"
#include <assert.h>
typedef struct AddrRange AddrRange;
@@ -64,6 +65,38 @@ struct CoalescedMemoryRange {
QTAILQ_ENTRY(CoalescedMemoryRange) link;
};
+struct MemoryRegionIoeventfd {
+ AddrRange addr;
+ bool match_data;
+ uint64_t data;
+ int fd;
+};
+
+static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a,
+ MemoryRegionIoeventfd b)
+{
+ if (a.addr.start < b.addr.start) return true;
+ if (a.addr.start > b.addr.start) return false;
+ if (a.addr.size < b.addr.size) return true;
+ if (a.addr.size > b.addr.size) return false;
+ if (a.match_data < b.match_data) return true;
+ if (a.match_data > b.match_data) return false;
+ if (a.match_data) {
+ if (a.data < b.data) return true;
+ if (a.data > b.data) return false;
+ }
+ if (a.fd < b.fd) return true;
+ if (a.fd > b.fd) return false;
+ return false;
+}
+
+static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
+ MemoryRegionIoeventfd b)
+{
+ return !memory_region_ioeventfd_before(a, b)
+ && !memory_region_ioeventfd_before(b, a);
+}
+
typedef struct FlatRange FlatRange;
typedef struct FlatView FlatView;
@@ -92,6 +125,8 @@ struct AddressSpace {
const AddressSpaceOps *ops;
MemoryRegion *root;
FlatView current_map;
+ int ioeventfd_nb;
+ MemoryRegionIoeventfd *ioeventfds;
};
struct AddressSpaceOps {
@@ -99,6 +134,8 @@ struct AddressSpaceOps {
void (*range_del)(AddressSpace *as, FlatRange *fr);
void (*log_start)(AddressSpace *as, FlatRange *fr);
void (*log_stop)(AddressSpace *as, FlatRange *fr);
+ void (*ioeventfd_add)(AddressSpace *as, MemoryRegionIoeventfd *fd);
+ void (*ioeventfd_del)(AddressSpace *as, MemoryRegionIoeventfd *fd);
};
#define FOR_EACH_FLAT_RANGE(var, view) \
@@ -201,11 +238,37 @@ static void as_memory_log_stop(AddressSpace *as,
FlatRange *fr)
cpu_physical_log_stop(fr->addr.start, fr->addr.size);
}
+static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd
*fd)
+{
+ int r;
+
+ if (!fd->match_data || fd->addr.size != 4) {
+ abort();
+ }
+
+ r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, true);
+ if (r < 0) {
+ abort();
+ }
+}
+
+static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd
*fd)
+{
+ int r;
+
+ r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, false);
+ if (r < 0) {
+ abort();
+ }
+}
+
static const AddressSpaceOps address_space_ops_memory = {
.range_add = as_memory_range_add,
.range_del = as_memory_range_del,
.log_start = as_memory_log_start,
.log_stop = as_memory_log_stop,
+ .ioeventfd_add = as_memory_ioeventfd_add,
+ .ioeventfd_del = as_memory_ioeventfd_del,
};
static AddressSpace address_space_memory = {
@@ -281,9 +344,35 @@ static void as_io_range_del(AddressSpace *as, FlatRange
*fr)
isa_unassign_ioport(fr->addr.start, fr->addr.size);
}
+static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
+{
+ int r;
+
+ if (!fd->match_data || fd->addr.size != 2) {
+ abort();
+ }
+
+ r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, true);
+ if (r < 0) {
+ abort();
+ }
+}
+
+static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
+{
+ int r;
+
+ r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, false);
+ if (r < 0) {
+ abort();
+ }
+}
+
static const AddressSpaceOps address_space_ops_io = {
.range_add = as_io_range_add,
.range_del = as_io_range_del,
+ .ioeventfd_add = as_io_ioeventfd_add,
+ .ioeventfd_del = as_io_ioeventfd_del,
};
static AddressSpace address_space_io = {
@@ -382,6 +471,69 @@ static FlatView generate_memory_topology(MemoryRegion *mr)
return view;
}
+static void address_space_add_del_ioeventfds(AddressSpace *as,
+ MemoryRegionIoeventfd *fds_new,
+ unsigned fds_new_nb,
+ MemoryRegionIoeventfd *fds_old,
+ unsigned fds_old_nb)
+{
+ unsigned iold, inew;
+
+ /* Generate a symmetric difference of the old and new fd sets, adding
+ * and deleting as necessary.
+ */
+
+ iold = inew = 0;
+ while (iold < fds_old_nb || inew < fds_new_nb) {
+ if (iold < fds_old_nb
+ && (inew == fds_new_nb
+ || memory_region_ioeventfd_before(fds_old[iold],
+ fds_new[inew]))) {
+ as->ops->ioeventfd_del(as, &fds_old[iold]);
+ ++iold;
+ } else if (inew < fds_new_nb
+ && (iold == fds_old_nb
+ || memory_region_ioeventfd_before(fds_new[inew],
+ fds_old[iold]))) {
+ as->ops->ioeventfd_add(as, &fds_new[inew]);
+ ++inew;
+ } else {
+ ++iold;
+ ++inew;
+ }
+ }
+}
+
+static void address_space_update_ioeventfds(AddressSpace *as)
+{
+ FlatRange *fr;
+ unsigned ioeventfd_nb = 0;
+ MemoryRegionIoeventfd *ioeventfds = NULL;
+ AddrRange tmp;
+ unsigned i;
+
+ FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
+ for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
+ tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
+ fr->addr.start - fr->offset_in_region);
+ if (addrrange_intersects(fr->addr, tmp)) {
+ ++ioeventfd_nb;
+ ioeventfds = qemu_realloc(ioeventfds,
+ ioeventfd_nb * sizeof(*ioeventfds));
+ ioeventfds[ioeventfd_nb-1] = fr->mr->ioeventfds[i];
+ ioeventfds[ioeventfd_nb-1].addr = tmp;
+ }
+ }
+ }
+
+ address_space_add_del_ioeventfds(as, ioeventfds, ioeventfd_nb,
+ as->ioeventfds, as->ioeventfd_nb);
+
+ qemu_free(as->ioeventfds);
+ as->ioeventfds = ioeventfds;
+ as->ioeventfd_nb = ioeventfd_nb;
+}
+
static void address_space_update_topology(AddressSpace *as)
{
FlatView old_view = as->current_map;
@@ -434,6 +586,7 @@ static void address_space_update_topology(AddressSpace *as)
}
as->current_map = new_view;
flatview_destroy(&old_view);
+ address_space_update_ioeventfds(as);
}
static void memory_region_update_topology(void)
@@ -464,6 +617,8 @@ void memory_region_init(MemoryRegion *mr,
QTAILQ_INIT(&mr->coalesced);
mr->name = qemu_strdup(name);
mr->dirty_log_mask = 0;
+ mr->ioeventfd_nb = 0;
+ mr->ioeventfds = NULL;
}
static bool memory_region_access_valid(MemoryRegion *mr,
@@ -675,6 +830,7 @@ void memory_region_destroy(MemoryRegion *mr)
assert(QTAILQ_EMPTY(&mr->subregions));
memory_region_clear_coalescing(mr);
qemu_free((char *)mr->name);
+ qemu_free(mr->ioeventfds);
}
target_phys_addr_t memory_region_size(MemoryRegion *mr)
@@ -798,6 +954,68 @@ void memory_region_clear_coalescing(MemoryRegion *mr)
memory_region_update_coalesced_range(mr);
}
+void memory_region_add_eventfd(MemoryRegion *mr,
+ target_phys_addr_t addr,
+ unsigned size,
+ bool match_data,
+ uint64_t data,
+ int fd)
+{
+ MemoryRegionIoeventfd mrfd = {
+ .addr.start = addr,
+ .addr.size = size,
+ .match_data = match_data,
+ .data = data,
+ .fd = fd,
+ };
+ unsigned i;
+
+ for (i = 0; i < mr->ioeventfd_nb; ++i) {
+ if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
+ break;
+ }
+ }
+ ++mr->ioeventfd_nb;
+ mr->ioeventfds = qemu_realloc(mr->ioeventfds,
+ sizeof(*mr->ioeventfds) * mr->ioeventfd_nb);
+ memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
+ sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
+ mr->ioeventfds[i] = mrfd;
+ memory_region_update_topology();
+}
+
+void memory_region_del_eventfd(MemoryRegion *mr,
+ target_phys_addr_t addr,
+ unsigned size,
+ bool match_data,
+ uint64_t data,
+ int fd)
+{
+ MemoryRegionIoeventfd mrfd = {
+ .addr.start = addr,
+ .addr.size = size,
+ .match_data = match_data,
+ .data = data,
+ .fd = fd,
+ };
+ unsigned i;
+
+ for (i = 0; i < mr->ioeventfd_nb; ++i) {
+ if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
+ break;
+ }
+ }
+ if (i == mr->ioeventfd_nb) {
+ abort();
+ }
+ memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1],
+ sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb - (i+1)));
+ --mr->ioeventfd_nb;
+ mr->ioeventfds = qemu_realloc(mr->ioeventfds,
+ sizeof(*mr->ioeventfds)*mr->ioeventfd_nb +
1);
+ memory_region_update_topology();
+}
+
static void memory_region_add_subregion_common(MemoryRegion *mr,
target_phys_addr_t offset,
MemoryRegion *subregion)
diff --git a/memory.h b/memory.h
index 4624946..e4c0ad1 100644
--- a/memory.h
+++ b/memory.h
@@ -85,6 +85,7 @@ struct MemoryRegionOps {
};
typedef struct CoalescedMemoryRange CoalescedMemoryRange;
+typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
struct MemoryRegion {
/* All fields are private - violators will be prosecuted */
@@ -107,6 +108,8 @@ struct MemoryRegion {
QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
const char *name;
uint8_t dirty_log_mask;
+ unsigned ioeventfd_nb;
+ MemoryRegionIoeventfd *ioeventfds;
};
struct MemoryRegionPortio {
@@ -208,6 +211,23 @@ void memory_region_add_coalescing(MemoryRegion *mr,
/* Disable MMIO coalescing for the region. */
void memory_region_clear_coalescing(MemoryRegion *mr);
+
+/* Request an eventfd to be triggered when a word is written to a location */
+void memory_region_add_eventfd(MemoryRegion *mr,
+ target_phys_addr_t addr,
+ unsigned size,
+ bool match_data,
+ uint64_t data,
+ int fd);
+
+/* Cancel an existing eventfd */
+void memory_region_del_eventfd(MemoryRegion *mr,
+ target_phys_addr_t addr,
+ unsigned size,
+ bool match_data,
+ uint64_t data,
+ int fd);
+
/* Add a sub-region at @offset. The sub-region may not overlap with other
* subregions (except for those explicitly marked as overlapping)
*/
--
1.7.5.3
- [Qemu-devel] [RFC v5 04/86] memory: merge adjacent segments of a single memory region, (continued)
- [Qemu-devel] [RFC v5 04/86] memory: merge adjacent segments of a single memory region, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 13/86] memory: separate building the final memory map into two steps, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 74/86] ppc405_uc: convert to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 16/86] pc: grab system_memory, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 69/86] gt64xxx.c: convert to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 34/86] pci: allow I/O BARs to be registered with pci_register_bar_region(), Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 18/86] pc: move global memory map out of pc_init1() and into its callers, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 83/86] isa: add isa_address_space(), Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 26/86] cirrus: simplify mmio BAR access functions, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 25/86] vga: convert vga and its derivatives to the memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 12/86] memory: add ioeventfd support,
Avi Kivity <=
- [Qemu-devel] [RFC v5 19/86] pci: pass address space to pci bus when created, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 52/86] ehci: convert to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 68/86] armv7m: convert to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 54/86] xen-platform: convert to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 22/86] usb-ohci: convert to MemoryRegion, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 35/86] rtl8139: convert to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 57/86] pci: convert pci rom to memory API, Avi Kivity, 2011/07/20
- [Qemu-devel] [RFC v5 64/86] apic: convert to memory API, Avi Kivity, 2011/07/20