From c13390cd384a9564e6dded127d01ef0627b6b1c5 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 19 May 2011 18:35:42 +0100 Subject: xen: fix qemu_map_cache with size != MCACHE_BUCKET_SIZE Fix the implementation of qemu_map_cache: correctly support size arguments different from 0 or MCACHE_BUCKET_SIZE. The new implementation supports locked mapcache entries with size multiple of MCACHE_BUCKET_SIZE. qemu_invalidate_entry can correctly find and unmap these "large" mapcache entries given that the virtual address passed to qemu_invalidate_entry is the same returned by qemu_map_cache when the locked mapcache entry was created. Signed-off-by: Stefano Stabellini Signed-off-by: Alexander Graf --- xen-mapcache.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 12 deletions(-) (limited to 'xen-mapcache.c') diff --git a/xen-mapcache.c b/xen-mapcache.c index 349cc6221d..90fbd4983f 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -43,14 +43,16 @@ typedef struct MapCacheEntry { target_phys_addr_t paddr_index; uint8_t *vaddr_base; - DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT); + unsigned long *valid_mapping; uint8_t lock; + target_phys_addr_t size; struct MapCacheEntry *next; } MapCacheEntry; typedef struct MapCacheRev { uint8_t *vaddr_req; target_phys_addr_t paddr_index; + target_phys_addr_t size; QTAILQ_ENTRY(MapCacheRev) next; } MapCacheRev; @@ -68,6 +70,15 @@ typedef struct MapCache { static MapCache *mapcache; +static inline int test_bits(int nr, int size, const unsigned long *addr) +{ + unsigned long res = find_next_zero_bit(addr, size + nr, nr); + if (res >= nr + size) + return 1; + else + return 0; +} + void qemu_map_cache_init(void) { unsigned long size; @@ -115,11 +126,15 @@ static void qemu_remap_bucket(MapCacheEntry *entry, err = qemu_mallocz(nb_pfn * sizeof (int)); if (entry->vaddr_base != NULL) { - if (munmap(entry->vaddr_base, size) != 0) { + if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } } + if (entry->valid_mapping != NULL) { + qemu_free(entry->valid_mapping); + entry->valid_mapping = NULL; + } for (i = 0; i < nb_pfn; i++) { pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i; @@ -134,6 +149,9 @@ static void qemu_remap_bucket(MapCacheEntry *entry, entry->vaddr_base = vaddr_base; entry->paddr_index = address_index; + entry->size = size; + entry->valid_mapping = (unsigned long *) qemu_mallocz(sizeof(unsigned long) * + BITS_TO_LONGS(size >> XC_PAGE_SHIFT)); bitmap_zero(entry->valid_mapping, nb_pfn); for (i = 0; i < nb_pfn; i++) { @@ -151,32 +169,47 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u MapCacheEntry *entry, *pentry = NULL; target_phys_addr_t address_index = phys_addr >> MCACHE_BUCKET_SHIFT; target_phys_addr_t address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1); + target_phys_addr_t __size = size; trace_qemu_map_cache(phys_addr); - if (address_index == mapcache->last_address_index && !lock) { + if (address_index == mapcache->last_address_index && !lock && !__size) { trace_qemu_map_cache_return(mapcache->last_address_vaddr + address_offset); return mapcache->last_address_vaddr + address_offset; } + /* size is always a multiple of MCACHE_BUCKET_SIZE */ + if ((address_offset + (__size % MCACHE_BUCKET_SIZE)) > MCACHE_BUCKET_SIZE) + __size += MCACHE_BUCKET_SIZE; + if (__size % MCACHE_BUCKET_SIZE) + __size += MCACHE_BUCKET_SIZE - (__size % MCACHE_BUCKET_SIZE); + if (!__size) + __size = MCACHE_BUCKET_SIZE; + entry = &mapcache->entry[address_index % mapcache->nr_buckets]; - while (entry && entry->lock && entry->paddr_index != address_index && entry->vaddr_base) { + while (entry && entry->lock && entry->vaddr_base && + (entry->paddr_index != address_index || entry->size != __size || + !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, + entry->valid_mapping))) { pentry = entry; entry = entry->next; } if (!entry) { entry = qemu_mallocz(sizeof (MapCacheEntry)); pentry->next = entry; - qemu_remap_bucket(entry, size ? : MCACHE_BUCKET_SIZE, address_index); + qemu_remap_bucket(entry, __size, address_index); } else if (!entry->lock) { if (!entry->vaddr_base || entry->paddr_index != address_index || - !test_bit(address_offset >> XC_PAGE_SHIFT, entry->valid_mapping)) { - qemu_remap_bucket(entry, size ? : MCACHE_BUCKET_SIZE, address_index); + entry->size != __size || + !test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, + entry->valid_mapping)) { + qemu_remap_bucket(entry, __size, address_index); } } - if (!test_bit(address_offset >> XC_PAGE_SHIFT, entry->valid_mapping)) { + if(!test_bits(address_offset >> XC_PAGE_SHIFT, size >> XC_PAGE_SHIFT, + entry->valid_mapping)) { mapcache->last_address_index = -1; trace_qemu_map_cache_return(NULL); return NULL; @@ -189,6 +222,7 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u entry->lock++; reventry->vaddr_req = mapcache->last_address_vaddr + address_offset; reventry->paddr_index = mapcache->last_address_index; + reventry->size = entry->size; QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next); } @@ -231,13 +265,16 @@ void qemu_map_cache_unlock(void *buffer) ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) { + MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; target_phys_addr_t paddr_index; + target_phys_addr_t size; int found = 0; QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { if (reventry->vaddr_req == ptr) { paddr_index = reventry->paddr_index; + size = reventry->size; found = 1; break; } @@ -252,7 +289,17 @@ ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) return 0; } - return paddr_index << MCACHE_BUCKET_SHIFT; + entry = &mapcache->entry[paddr_index % mapcache->nr_buckets]; + while (entry && (entry->paddr_index != paddr_index || entry->size != size)) { + pentry = entry; + entry = entry->next; + } + if (!entry) { + DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr); + return 0; + } + return (reventry->paddr_index << MCACHE_BUCKET_SHIFT) + + ((unsigned long) ptr - (unsigned long) entry->vaddr_base); } void qemu_invalidate_entry(uint8_t *buffer) @@ -260,6 +307,7 @@ void qemu_invalidate_entry(uint8_t *buffer) MapCacheEntry *entry = NULL, *pentry = NULL; MapCacheRev *reventry; target_phys_addr_t paddr_index; + target_phys_addr_t size; int found = 0; if (mapcache->last_address_vaddr == buffer) { @@ -269,6 +317,7 @@ void qemu_invalidate_entry(uint8_t *buffer) QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { if (reventry->vaddr_req == buffer) { paddr_index = reventry->paddr_index; + size = reventry->size; found = 1; break; } @@ -284,7 +333,7 @@ void qemu_invalidate_entry(uint8_t *buffer) qemu_free(reventry); entry = &mapcache->entry[paddr_index % mapcache->nr_buckets]; - while (entry && entry->paddr_index != paddr_index) { + while (entry && (entry->paddr_index != paddr_index || entry->size != size)) { pentry = entry; entry = entry->next; } @@ -298,10 +347,11 @@ void qemu_invalidate_entry(uint8_t *buffer) } pentry->next = entry->next; - if (munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE) != 0) { + if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } + qemu_free(entry->valid_mapping); qemu_free(entry); } @@ -328,13 +378,16 @@ void qemu_invalidate_map_cache(void) continue; } - if (munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE) != 0) { + if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } entry->paddr_index = 0; entry->vaddr_base = NULL; + entry->size = 0; + qemu_free(entry->valid_mapping); + entry->valid_mapping = NULL; } mapcache->last_address_index = -1; -- cgit 1.4.1 From cd306087e5a9ea4091071a0a41c0ea99fac60ab0 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 19 May 2011 18:35:43 +0100 Subject: xen: remove qemu_map_cache_unlock There is no need for qemu_map_cache_unlock, just use qemu_invalidate_entry instead. Signed-off-by: Stefano Stabellini Signed-off-by: Alexander Graf --- exec.c | 2 +- xen-mapcache-stub.c | 4 ---- xen-mapcache.c | 33 --------------------------------- xen-mapcache.h | 1 - 4 files changed, 1 insertion(+), 39 deletions(-) (limited to 'xen-mapcache.c') diff --git a/exec.c b/exec.c index 09928a3b37..01f33bb2bc 100644 --- a/exec.c +++ b/exec.c @@ -3146,7 +3146,7 @@ void qemu_put_ram_ptr(void *addr) xen_unmap_block(block->host, block->length); block->host = NULL; } else { - qemu_map_cache_unlock(addr); + qemu_invalidate_entry(addr); } } } diff --git a/xen-mapcache-stub.c b/xen-mapcache-stub.c index 7c14b3d141..60f712b229 100644 --- a/xen-mapcache-stub.c +++ b/xen-mapcache-stub.c @@ -22,10 +22,6 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u return qemu_get_ram_ptr(phys_addr); } -void qemu_map_cache_unlock(void *buffer) -{ -} - ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) { return -1; diff --git a/xen-mapcache.c b/xen-mapcache.c index 90fbd4983f..57fe24de86 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -230,39 +230,6 @@ uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, u return mapcache->last_address_vaddr + address_offset; } -void qemu_map_cache_unlock(void *buffer) -{ - MapCacheEntry *entry = NULL, *pentry = NULL; - MapCacheRev *reventry; - target_phys_addr_t paddr_index; - int found = 0; - - QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { - if (reventry->vaddr_req == buffer) { - paddr_index = reventry->paddr_index; - found = 1; - break; - } - } - if (!found) { - return; - } - QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next); - qemu_free(reventry); - - entry = &mapcache->entry[paddr_index % mapcache->nr_buckets]; - while (entry && entry->paddr_index != paddr_index) { - pentry = entry; - entry = entry->next; - } - if (!entry) { - return; - } - if (entry->lock > 0) { - entry->lock--; - } -} - ram_addr_t qemu_ram_addr_from_mapcache(void *ptr) { MapCacheEntry *entry = NULL, *pentry = NULL; diff --git a/xen-mapcache.h b/xen-mapcache.h index 339444c94e..b89b8f9653 100644 --- a/xen-mapcache.h +++ b/xen-mapcache.h @@ -14,7 +14,6 @@ void qemu_map_cache_init(void); uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, uint8_t lock); -void qemu_map_cache_unlock(void *phys_addr); ram_addr_t qemu_ram_addr_from_mapcache(void *ptr); void qemu_invalidate_entry(uint8_t *buffer); void qemu_invalidate_map_cache(void); -- cgit 1.4.1 From 6506e4f995967b1a48cc34418c77b318df92ce35 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 19 May 2011 18:35:44 +0100 Subject: xen: remove xen_map_block and xen_unmap_block Replace xen_map_block with qemu_map_cache with the appropriate locking and size parameters. Replace xen_unmap_block with qemu_invalidate_entry. Signed-off-by: Stefano Stabellini Signed-off-by: Alexander Graf --- exec.c | 19 ++++--------------- xen-mapcache-stub.c | 4 ---- xen-mapcache.c | 31 ------------------------------- xen-mapcache.h | 15 --------------- 4 files changed, 4 insertions(+), 65 deletions(-) (limited to 'xen-mapcache.c') diff --git a/exec.c b/exec.c index 01f33bb2bc..e11c1dd97a 100644 --- a/exec.c +++ b/exec.c @@ -53,6 +53,7 @@ #endif #else /* !CONFIG_USER_ONLY */ #include "xen-mapcache.h" +#include "trace.h" #endif //#define DEBUG_TB_INVALIDATE @@ -3088,7 +3089,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr) if (block->offset == 0) { return qemu_map_cache(addr, 0, 1); } else if (block->host == NULL) { - block->host = xen_map_block(block->offset, block->length); + block->host = qemu_map_cache(block->offset, block->length, 1); } } return block->host + (addr - block->offset); @@ -3117,7 +3118,7 @@ void *qemu_safe_ram_ptr(ram_addr_t addr) if (block->offset == 0) { return qemu_map_cache(addr, 0, 1); } else if (block->host == NULL) { - block->host = xen_map_block(block->offset, block->length); + block->host = qemu_map_cache(block->offset, block->length, 1); } } return block->host + (addr - block->offset); @@ -3135,19 +3136,7 @@ void qemu_put_ram_ptr(void *addr) trace_qemu_put_ram_ptr(addr); if (xen_mapcache_enabled()) { - RAMBlock *block; - - QLIST_FOREACH(block, &ram_list.blocks, next) { - if (addr == block->host) { - break; - } - } - if (block && block->host) { - xen_unmap_block(block->host, block->length); - block->host = NULL; - } else { - qemu_invalidate_entry(addr); - } + qemu_invalidate_entry(block->host); } } diff --git a/xen-mapcache-stub.c b/xen-mapcache-stub.c index 60f712b229..8a2380a151 100644 --- a/xen-mapcache-stub.c +++ b/xen-mapcache-stub.c @@ -34,7 +34,3 @@ void qemu_invalidate_map_cache(void) void qemu_invalidate_entry(uint8_t *buffer) { } -uint8_t *xen_map_block(target_phys_addr_t phys_addr, target_phys_addr_t size) -{ - return NULL; -} diff --git a/xen-mapcache.c b/xen-mapcache.c index 57fe24de86..fac47cd9be 100644 --- a/xen-mapcache.c +++ b/xen-mapcache.c @@ -362,34 +362,3 @@ void qemu_invalidate_map_cache(void) mapcache_unlock(); } - -uint8_t *xen_map_block(target_phys_addr_t phys_addr, target_phys_addr_t size) -{ - uint8_t *vaddr_base; - xen_pfn_t *pfns; - int *err; - unsigned int i; - target_phys_addr_t nb_pfn = size >> XC_PAGE_SHIFT; - - trace_xen_map_block(phys_addr, size); - phys_addr >>= XC_PAGE_SHIFT; - - pfns = qemu_mallocz(nb_pfn * sizeof (xen_pfn_t)); - err = qemu_mallocz(nb_pfn * sizeof (int)); - - for (i = 0; i < nb_pfn; i++) { - pfns[i] = phys_addr + i; - } - - vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE, - pfns, err, nb_pfn); - if (vaddr_base == NULL) { - perror("xc_map_foreign_bulk"); - exit(-1); - } - - qemu_free(pfns); - qemu_free(err); - - return vaddr_base; -} diff --git a/xen-mapcache.h b/xen-mapcache.h index b89b8f9653..6216cc3be7 100644 --- a/xen-mapcache.h +++ b/xen-mapcache.h @@ -9,27 +9,12 @@ #ifndef XEN_MAPCACHE_H #define XEN_MAPCACHE_H -#include -#include "trace.h" - void qemu_map_cache_init(void); uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, target_phys_addr_t size, uint8_t lock); ram_addr_t qemu_ram_addr_from_mapcache(void *ptr); void qemu_invalidate_entry(uint8_t *buffer); void qemu_invalidate_map_cache(void); -uint8_t *xen_map_block(target_phys_addr_t phys_addr, target_phys_addr_t size); - -static inline void xen_unmap_block(void *addr, ram_addr_t size) -{ - trace_xen_unmap_block(addr, size); - - if (munmap(addr, size) != 0) { - hw_error("xen_unmap_block: %s", strerror(errno)); - } -} - - #define mapcache_lock() ((void)0) #define mapcache_unlock() ((void)0) -- cgit 1.4.1