From mboxrd@z Thu Jan 1 00:00:00 1970 From: Blue Swirl Subject: Re: [Qemu-devel] [RFC v5 12/86] memory: add ioeventfd support Date: Thu, 21 Jul 2011 22:55:26 +0300 Message-ID: References: <1311180636-17012-1-git-send-email-avi@redhat.com> <1311180636-17012-13-git-send-email-avi@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org To: Avi Kivity Return-path: Received: from mail-qw0-f46.google.com ([209.85.216.46]:49358 "EHLO mail-qw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751471Ab1GUTzr convert rfc822-to-8bit (ORCPT ); Thu, 21 Jul 2011 15:55:47 -0400 Received: by qwk3 with SMTP id 3so808519qwk.19 for ; Thu, 21 Jul 2011 12:55:46 -0700 (PDT) In-Reply-To: <1311180636-17012-13-git-send-email-avi@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: On Wed, Jul 20, 2011 at 7:49 PM, Avi Kivity wrote: > 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 > --- > =C2=A0memory.c | =C2=A0218 ++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++ > =C2=A0memory.h | =C2=A0 20 ++++++ > =C2=A02 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 @@ > =C2=A0#include "exec-memory.h" > =C2=A0#include "ioport.h" > =C2=A0#include "bitops.h" > +#include "kvm.h" > =C2=A0#include > > =C2=A0typedef struct AddrRange AddrRange; > @@ -64,6 +65,38 @@ struct CoalescedMemoryRange { > =C2=A0 =C2=A0 QTAILQ_ENTRY(CoalescedMemoryRange) link; > =C2=A0}; > > +struct MemoryRegionIoeventfd { > + =C2=A0 =C2=A0AddrRange addr; > + =C2=A0 =C2=A0bool match_data; > + =C2=A0 =C2=A0uint64_t data; > + =C2=A0 =C2=A0int fd; > +}; > + > +static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 MemoryRegionIoeventfd b) > +{ > + =C2=A0 =C2=A0if (a.addr.start < b.addr.start) return true; > + =C2=A0 =C2=A0if (a.addr.start > b.addr.start) return false; > + =C2=A0 =C2=A0if (a.addr.size < b.addr.size) return true; > + =C2=A0 =C2=A0if (a.addr.size > b.addr.size) return false; > + =C2=A0 =C2=A0if (a.match_data < b.match_data) return true; > + =C2=A0 =C2=A0if (a.match_data > b.match_data) return false; > + =C2=A0 =C2=A0if (a.match_data) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (a.data < b.data) return true; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (a.data > b.data) return false; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (a.fd < b.fd) return true; > + =C2=A0 =C2=A0if (a.fd > b.fd) return false; NACK for CO.. Wait, is this another trap? > + =C2=A0 =C2=A0return false; > +} > + > +static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0MemoryRegionIoeventfd b) > +{ > + =C2=A0 =C2=A0return !memory_region_ioeventfd_before(a, b) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0&& !memory_region_ioeventfd_before(b, a)= ; > +} > + > =C2=A0typedef struct FlatRange FlatRange; > =C2=A0typedef struct FlatView FlatView; > > @@ -92,6 +125,8 @@ struct AddressSpace { > =C2=A0 =C2=A0 const AddressSpaceOps *ops; > =C2=A0 =C2=A0 MemoryRegion *root; > =C2=A0 =C2=A0 FlatView current_map; > + =C2=A0 =C2=A0int ioeventfd_nb; > + =C2=A0 =C2=A0MemoryRegionIoeventfd *ioeventfds; > =C2=A0}; > > =C2=A0struct AddressSpaceOps { > @@ -99,6 +134,8 @@ struct AddressSpaceOps { > =C2=A0 =C2=A0 void (*range_del)(AddressSpace *as, FlatRange *fr); > =C2=A0 =C2=A0 void (*log_start)(AddressSpace *as, FlatRange *fr); > =C2=A0 =C2=A0 void (*log_stop)(AddressSpace *as, FlatRange *fr); > + =C2=A0 =C2=A0void (*ioeventfd_add)(AddressSpace *as, MemoryRegionIo= eventfd *fd); > + =C2=A0 =C2=A0void (*ioeventfd_del)(AddressSpace *as, MemoryRegionIo= eventfd *fd); > =C2=A0}; > > =C2=A0#define FOR_EACH_FLAT_RANGE(var, view) =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0\ > @@ -201,11 +238,37 @@ static void as_memory_log_stop(AddressSpace *as= , FlatRange *fr) > =C2=A0 =C2=A0 cpu_physical_log_stop(fr->addr.start, fr->addr.size); > =C2=A0} > > +static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIo= eventfd *fd) > +{ > + =C2=A0 =C2=A0int r; > + > + =C2=A0 =C2=A0if (!fd->match_data || fd->addr.size !=3D 4) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0r =3D kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.sta= rt, fd->data, true); > + =C2=A0 =C2=A0if (r < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > +} > + > +static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIo= eventfd *fd) > +{ > + =C2=A0 =C2=A0int r; > + > + =C2=A0 =C2=A0r =3D kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.sta= rt, fd->data, false); > + =C2=A0 =C2=A0if (r < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > +} > + > =C2=A0static const AddressSpaceOps address_space_ops_memory =3D { > =C2=A0 =C2=A0 .range_add =3D as_memory_range_add, > =C2=A0 =C2=A0 .range_del =3D as_memory_range_del, > =C2=A0 =C2=A0 .log_start =3D as_memory_log_start, > =C2=A0 =C2=A0 .log_stop =3D as_memory_log_stop, > + =C2=A0 =C2=A0.ioeventfd_add =3D as_memory_ioeventfd_add, > + =C2=A0 =C2=A0.ioeventfd_del =3D as_memory_ioeventfd_del, > =C2=A0}; > > =C2=A0static AddressSpace address_space_memory =3D { > @@ -281,9 +344,35 @@ static void as_io_range_del(AddressSpace *as, Fl= atRange *fr) > =C2=A0 =C2=A0 isa_unassign_ioport(fr->addr.start, fr->addr.size); > =C2=A0} > > +static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeven= tfd *fd) > +{ > + =C2=A0 =C2=A0int r; > + > + =C2=A0 =C2=A0if (!fd->match_data || fd->addr.size !=3D 2) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0r =3D kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.star= t, fd->data, true); > + =C2=A0 =C2=A0if (r < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > +} > + > +static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeven= tfd *fd) > +{ > + =C2=A0 =C2=A0int r; > + > + =C2=A0 =C2=A0r =3D kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.star= t, fd->data, false); > + =C2=A0 =C2=A0if (r < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > +} > + > =C2=A0static const AddressSpaceOps address_space_ops_io =3D { > =C2=A0 =C2=A0 .range_add =3D as_io_range_add, > =C2=A0 =C2=A0 .range_del =3D as_io_range_del, > + =C2=A0 =C2=A0.ioeventfd_add =3D as_io_ioeventfd_add, > + =C2=A0 =C2=A0.ioeventfd_del =3D as_io_ioeventfd_del, > =C2=A0}; > > =C2=A0static AddressSpace address_space_io =3D { > @@ -382,6 +471,69 @@ static FlatView generate_memory_topology(MemoryR= egion *mr) > =C2=A0 =C2=A0 return view; > =C2=A0} > > +static void address_space_add_del_ioeventfds(AddressSpace *as, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 MemoryRegionIoeventfd *fds_new, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 unsigned fds_new_nb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 MemoryRegionIoeventfd *fds_old, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 unsigned fds_old_nb) > +{ > + =C2=A0 =C2=A0unsigned iold, inew; > + > + =C2=A0 =C2=A0/* Generate a symmetric difference of the old and new = fd sets, adding > + =C2=A0 =C2=A0 * and deleting as necessary. > + =C2=A0 =C2=A0 */ > + > + =C2=A0 =C2=A0iold =3D inew =3D 0; > + =C2=A0 =C2=A0while (iold < fds_old_nb || inew < fds_new_nb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (iold < fds_old_nb > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&& (inew =3D=3D fds_new_nb > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|| memory_re= gion_ioeventfd_before(fds_old[iold], > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fds_new[inew]))) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0as->ops->ioeventfd_del(as,= &fds_old[iold]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0++iold; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} else if (inew < fds_new_nb > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 && (= iold =3D=3D fds_old_nb > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 || memory_region_ioeventfd_before(fds_new[inew], > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 fds_old[iold]))= ) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0as->ops->ioeventfd_add(as,= &fds_new[inew]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0++inew; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0++iold; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0++inew; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +} > + > +static void address_space_update_ioeventfds(AddressSpace *as) > +{ > + =C2=A0 =C2=A0FlatRange *fr; > + =C2=A0 =C2=A0unsigned ioeventfd_nb =3D 0; > + =C2=A0 =C2=A0MemoryRegionIoeventfd *ioeventfds =3D NULL; > + =C2=A0 =C2=A0AddrRange tmp; > + =C2=A0 =C2=A0unsigned i; > + > + =C2=A0 =C2=A0FOR_EACH_FLAT_RANGE(fr, &as->current_map) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < fr->mr->ioeventfd_nb; = ++i) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tmp =3D addrrange_shift(fr= ->mr->ioeventfds[i].addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fr->addr.start - fr->o= ffset_in_region); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (addrrange_intersects(f= r->addr, tmp)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0++ioeventfd_= nb; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ioeventfds =3D= qemu_realloc(ioeventfds, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0ioeventfd_nb * sizeof(*ioeventfds)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ioeventfds[i= oeventfd_nb-1] =3D fr->mr->ioeventfds[i]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ioeventfds[i= oeventfd_nb-1].addr =3D tmp; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0address_space_add_del_ioeventfds(as, ioeventfds, ioeve= ntfd_nb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 as->ioeventfds= , as->ioeventfd_nb); > + > + =C2=A0 =C2=A0qemu_free(as->ioeventfds); > + =C2=A0 =C2=A0as->ioeventfds =3D ioeventfds; > + =C2=A0 =C2=A0as->ioeventfd_nb =3D ioeventfd_nb; > +} > + > =C2=A0static void address_space_update_topology(AddressSpace *as) > =C2=A0{ > =C2=A0 =C2=A0 FlatView old_view =3D as->current_map; > @@ -434,6 +586,7 @@ static void address_space_update_topology(Address= Space *as) > =C2=A0 =C2=A0 } > =C2=A0 =C2=A0 as->current_map =3D new_view; > =C2=A0 =C2=A0 flatview_destroy(&old_view); > + =C2=A0 =C2=A0address_space_update_ioeventfds(as); > =C2=A0} > > =C2=A0static void memory_region_update_topology(void) > @@ -464,6 +617,8 @@ void memory_region_init(MemoryRegion *mr, > =C2=A0 =C2=A0 QTAILQ_INIT(&mr->coalesced); > =C2=A0 =C2=A0 mr->name =3D qemu_strdup(name); > =C2=A0 =C2=A0 mr->dirty_log_mask =3D 0; > + =C2=A0 =C2=A0mr->ioeventfd_nb =3D 0; > + =C2=A0 =C2=A0mr->ioeventfds =3D NULL; > =C2=A0} > > =C2=A0static bool memory_region_access_valid(MemoryRegion *mr, > @@ -675,6 +830,7 @@ void memory_region_destroy(MemoryRegion *mr) > =C2=A0 =C2=A0 assert(QTAILQ_EMPTY(&mr->subregions)); > =C2=A0 =C2=A0 memory_region_clear_coalescing(mr); > =C2=A0 =C2=A0 qemu_free((char *)mr->name); > + =C2=A0 =C2=A0qemu_free(mr->ioeventfds); > =C2=A0} > > =C2=A0target_phys_addr_t memory_region_size(MemoryRegion *mr) > @@ -798,6 +954,68 @@ void memory_region_clear_coalescing(MemoryRegion= *mr) > =C2=A0 =C2=A0 memory_region_update_coalesced_range(mr); > =C2=A0} > > +void memory_region_add_eventfd(MemoryRegion *mr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool match_data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int fd) > +{ > + =C2=A0 =C2=A0MemoryRegionIoeventfd mrfd =3D { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.addr.start =3D addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.addr.size =3D size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.match_data =3D match_data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.data =3D data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.fd =3D fd, > + =C2=A0 =C2=A0}; > + =C2=A0 =C2=A0unsigned i; > + > + =C2=A0 =C2=A0for (i =3D 0; i < mr->ioeventfd_nb; ++i) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (memory_region_ioeventfd_before(mrfd,= mr->ioeventfds[i])) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0++mr->ioeventfd_nb; > + =C2=A0 =C2=A0mr->ioeventfds =3D qemu_realloc(mr->ioeventfds, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sizeof(*mr->ioeventfds= ) * mr->ioeventfd_nb); > + =C2=A0 =C2=A0memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i], > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sizeof(*mr->ioeventfds) * = (mr->ioeventfd_nb-1 - i)); > + =C2=A0 =C2=A0mr->ioeventfds[i] =3D mrfd; > + =C2=A0 =C2=A0memory_region_update_topology(); > +} > + > +void memory_region_del_eventfd(MemoryRegion *mr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool match_data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int fd) > +{ > + =C2=A0 =C2=A0MemoryRegionIoeventfd mrfd =3D { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.addr.start =3D addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.addr.size =3D size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.match_data =3D match_data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.data =3D data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0.fd =3D fd, > + =C2=A0 =C2=A0}; > + =C2=A0 =C2=A0unsigned i; > + > + =C2=A0 =C2=A0for (i =3D 0; i < mr->ioeventfd_nb; ++i) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (memory_region_ioeventfd_equal(mrfd, = mr->ioeventfds[i])) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (i =3D=3D mr->ioeventfd_nb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0abort(); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1], > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sizeof(*mr->ioeventfds) * = (mr->ioeventfd_nb - (i+1))); > + =C2=A0 =C2=A0--mr->ioeventfd_nb; > + =C2=A0 =C2=A0mr->ioeventfds =3D qemu_realloc(mr->ioeventfds, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sizeof(*mr->ioeventfds= )*mr->ioeventfd_nb + 1); > + =C2=A0 =C2=A0memory_region_update_topology(); > +} > + > =C2=A0static void memory_region_add_subregion_common(MemoryRegion *mr= , > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t offset, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0MemoryRegion *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 { > =C2=A0}; > > =C2=A0typedef struct CoalescedMemoryRange CoalescedMemoryRange; > +typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; > > =C2=A0struct MemoryRegion { > =C2=A0 =C2=A0 /* All fields are private - violators will be prosecute= d */ > @@ -107,6 +108,8 @@ struct MemoryRegion { > =C2=A0 =C2=A0 QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coa= lesced; > =C2=A0 =C2=A0 const char *name; > =C2=A0 =C2=A0 uint8_t dirty_log_mask; > + =C2=A0 =C2=A0unsigned ioeventfd_nb; > + =C2=A0 =C2=A0MemoryRegionIoeventfd *ioeventfds; > =C2=A0}; > > =C2=A0struct MemoryRegionPortio { > @@ -208,6 +211,23 @@ void memory_region_add_coalescing(MemoryRegion *= mr, > =C2=A0/* Disable MMIO coalescing for the region. */ > =C2=A0void memory_region_clear_coalescing(MemoryRegion *mr); > > + > +/* Request an eventfd to be triggered when a word is written to a lo= cation */ > +void memory_region_add_eventfd(MemoryRegion *mr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool match_data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int fd); > + > +/* Cancel an existing eventfd =C2=A0*/ > +void memory_region_del_eventfd(MemoryRegion *mr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool match_data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int fd); > + > =C2=A0/* Add a sub-region at @offset. =C2=A0The sub-region may not ov= erlap with other > =C2=A0* subregions (except for those explicitly marked as overlapping= ) > =C2=A0*/ > -- > 1.7.5.3 > > >