Paravirtualized devices (and also some real devices) can assume they are going to access RAM. For this reason, provide a fast-path function with the following properties:
1) it will never allocate a bounce buffer 2) it can be used for read-modify-write operations 3) unlike qemu_get_ram_ptr, it is safe because it recognizes "short" blocks To use cpu_physical_memory_map_fast for RMW, just pass 1 to is_write when unmapping. Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- cpu-common.h | 4 ++++ exec.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 0 deletions(-) diff --git a/cpu-common.h b/cpu-common.h index 96c02ae..d6e116d 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -80,6 +80,10 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr, void *cpu_physical_memory_map(target_phys_addr_t addr, target_phys_addr_t *plen, int is_write); +void *cpu_physical_memory_map_fast(target_phys_addr_t addr, + target_phys_addr_t *plen); +bool cpu_physical_memory_map_check(target_phys_addr_t addr, + target_phys_addr_t len); void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, int is_write, target_phys_addr_t access_len); void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)); diff --git a/exec.c b/exec.c index 9b2c9e4..2b88c29 100644 --- a/exec.c +++ b/exec.c @@ -3944,6 +3944,19 @@ static void *cpu_physical_memory_map_internal(target_phys_addr_t addr, /* Map a physical memory region into a host virtual address. * May map a subset of the requested range, given by and returned in *plen. + * May return NULL if extra resources are needed to perform the mapping + * (i.e. cpu_physical_memory_map is needed). + * It may be used for read-modify-write operations. + */ +void *cpu_physical_memory_map_fast(target_phys_addr_t addr, + target_phys_addr_t *plen) +{ + uintptr_t pd; + return cpu_physical_memory_map_internal(addr, plen, &pd); +} + +/* Map a physical memory region into a host virtual address. + * May map a subset of the requested range, given by and returned in *plen. * May return NULL if resources needed to perform the mapping are exhausted. * Use only for reads OR writes - not for read-modify-write operations. * Use cpu_register_map_client() to know when retrying the map operation is @@ -3981,6 +3994,24 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, return bounce.buffer; } +/* Returns true if the entire area between ADDR and ADDR+LEN (inclusive + * and exclusive, respectively) can be mapped by cpu_physical_memory_map_fast + * (possibly in multiple steps). + */ +bool cpu_physical_memory_map_check(target_phys_addr_t addr, + target_phys_addr_t len) +{ + while (len > 0) { + target_phys_addr_t l = len; + if (!cpu_physical_memory_map_fast(addr, &l)) { + return false; + } + len -= l; + addr += l; + } + return true; +} + /* Unmaps a memory region previously mapped by cpu_physical_memory_map(). * Will also mark the memory as dirty if is_write == 1. access_len gives * the amount of memory that was actually read or written by the caller. -- 1.7.4.4