return false;
}
+/* Called from RCU critical section */
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
hwaddr *xlat, hwaddr *plen,
bool is_write)
IOMMUTLBEntry iotlb;
MemoryRegionSection *section;
MemoryRegion *mr;
- hwaddr len = *plen;
- rcu_read_lock();
for (;;) {
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
section = address_space_translate_internal(d, addr, &addr, plen, true);
iotlb = mr->iommu_ops->translate(mr, addr, is_write);
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
| (addr & iotlb.addr_mask));
- len = MIN(len, (addr | iotlb.addr_mask) - addr + 1);
+ *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
if (!(iotlb.perm & (1 << is_write))) {
mr = &io_mem_unassigned;
break;
if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
- len = MIN(page, len);
+ *plen = MIN(page, *plen);
}
- *plen = len;
*xlat = addr;
- rcu_read_unlock();
return mr;
}
}
#endif
-void cpu_exec_init_all(void)
-{
-#if !defined(CONFIG_USER_ONLY)
- qemu_mutex_init(&ram_list.mutex);
- memory_map_init();
- io_mem_init();
-#endif
-}
-
#if !defined(CONFIG_USER_ONLY)
static int cpu_common_post_load(void *opaque, int version_id)
MemoryRegion *mr;
MemTxResult result = MEMTX_OK;
+ rcu_read_lock();
while (len > 0) {
l = len;
mr = address_space_translate(as, addr, &addr1, &l, is_write);
buf += l;
addr += l;
}
+ rcu_read_unlock();
return result;
}
hwaddr addr1;
MemoryRegion *mr;
+ rcu_read_lock();
while (len > 0) {
l = len;
mr = address_space_translate(as, addr, &addr1, &l, true);
buf += l;
addr += l;
}
+ rcu_read_unlock();
}
/* used for ROM loading : can write in RAM and ROM */
void *buffer;
hwaddr addr;
hwaddr len;
+ bool in_use;
} BounceBuffer;
static BounceBuffer bounce;
typedef struct MapClient {
- void *opaque;
- void (*callback)(void *opaque);
+ QEMUBH *bh;
QLIST_ENTRY(MapClient) link;
} MapClient;
+QemuMutex map_client_list_lock;
static QLIST_HEAD(map_client_list, MapClient) map_client_list
= QLIST_HEAD_INITIALIZER(map_client_list);
-void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+static void cpu_unregister_map_client_do(MapClient *client)
+{
+ QLIST_REMOVE(client, link);
+ g_free(client);
+}
+
+static void cpu_notify_map_clients_locked(void)
+{
+ MapClient *client;
+
+ while (!QLIST_EMPTY(&map_client_list)) {
+ client = QLIST_FIRST(&map_client_list);
+ qemu_bh_schedule(client->bh);
+ cpu_unregister_map_client_do(client);
+ }
+}
+
+void cpu_register_map_client(QEMUBH *bh)
{
MapClient *client = g_malloc(sizeof(*client));
- client->opaque = opaque;
- client->callback = callback;
+ qemu_mutex_lock(&map_client_list_lock);
+ client->bh = bh;
QLIST_INSERT_HEAD(&map_client_list, client, link);
- return client;
+ if (!atomic_read(&bounce.in_use)) {
+ cpu_notify_map_clients_locked();
+ }
+ qemu_mutex_unlock(&map_client_list_lock);
}
-static void cpu_unregister_map_client(void *_client)
+void cpu_exec_init_all(void)
{
- MapClient *client = (MapClient *)_client;
-
- QLIST_REMOVE(client, link);
- g_free(client);
+ qemu_mutex_init(&ram_list.mutex);
+ memory_map_init();
+ io_mem_init();
+ qemu_mutex_init(&map_client_list_lock);
}
-static void cpu_notify_map_clients(void)
+void cpu_unregister_map_client(QEMUBH *bh)
{
MapClient *client;
- while (!QLIST_EMPTY(&map_client_list)) {
- client = QLIST_FIRST(&map_client_list);
- client->callback(client->opaque);
- cpu_unregister_map_client(client);
+ qemu_mutex_lock(&map_client_list_lock);
+ QLIST_FOREACH(client, &map_client_list, link) {
+ if (client->bh == bh) {
+ cpu_unregister_map_client_do(client);
+ break;
+ }
}
+ qemu_mutex_unlock(&map_client_list_lock);
+}
+
+static void cpu_notify_map_clients(void)
+{
+ qemu_mutex_lock(&map_client_list_lock);
+ cpu_notify_map_clients_locked();
+ qemu_mutex_unlock(&map_client_list_lock);
}
bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write)
MemoryRegion *mr;
hwaddr l, xlat;
+ rcu_read_lock();
while (len > 0) {
l = len;
mr = address_space_translate(as, addr, &xlat, &l, is_write);
len -= l;
addr += l;
}
+ rcu_read_unlock();
return true;
}
}
l = len;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &xlat, &l, is_write);
+
if (!memory_access_is_direct(mr, is_write)) {
- if (bounce.buffer) {
+ if (atomic_xchg(&bounce.in_use, true)) {
+ rcu_read_unlock();
return NULL;
}
/* Avoid unbounded allocations */
bounce.buffer, l);
}
+ rcu_read_unlock();
*plen = l;
return bounce.buffer;
}
}
memory_region_ref(mr);
+ rcu_read_unlock();
*plen = done;
return qemu_ram_ptr_length(raddr + base, plen);
}
qemu_vfree(bounce.buffer);
bounce.buffer = NULL;
memory_region_unref(bounce.mr);
+ atomic_mb_set(&bounce.in_use, false);
cpu_notify_map_clients();
}
hwaddr addr1;
MemTxResult r;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr1, &l, false);
if (l < 4 || !memory_access_is_direct(mr, false)) {
/* I/O case */
if (result) {
*result = r;
}
+ rcu_read_unlock();
return val;
}
hwaddr addr1;
MemTxResult r;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr1, &l,
false);
if (l < 8 || !memory_access_is_direct(mr, false)) {
if (result) {
*result = r;
}
+ rcu_read_unlock();
return val;
}
hwaddr addr1;
MemTxResult r;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr1, &l,
false);
if (l < 2 || !memory_access_is_direct(mr, false)) {
if (result) {
*result = r;
}
+ rcu_read_unlock();
return val;
}
hwaddr addr1;
MemTxResult r;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr1, &l,
true);
if (l < 4 || !memory_access_is_direct(mr, true)) {
if (result) {
*result = r;
}
+ rcu_read_unlock();
}
void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
hwaddr addr1;
MemTxResult r;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr1, &l,
true);
if (l < 4 || !memory_access_is_direct(mr, true)) {
if (result) {
*result = r;
}
+ rcu_read_unlock();
}
void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val,
hwaddr addr1;
MemTxResult r;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr1, &l, true);
if (l < 2 || !memory_access_is_direct(mr, true)) {
#if defined(TARGET_WORDS_BIGENDIAN)
if (result) {
*result = r;
}
+ rcu_read_unlock();
}
void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val,
{
MemoryRegion*mr;
hwaddr l = 1;
+ bool res;
+ rcu_read_lock();
mr = address_space_translate(&address_space_memory,
phys_addr, &phys_addr, &l, false);
- return !(memory_region_is_ram(mr) ||
- memory_region_is_romd(mr));
+ res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
+ rcu_read_unlock();
+ return res;
}
void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)