memory: split address_space_read and address_space_write

Rather than dispatching on is_write for every iteration, make
address_space_rw call one of the two functions. The amount of
duplicate logic is pretty small, and memory_access_is_direct can
be tweaked so that it inlines better in the callers.

Backports commit eb7eeb88628074207dd611472e712af775985e73 from qemu
This commit is contained in:
Paolo Bonzini 2018-02-17 20:14:23 -05:00 committed by Lioncash
parent 077ffc3bd5
commit 0688343929
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -328,11 +328,10 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
{ {
if (memory_region_is_ram(mr)) { if (is_write) {
return !(is_write && mr->readonly); return memory_region_is_ram(mr) && !mr->readonly;
} } else {
if (memory_region_is_romd(mr)) { return memory_region_is_ram(mr) || memory_region_is_romd(mr);
return !is_write;
} }
return false; return false;
@ -1796,8 +1795,8 @@ static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
return l; return l;
} }
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
uint8_t *buf, int len, bool is_write) const uint8_t *buf, int len)
{ {
hwaddr l; hwaddr l;
uint8_t *ptr; uint8_t *ptr;
@ -1805,119 +1804,159 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
hwaddr addr1; hwaddr addr1;
MemoryRegion *mr; MemoryRegion *mr;
MemTxResult result = MEMTX_OK; MemTxResult result = MEMTX_OK;
// Unicorn: commented out
//bool release_lock = false;
// Unicorn: commented out
//rcu_read_lock();
while (len > 0) { while (len > 0) {
l = len; l = len;
mr = address_space_translate(as, addr, &addr1, &l, is_write); mr = address_space_translate(as, addr, &addr1, &l, true);
if (!mr) if (!mr)
return true; return true;
if (is_write) { if (!memory_access_is_direct(mr, true)) {
if (!memory_access_is_direct(mr, is_write)) { // Unicorn: commented out
l = memory_access_size(mr, l, addr1); //release_lock |= prepare_mmio_access(mr);
/* XXX: could force current_cpu to NULL to avoid l = memory_access_size(mr, l, addr1);
potential bugs */ /* XXX: could force current_cpu to NULL to avoid
switch (l) { potential bugs */
case 8: switch (l) {
/* 64 bit write access */ case 8:
val = ldq_p(buf); /* 64 bit write access */
result |= memory_region_dispatch_write(mr, addr1, val, 8, val = ldq_p(buf);
attrs); result |= memory_region_dispatch_write(mr, addr1, val, 8,
break; attrs);
case 4: break;
/* 32 bit write access */ case 4:
val = ldl_p(buf); /* 32 bit write access */
result |= memory_region_dispatch_write(mr, addr1, val, 4, val = ldl_p(buf);
attrs); result |= memory_region_dispatch_write(mr, addr1, val, 4,
attrs);
break; break;
case 2: case 2:
/* 16 bit write access */ /* 16 bit write access */
val = lduw_p(buf); val = lduw_p(buf);
result |= memory_region_dispatch_write(mr, addr1, val, 2, result |= memory_region_dispatch_write(mr, addr1, val, 2,
attrs); attrs);
break; break;
case 1: case 1:
/* 8 bit write access */ /* 8 bit write access */
val = ldub_p(buf); val = ldub_p(buf);
result |= memory_region_dispatch_write(mr, addr1, val, 1, result |= memory_region_dispatch_write(mr, addr1, val, 1,
attrs); attrs);
break;
break; default:
default: abort();
abort();
}
} else {
addr1 += memory_region_get_ram_addr(mr);
/* RAM case */
ptr = qemu_get_ram_ptr(as->uc, addr1);
memcpy(ptr, buf, l);
invalidate_and_set_dirty(mr, addr1, l);
} }
} else { } else {
if (!memory_access_is_direct(mr, is_write)) { addr1 += memory_region_get_ram_addr(mr);
/* I/O case */ /* RAM case */
l = memory_access_size(mr, l, addr1); ptr = qemu_get_ram_ptr(mr->uc, addr1);
memcpy(ptr, buf, l);
switch (l) { invalidate_and_set_dirty(mr, addr1, l);
case 8:
/* 64 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 8,
attrs);
stq_p(buf, val);
break;
case 4:
/* 32 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 4,
attrs);
stl_p(buf, val);
break;
case 2:
/* 16 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 2,
attrs);
stw_p(buf, val);
break;
case 1:
/* 8 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 1,
attrs);
stb_p(buf, val);
break;
default:
abort();
}
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(as->uc, mr->ram_addr + addr1);
memcpy(buf, ptr, l);
}
} }
/* Unicorn: commented out
if (release_lock) {
qemu_mutex_unlock_iothread();
release_lock = false;
}*/
len -= l; len -= l;
buf += l; buf += l;
addr += l; addr += l;
} }
// Unicorn: commented out
//rcu_read_unlock();
return result; return result;
} }
MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
const uint8_t *buf, int len)
{
return address_space_rw(as, addr, attrs, (uint8_t *)buf, len, true);
}
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
uint8_t *buf, int len) uint8_t *buf, int len)
{ {
return address_space_rw(as, addr, attrs, buf, len, false); hwaddr l;
uint8_t *ptr;
uint64_t val;
hwaddr addr1;
MemoryRegion *mr;
MemTxResult result = MEMTX_OK;
// Unicorn: commented out
//bool release_lock = false;
// Unicorn: commented out
//rcu_read_lock();
while (len > 0) {
l = len;
mr = address_space_translate(as, addr, &addr1, &l, false);
if (!memory_access_is_direct(mr, false)) {
/* I/O case */
// Unicorn: commented out
//release_lock |= prepare_mmio_access(mr);
l = memory_access_size(mr, l, addr1);
switch (l) {
case 8:
/* 64 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 8,
attrs);
stq_p(buf, val);
break;
case 4:
/* 32 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 4,
attrs);
stl_p(buf, val);
break;
case 2:
/* 16 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 2,
attrs);
stw_p(buf, val);
break;
case 1:
/* 8 bit read access */
result |= memory_region_dispatch_read(mr, addr1, &val, 1,
attrs);
stb_p(buf, val);
break;
default:
abort();
}
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(mr->uc, mr->ram_addr + addr1);
memcpy(buf, ptr, l);
}
/* Unicorn: Commented out
if (release_lock) {
qemu_mutex_unlock_iothread();
release_lock = false;
}*/
len -= l;
buf += l;
addr += l;
}
// Unicorn: commented out
//rcu_read_unlock();
return result;
} }
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
uint8_t *buf, int len, bool is_write)
{
if (is_write) {
return address_space_write(as, addr, attrs, (uint8_t *)buf, len);
} else {
return address_space_read(as, addr, attrs, (uint8_t *)buf, len);
}
}
bool cpu_physical_memory_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, bool cpu_physical_memory_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
int len, int is_write) int len, int is_write)