exec: make qemu_ram_ptr_length more similar to qemu_get_ram_ptr

Notably, use qemu_get_ram_block to enjoy the MRU optimization.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2015-12-16 10:31:26 +01:00
parent 49b24afcb1
commit e81bcda529

46
exec.c
View file

@ -1809,36 +1809,33 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr /* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
* but takes a size argument. * but takes a size argument.
* *
* By the time this function returns, the returned pointer is not protected * Called within RCU critical section.
* by RCU anymore. If the caller is not within an RCU critical section and
* does not hold the iothread lock, it must have other means of protecting the
* pointer, such as a reference to the region that includes the incoming
* ram_addr_t.
*/ */
static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size) static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
{ {
void *ptr; RAMBlock *block;
ram_addr_t offset_inside_block;
if (*size == 0) { if (*size == 0) {
return NULL; return NULL;
} }
if (xen_enabled()) {
return xen_map_cache(addr, *size, 1); block = qemu_get_ram_block(addr);
} else { offset_inside_block = addr - block->offset;
RAMBlock *block; *size = MIN(*size, block->max_length - offset_inside_block);
rcu_read_lock();
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { if (xen_enabled() && block->host == NULL) {
if (addr - block->offset < block->max_length) { /* We need to check if the requested address is in the RAM
if (addr - block->offset + *size > block->max_length) * because we don't want to map the entire memory in QEMU.
*size = block->max_length - addr + block->offset; * In that case just map the requested area.
ptr = ramblock_ptr(block, addr - block->offset); */
rcu_read_unlock(); if (block->offset == 0) {
return ptr; return xen_map_cache(addr, *size, 1);
}
} }
fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); block->host = xen_map_cache(block->offset, block->max_length, 1);
abort();
} }
return ramblock_ptr(block, offset_inside_block);
} }
/* /*
@ -2786,6 +2783,7 @@ void *address_space_map(AddressSpace *as,
hwaddr l, xlat, base; hwaddr l, xlat, base;
MemoryRegion *mr, *this_mr; MemoryRegion *mr, *this_mr;
ram_addr_t raddr; ram_addr_t raddr;
void *ptr;
if (len == 0) { if (len == 0) {
return NULL; return NULL;
@ -2837,9 +2835,11 @@ void *address_space_map(AddressSpace *as,
} }
memory_region_ref(mr); memory_region_ref(mr);
rcu_read_unlock();
*plen = done; *plen = done;
return qemu_ram_ptr_length(raddr + base, plen); ptr = qemu_ram_ptr_length(raddr + base, plen);
rcu_read_unlock();
return ptr;
} }
/* Unmaps a memory region previously mapped by address_space_map(). /* Unmaps a memory region previously mapped by address_space_map().