From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:37694) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QNTzb-0006C7-04 for qemu-devel@nongnu.org; Fri, 20 May 2011 14:00:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QNTzZ-00066s-Jl for qemu-devel@nongnu.org; Fri, 20 May 2011 14:00:06 -0400 Received: from mail-qw0-f45.google.com ([209.85.216.45]:63337) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QNTzZ-00066P-7y for qemu-devel@nongnu.org; Fri, 20 May 2011 14:00:05 -0400 Received: by qwj8 with SMTP id 8so2318662qwj.4 for ; Fri, 20 May 2011 11:00:04 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <1305814352-15044-2-git-send-email-avi@redhat.com> References: <1305814352-15044-1-git-send-email-avi@redhat.com> <1305814352-15044-2-git-send-email-avi@redhat.com> From: Blue Swirl Date: Fri, 20 May 2011 20:59:44 +0300 Message-ID: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [RFC v1] Add declarations for hierarchical memory region API List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Avi Kivity Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org On Thu, May 19, 2011 at 5:12 PM, Avi Kivity wrote: > The memory API separates the attributes of a memory region (its size, how > reads or writes are handled, dirty logging, and coalescing) from where it > is mapped and whether it is enabled. =C2=A0This allows a device to config= ure > a memory region once, then hand it off to its parent bus to map it accord= ing > to the bus configuration. > > Hierarchical registration also allows a device to compose a region out of > a number of sub-regions with different properties; for example some may b= e > RAM while others may be MMIO. > > Signed-off-by: Avi Kivity > --- > =C2=A0memory.h | =C2=A0142 ++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++ > =C2=A01 files changed, 142 insertions(+), 0 deletions(-) > =C2=A0create mode 100644 memory.h > > diff --git a/memory.h b/memory.h > new file mode 100644 > index 0000000..77c5951 > --- /dev/null > +++ b/memory.h > @@ -0,0 +1,142 @@ > +#ifndef MEMORY_H > +#define MEMORY_H > + > +#include > +#include > +#include "qemu-common.h" > +#include "cpu-common.h" > +#include "targphys.h" > +#include "qemu-queue.h" > + > +typedef struct MemoryRegionOps MemoryRegionOps; > +typedef struct MemoryRegion MemoryRegion; > + > +/* > + * Memory region callbacks > + */ > +struct MemoryRegionOps { > + =C2=A0 =C2=A0/* Read from the memory region. @addr is relative to @mr; = @size is > + =C2=A0 =C2=A0 * in bytes. */ > + =C2=A0 =C2=A0uint64_t (*read)(MemoryRegion *mr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 t= arget_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 u= nsigned size); > + =C2=A0 =C2=A0/* Write to the memory region. @addr is relative to @mr; @= size is > + =C2=A0 =C2=A0 * in bytes. */ > + =C2=A0 =C2=A0void (*write)(MemoryRegion *mr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_ph= ys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t = data, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned = size); > + =C2=A0 =C2=A0/* Guest-visible constraints: */ > + =C2=A0 =C2=A0struct { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If nonzero, specify bounds on access size= s beyond which a machine > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * check is thrown. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned min_access_size; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned max_access_size; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If true, unaligned accesses are supported= . =C2=A0Otherwise unaligned > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * accesses throw machine checks. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool unaligned; > + =C2=A0 =C2=A0} valid; > + =C2=A0 =C2=A0/* Internal implementation constraints: */ > + =C2=A0 =C2=A0struct { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If nonzero, specifies the minimum size im= plemented. =C2=A0Smaller sizes > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * will be rounded upwards and a partial res= ult will be returned. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned min_access_size; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If nonzero, specifies the maximum size im= plemented. =C2=A0Larger sizes > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * will be done as a series of accesses with= smaller sizes. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned max_access_size; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* If true, unaligned accesses are supported= . =C2=A0Otherwise all accesses > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * are converted to (possibly multiple) natu= rally aligned accesses. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool unaligned; > + =C2=A0 =C2=A0} impl; > +}; > + > +typedef struct CoalescedMemoryRange CoalescedMemoryRange; > + > +struct CoalescedMemoryRange { > + =C2=A0 =C2=A0target_phys_addr_t start; > + =C2=A0 =C2=A0target_phys_addr_t size; > + =C2=A0 =C2=A0QTAILQ_ENTRY(coalesced_ranges) link; > +}; > + > +struct MemoryRegion { > + =C2=A0 =C2=A0/* All fields are private - violators will be prosecuted *= / > + =C2=A0 =C2=A0const MemoryRegionOps *ops; > + =C2=A0 =C2=A0MemoryRegion *parent; > + =C2=A0 =C2=A0target_phys_addr_t size; > + =C2=A0 =C2=A0target_phys_addr_t addr; > + =C2=A0 =C2=A0ram_addr_t ram_addr; > + =C2=A0 =C2=A0unsigned priority; > + =C2=A0 =C2=A0bool may_overlap; > + =C2=A0 =C2=A0QTAILQ_HEAD(subregions, MemoryRegion) subregions; > + =C2=A0 =C2=A0QTAILQ_ENTRY(subregions) subregions_link; > + =C2=A0 =C2=A0QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coales= ced; > +}; > + > +/* Initialize a memory region > + * > + * The region typically acts as a container for other memory regions. > + */ > +void memory_region_init(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=A0target_phys_addr_t size); > +/* Initialize an I/O memory region. =C2=A0Accesses into the region will = be > + * cause the callbacks in @ops to be called. > + * > + * if @size is nonzero, subregions will be clipped to @size. > + */ > +void memory_region_init_io(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 const MemoryRegionOps *ops, > + =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 size); > +/* Initialize an I/O memory region. =C2=A0Accesses into the region will = be > + * modify memory directly. > + */ > +void memory_region_init_ram(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=A0target_phys_addr_t size); > +/* Initialize a RAM memory region. =C2=A0Accesses into the region will b= e > + * modify memory in @ptr directly. > + */ > +void memory_region_init_ram_ptr(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=A0target_phys_addr_t 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 =C2=A0void *ptr); > +/* Destroy a memory region. =C2=A0The memory becomes inaccessible. */ > +void memory_region_destroy(MemoryRegion *mr); Doesn't the lower priority region become accessible instead in some cases? > +/* Sets an offset to be added to MemoryRegionOps callbacks. */ > +void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offse= t); > +/* Turn loggging on or off for specified client (display, migration) */ g-- > +void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client); > +/* Enable memory coalescing for the region. =C2=A0MMIO ->write callbacks= may be > + * delayed until a non-coalesced MMIO is issued. > + */ > +void memory_region_set_coalescing(MemoryRegion *mr); > +/* Enable memory coalescing for a sub-range of the region. =C2=A0MMIO ->= write > + * callbacks may be delayed until a non-coalesced MMIO is issued. > + */ > +void memory_region_add_coalescing(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=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=A0target_phys_addr_t size); > +/* Disable MMIO coalescing for the region. */ > +void memory_region_clear_coalescing(MemoryRegion *mr); Perhaps the interface could be more generic, like +void memory_region_set_property(MemoryRegion *mr, unsigned flags); +void memory_region_clear_property(MemoryRegion *mr, unsigned flags); > + > +/* Add a sub-region at @offset. =C2=A0The sub-region may not overlap wit= h other > + * subregions (except for those explicitly marked as overlapping) > + */ > +void memory_region_add_subregion(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 target_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 MemoryRegion *subregion); > +/* Add a sub-region at @offset. =C2=A0The sun-region may overlap other s= ubregions; Sunny regions? > + * conflicts are resolved by having a higher @priority hide a lower @pri= ority. > + * Subregions without priority are taken as @priority 0. > + */ > +void memory_region_add_subregion_overlap(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 targe= t_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 Memor= yRegion *subregion, > + =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 unsig= ned priority); > +/* Remove a subregion. */ > +void memory_region_del_subregion(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 MemoryRegion *subregion); What would the subregions be used for?