On Thu, May 19, 2011 at 5:12 PM, Avi Kivity <a...@redhat.com> 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. This allows a device to configure > a memory region once, then hand it off to its parent bus to map it according > 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 be > RAM while others may be MMIO. > > Signed-off-by: Avi Kivity <a...@redhat.com> > --- > memory.h | 142 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 142 insertions(+), 0 deletions(-) > create 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 <stdint.h> > +#include <stdbool.h> > +#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 { > + /* Read from the memory region. @addr is relative to @mr; @size is > + * in bytes. */ > + uint64_t (*read)(MemoryRegion *mr, > + target_phys_addr_t addr, > + unsigned size); > + /* Write to the memory region. @addr is relative to @mr; @size is > + * in bytes. */ > + void (*write)(MemoryRegion *mr, > + target_phys_addr_t addr, > + uint64_t data, > + unsigned size); > + /* Guest-visible constraints: */ > + struct { > + /* If nonzero, specify bounds on access sizes beyond which a machine > + * check is thrown. > + */ > + unsigned min_access_size; > + unsigned max_access_size; > + /* If true, unaligned accesses are supported. Otherwise unaligned > + * accesses throw machine checks. > + */ > + bool unaligned; > + } valid; > + /* Internal implementation constraints: */ > + struct { > + /* If nonzero, specifies the minimum size implemented. Smaller sizes > + * will be rounded upwards and a partial result will be returned. > + */ > + unsigned min_access_size; > + /* If nonzero, specifies the maximum size implemented. Larger sizes > + * will be done as a series of accesses with smaller sizes. > + */ > + unsigned max_access_size; > + /* If true, unaligned accesses are supported. Otherwise all accesses > + * are converted to (possibly multiple) naturally aligned accesses. > + */ > + bool unaligned; > + } impl; > +}; > + > +typedef struct CoalescedMemoryRange CoalescedMemoryRange; > + > +struct CoalescedMemoryRange { > + target_phys_addr_t start; > + target_phys_addr_t size; > + QTAILQ_ENTRY(coalesced_ranges) link; > +}; > + > +struct MemoryRegion { > + /* All fields are private - violators will be prosecuted */ > + const MemoryRegionOps *ops; > + MemoryRegion *parent; > + target_phys_addr_t size; > + target_phys_addr_t addr; > + ram_addr_t ram_addr; > + unsigned priority; > + bool may_overlap; > + QTAILQ_HEAD(subregions, MemoryRegion) subregions; > + QTAILQ_ENTRY(subregions) subregions_link; > + QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced; > +}; > + > +/* Initialize a memory region > + * > + * The region typically acts as a container for other memory regions. > + */ > +void memory_region_init(MemoryRegion *mr, > + target_phys_addr_t size); > +/* Initialize an I/O memory region. Accesses 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, > + const MemoryRegionOps *ops, > + target_phys_addr_t size); > +/* Initialize an I/O memory region. Accesses into the region will be > + * modify memory directly. > + */ > +void memory_region_init_ram(MemoryRegion *mr, > + target_phys_addr_t size); > +/* Initialize a RAM memory region. Accesses into the region will be > + * modify memory in @ptr directly. > + */ > +void memory_region_init_ram_ptr(MemoryRegion *mr, > + target_phys_addr_t size, > + void *ptr); > +/* Destroy a memory region. The 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 offset); > +/* 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. MMIO ->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. MMIO ->write > + * callbacks may be delayed until a non-coalesced MMIO is issued. > + */ > +void memory_region_add_coalescing(MemoryRegion *mr, > + target_phys_addr_t offset, > + target_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. The sub-region may not overlap with other > + * subregions (except for those explicitly marked as overlapping) > + */ > +void memory_region_add_subregion(MemoryRegion *mr, > + target_phys_addr_t offset, > + MemoryRegion *subregion); > +/* Add a sub-region at @offset. The sun-region may overlap other subregions; Sunny regions? > + * conflicts are resolved by having a higher @priority hide a lower > @priority. > + * Subregions without priority are taken as @priority 0. > + */ > +void memory_region_add_subregion_overlap(MemoryRegion *mr, > + target_phys_addr_t offset, > + MemoryRegion *subregion, > + unsigned priority); > +/* Remove a subregion. */ > +void memory_region_del_subregion(MemoryRegion *mr, > + MemoryRegion *subregion); What would the subregions be used for?