}
}
+static void memory_region_oldmmio_read_accessor(void *opaque,
+ hwaddr addr,
+ uint64_t *value,
+ unsigned size,
+ unsigned shift,
+ uint64_t mask)
+{
+ MemoryRegion *mr = opaque;
+ uint64_t tmp;
+
+ tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
+ *value |= (tmp & mask) << shift;
+}
+
static void memory_region_read_accessor(void *opaque,
hwaddr addr,
uint64_t *value,
*value |= (tmp & mask) << shift;
}
+static void memory_region_oldmmio_write_accessor(void *opaque,
+ hwaddr addr,
+ uint64_t *value,
+ unsigned size,
+ unsigned shift,
+ uint64_t mask)
+{
+ MemoryRegion *mr = opaque;
+ uint64_t tmp;
+
+ tmp = (*value >> shift) & mask;
+ mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp);
+}
+
static void memory_region_write_accessor(void *opaque,
hwaddr addr,
uint64_t *value,
if (!access_size_max) {
access_size_max = 4;
}
+
+ /* FIXME: support unaligned access? */
access_size = MAX(MIN(size, access_size_max), access_size_min);
access_mask = -1ULL >> (64 - access_size * 8);
for (i = 0; i < size; i += access_size) {
- /* FIXME: big-endian support */
+#ifdef TARGET_WORDS_BIGENDIAN
+ access(opaque, addr + i, value, access_size,
+ (size - access_size - i) * 8, access_mask);
+#else
access(opaque, addr + i, value, access_size, i * 8, access_mask);
+#endif
}
}
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static bool memory_region_access_valid(MemoryRegion *mr,
- hwaddr addr,
- unsigned size,
- bool is_write)
+bool memory_region_access_valid(MemoryRegion *mr,
+ hwaddr addr,
+ unsigned size,
+ bool is_write)
{
- if (mr->ops->valid.accepts
- && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write)) {
- return false;
- }
+ int access_size_min, access_size_max;
+ int access_size, i;
if (!mr->ops->valid.unaligned && (addr & (size - 1))) {
return false;
}
- /* Treat zero as compatibility all valid */
- if (!mr->ops->valid.max_access_size) {
+ if (!mr->ops->valid.accepts) {
return true;
}
- if (size > mr->ops->valid.max_access_size
- || size < mr->ops->valid.min_access_size) {
- return false;
+ access_size_min = mr->ops->valid.min_access_size;
+ if (!mr->ops->valid.min_access_size) {
+ access_size_min = 1;
+ }
+
+ access_size_max = mr->ops->valid.max_access_size;
+ if (!mr->ops->valid.max_access_size) {
+ access_size_max = 4;
+ }
+
+ access_size = MAX(MIN(size, access_size_max), access_size_min);
+ for (i = 0; i < size; i += access_size) {
+ if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size,
+ is_write)) {
+ return false;
+ }
}
+
return true;
}
{
uint64_t data = 0;
- if (!memory_region_access_valid(mr, addr, size, false)) {
- return unassigned_mem_read(mr, addr, size);
- }
-
- if (!mr->ops->read) {
- return mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
+ if (mr->ops->read) {
+ access_with_adjusted_size(addr, &data, size,
+ mr->ops->impl.min_access_size,
+ mr->ops->impl.max_access_size,
+ memory_region_read_accessor, mr);
+ } else {
+ access_with_adjusted_size(addr, &data, size, 1, 4,
+ memory_region_oldmmio_read_accessor, mr);
}
- /* FIXME: support unaligned access */
- access_with_adjusted_size(addr, &data, size,
- mr->ops->impl.min_access_size,
- mr->ops->impl.max_access_size,
- memory_region_read_accessor, mr);
-
return data;
}
case 4:
*data = bswap32(*data);
break;
+ case 8:
+ *data = bswap64(*data);
+ break;
default:
abort();
}
}
}
-static uint64_t memory_region_dispatch_read(MemoryRegion *mr,
- hwaddr addr,
- unsigned size)
+static bool memory_region_dispatch_read(MemoryRegion *mr,
+ hwaddr addr,
+ uint64_t *pval,
+ unsigned size)
{
- uint64_t ret;
+ if (!memory_region_access_valid(mr, addr, size, false)) {
+ *pval = unassigned_mem_read(mr, addr, size);
+ return true;
+ }
- ret = memory_region_dispatch_read1(mr, addr, size);
- adjust_endianness(mr, &ret, size);
- return ret;
+ *pval = memory_region_dispatch_read1(mr, addr, size);
+ adjust_endianness(mr, pval, size);
+ return false;
}
-static void memory_region_dispatch_write(MemoryRegion *mr,
+static bool memory_region_dispatch_write(MemoryRegion *mr,
hwaddr addr,
uint64_t data,
unsigned size)
{
if (!memory_region_access_valid(mr, addr, size, true)) {
unassigned_mem_write(mr, addr, data, size);
- return;
+ return true;
}
adjust_endianness(mr, &data, size);
- if (!mr->ops->write) {
- mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, data);
- return;
+ if (mr->ops->write) {
+ access_with_adjusted_size(addr, &data, size,
+ mr->ops->impl.min_access_size,
+ mr->ops->impl.max_access_size,
+ memory_region_write_accessor, mr);
+ } else {
+ access_with_adjusted_size(addr, &data, size, 1, 4,
+ memory_region_oldmmio_write_accessor, mr);
}
-
- /* FIXME: support unaligned access */
- access_with_adjusted_size(addr, &data, size,
- mr->ops->impl.min_access_size,
- mr->ops->impl.max_access_size,
- memory_region_write_accessor, mr);
+ return false;
}
void memory_region_init_io(MemoryRegion *mr,
g_free(as->ioeventfds);
}
-uint64_t io_mem_read(MemoryRegion *mr, hwaddr addr, unsigned size)
+bool io_mem_read(MemoryRegion *mr, hwaddr addr, uint64_t *pval, unsigned size)
{
- return memory_region_dispatch_read(mr, addr, size);
+ return memory_region_dispatch_read(mr, addr, pval, size);
}
-void io_mem_write(MemoryRegion *mr, hwaddr addr,
+bool io_mem_write(MemoryRegion *mr, hwaddr addr,
uint64_t val, unsigned size)
{
- memory_region_dispatch_write(mr, addr, val, size);
+ return memory_region_dispatch_write(mr, addr, val, size);
}
typedef struct MemoryRegionList MemoryRegionList;