@@ -48,6 +48,7 @@
#endif
#include "exec/cpu-all.h"
#include "qemu/rcu_queue.h"
+#include "qemu/main-loop.h"
#include "exec/cputlb.h"
#include "translate-all.h"
@@ -2295,8 +2296,9 @@ static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
return l;
}
-bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
- int len, bool is_write)
+static bool address_space_rw_internal(AddressSpace *as, hwaddr addr,
+ uint8_t *buf, int len, bool is_write,
+ bool unlocked)
{
hwaddr l;
uint8_t *ptr;
@@ -2304,12 +2306,29 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
hwaddr addr1;
MemoryRegion *mr;
bool error = false;
+ bool release_lock;
rcu_read_lock();
while (len > 0) {
l = len;
mr = address_space_translate(as, addr, &addr1, &l, is_write);
+ release_lock = false;
+ if (unlocked && mr->global_locking) {
+ qemu_mutex_lock_iothread();
+ unlocked = false;
+ release_lock = true;
+ }
+ if (mr->flush_coalesced_mmio) {
+ if (unlocked) {
+ qemu_mutex_lock_iothread();
+ }
+ qemu_flush_coalesced_mmio_buffer();
+ if (unlocked) {
+ qemu_mutex_unlock_iothread();
+ }
+ }
+
if (is_write) {
if (!memory_access_is_direct(mr, is_write)) {
l = memory_access_size(mr, l, addr1);
@@ -2380,6 +2399,12 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
memcpy(buf, ptr, l);
}
}
+
+ if (release_lock) {
+ qemu_mutex_unlock_iothread();
+ unlocked = true;
+ }
+
len -= l;
buf += l;
addr += l;
@@ -2389,6 +2414,18 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
return error;
}
+bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
+ int len, bool is_write)
+{
+ return address_space_rw_internal(as, addr, buf, len, is_write, false);
+}
+
+bool address_space_rw_unlocked(AddressSpace *as, hwaddr addr, uint8_t *buf,
+ int len, bool is_write)
+{
+ return address_space_rw_internal(as, addr, buf, len, is_write, true);
+}
+
bool address_space_write(AddressSpace *as, hwaddr addr,
const uint8_t *buf, int len)
{
@@ -1084,6 +1084,8 @@ void address_space_destroy(AddressSpace *as);
* Return true if the operation hit any unassigned memory or encountered an
* IOMMU fault.
*
+ * NOTE: The iothread lock must be held when calling this function.
+ *
* @as: #AddressSpace to be accessed
* @addr: address within that address space
* @buf: buffer with the data transferred
@@ -1093,6 +1095,23 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
int len, bool is_write);
/**
+ * address_space_rw_unlocked: read from or write to an address space outside
+ * of the iothread lock.
+ *
+ * Return true if the operation hit any unassigned memory or encountered an
+ * IOMMU fault.
+ *
+ * NOTE: The iothread lock *must not* be held when calling this function.
+ *
+ * @as: #AddressSpace to be accessed
+ * @addr: address within that address space
+ * @buf: buffer with the data transferred
+ * @is_write: indicates the transfer direction
+ */
+bool address_space_rw_unlocked(AddressSpace *as, hwaddr addr, uint8_t *buf,
+ int len, bool is_write);
+
+/**
* address_space_write: write to address space.
*
* Return true if the operation hit any unassigned memory or encountered an
@@ -391,9 +391,6 @@ static void memory_region_read_accessor(MemoryRegion *mr,
{
uint64_t tmp;
- if (mr->flush_coalesced_mmio) {
- qemu_flush_coalesced_mmio_buffer();
- }
tmp = mr->ops->read(mr->opaque, addr, size);
trace_memory_region_ops_read(mr, addr, tmp, size);
*value |= (tmp & mask) << shift;
@@ -422,9 +419,6 @@ static void memory_region_write_accessor(MemoryRegion *mr,
{
uint64_t tmp;
- if (mr->flush_coalesced_mmio) {
- qemu_flush_coalesced_mmio_buffer();
- }
tmp = (*value >> shift) & mask;
trace_memory_region_ops_write(mr, addr, tmp, size);
mr->ops->write(mr->opaque, addr, tmp, size);