exec: reorganize address_space_map

First of all, rename "todo" to "done".

Second, clearly separate the case of done == 0 with the case of done != 0.
This will help handling reference counting in the next patch.

Third, this test:

             if (memory_region_get_ram_addr(mr) + xlat != raddr + todo) {

does not guarantee that the memory region is the same across two iterations
of the while loop.  For example, you could have two blocks:

A) size 640 K, mapped at physical address 0, ram_addr_t 0
B) size 64 K, mapped at physical address 0xa0000, ram_addr_t 0xa0000

then mapping 1 M starting at physical address zero will erroneously treat
B as the continuation of block A.  qemu_ram_ptr_length ensures that no
invalid memory is accessed, but it is still a pointless complication of
the algorithm.  The patch makes the logic clearer with an explicit test
that the memory region is the same.

Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2013-06-28 17:29:27 +02:00
parent 1b5ec23467
commit e3127ae0cd
1 changed files with 38 additions and 33 deletions

71
exec.c
View File

@ -2065,47 +2065,52 @@ void *address_space_map(AddressSpace *as,
bool is_write) bool is_write)
{ {
hwaddr len = *plen; hwaddr len = *plen;
hwaddr todo = 0; hwaddr done = 0;
hwaddr l, xlat; hwaddr l, xlat, base;
MemoryRegion *mr; MemoryRegion *mr, *this_mr;
ram_addr_t raddr = RAM_ADDR_MAX; ram_addr_t raddr;
ram_addr_t rlen;
void *ret;
while (len > 0) { if (len == 0) {
l = len; return NULL;
mr = address_space_translate(as, addr, &xlat, &l, is_write); }
if (!memory_access_is_direct(mr, is_write)) { l = len;
if (todo || bounce.buffer) { mr = address_space_translate(as, addr, &xlat, &l, is_write);
break; if (!memory_access_is_direct(mr, is_write)) {
} if (bounce.buffer) {
bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); return NULL;
bounce.addr = addr;
bounce.len = l;
if (!is_write) {
address_space_read(as, addr, bounce.buffer, l);
}
*plen = l;
return bounce.buffer;
} }
if (!todo) { bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
raddr = memory_region_get_ram_addr(mr) + xlat; bounce.addr = addr;
} else { bounce.len = l;
if (memory_region_get_ram_addr(mr) + xlat != raddr + todo) { if (!is_write) {
break; address_space_read(as, addr, bounce.buffer, l);
}
} }
*plen = l;
return bounce.buffer;
}
base = xlat;
raddr = memory_region_get_ram_addr(mr);
for (;;) {
len -= l; len -= l;
addr += l; addr += l;
todo += l; done += l;
if (len == 0) {
break;
}
l = len;
this_mr = address_space_translate(as, addr, &xlat, &l, is_write);
if (this_mr != mr || xlat != base + done) {
break;
}
} }
rlen = todo;
ret = qemu_ram_ptr_length(raddr, &rlen); *plen = done;
*plen = rlen; return qemu_ram_ptr_length(raddr + base, plen);
return ret;
} }
/* Unmaps a memory region previously mapped by address_space_map(). /* Unmaps a memory region previously mapped by address_space_map().