aboutsummaryrefslogtreecommitdiff
path: root/hw/i386
diff options
context:
space:
mode:
authorIgor Druzhinin <igor.druzhinin@citrix.com>2017-07-10 23:40:02 +0100
committerStefano Stabellini <sstabellini@kernel.org>2017-07-18 14:16:09 -0700
commit5ba3d7564593c55292056ef5af84d50b55ebcf0e (patch)
treed5ff65b3661561716f52d189f6945d1e2dac1e5c /hw/i386
parent759235653de427e4e7b62d8e6fb1ef9cb68bac7d (diff)
xen/mapcache: introduce xen_replace_cache_entry()
This new call is trying to update a requested map cache entry according to the changes in the physmap. The call is searching for the entry, unmaps it and maps again at the same place using a new guest address. If the mapping is dummy this call will make it real. This function makes use of a new xenforeignmemory_map2() call with an extended interface that was recently introduced in libxenforeignmemory [1]. [1] https://www.mail-archive.com/xen-devel@lists.xen.org/msg113007.html Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com> Reviewed-by: Paul Durrant <paul.durrant@citrix.com> Reviewed-by: Stefano Stabellini <sstabellini@kernel.org> Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
Diffstat (limited to 'hw/i386')
-rw-r--r--hw/i386/xen/xen-mapcache.c85
1 files changed, 77 insertions, 8 deletions
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index 39cb511117..56986db706 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -151,6 +151,7 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
}
static void xen_remap_bucket(MapCacheEntry *entry,
+ void *vaddr,
hwaddr size,
hwaddr address_index,
bool dummy)
@@ -167,7 +168,9 @@ static void xen_remap_bucket(MapCacheEntry *entry,
err = g_malloc0(nb_pfn * sizeof (int));
if (entry->vaddr_base != NULL) {
- ram_block_notify_remove(entry->vaddr_base, entry->size);
+ if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
+ ram_block_notify_remove(entry->vaddr_base, entry->size);
+ }
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);
@@ -181,11 +184,11 @@ static void xen_remap_bucket(MapCacheEntry *entry,
}
if (!dummy) {
- vaddr_base = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
+ vaddr_base = xenforeignmemory_map2(xen_fmem, xen_domid, vaddr,
+ PROT_READ | PROT_WRITE, 0,
nb_pfn, pfns, err);
if (vaddr_base == NULL) {
- perror("xenforeignmemory_map");
+ perror("xenforeignmemory_map2");
exit(-1);
}
} else {
@@ -193,7 +196,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
* We create dummy mappings where we are unable to create a foreign
* mapping immediately due to certain circumstances (i.e. on resume now)
*/
- vaddr_base = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ vaddr_base = mmap(vaddr, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
if (vaddr_base == NULL) {
perror("mmap");
@@ -201,6 +204,10 @@ static void xen_remap_bucket(MapCacheEntry *entry,
}
}
+ if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
+ ram_block_notify_add(vaddr_base, size);
+ }
+
entry->vaddr_base = vaddr_base;
entry->paddr_index = address_index;
entry->size = size;
@@ -213,7 +220,6 @@ static void xen_remap_bucket(MapCacheEntry *entry,
entry->flags &= ~(XEN_MAPCACHE_ENTRY_DUMMY);
}
- ram_block_notify_add(entry->vaddr_base, entry->size);
bitmap_zero(entry->valid_mapping, nb_pfn);
for (i = 0; i < nb_pfn; i++) {
if (!err[i]) {
@@ -286,14 +292,14 @@ tryagain:
if (!entry) {
entry = g_malloc0(sizeof (MapCacheEntry));
pentry->next = entry;
- xen_remap_bucket(entry, cache_size, address_index, dummy);
+ xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
} else if (!entry->lock) {
if (!entry->vaddr_base || entry->paddr_index != address_index ||
entry->size != cache_size ||
!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
- xen_remap_bucket(entry, cache_size, address_index, dummy);
+ xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
}
}
@@ -490,3 +496,66 @@ void xen_invalidate_map_cache(void)
mapcache_unlock();
}
+
+static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
+ hwaddr new_phys_addr,
+ hwaddr size)
+{
+ MapCacheEntry *entry;
+ hwaddr address_index, address_offset;
+ hwaddr test_bit_size, cache_size = size;
+
+ address_index = old_phys_addr >> MCACHE_BUCKET_SHIFT;
+ address_offset = old_phys_addr & (MCACHE_BUCKET_SIZE - 1);
+
+ assert(size);
+ /* test_bit_size is always a multiple of XC_PAGE_SIZE */
+ test_bit_size = size + (old_phys_addr & (XC_PAGE_SIZE - 1));
+ if (test_bit_size % XC_PAGE_SIZE) {
+ test_bit_size += XC_PAGE_SIZE - (test_bit_size % XC_PAGE_SIZE);
+ }
+ cache_size = size + address_offset;
+ if (cache_size % MCACHE_BUCKET_SIZE) {
+ cache_size += MCACHE_BUCKET_SIZE - (cache_size % MCACHE_BUCKET_SIZE);
+ }
+
+ entry = &mapcache->entry[address_index % mapcache->nr_buckets];
+ while (entry && !(entry->paddr_index == address_index &&
+ entry->size == cache_size)) {
+ entry = entry->next;
+ }
+ if (!entry) {
+ DPRINTF("Trying to update an entry for %lx " \
+ "that is not in the mapcache!\n", old_phys_addr);
+ return NULL;
+ }
+
+ address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT;
+ address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1);
+
+ fprintf(stderr, "Replacing a dummy mapcache entry for %lx with %lx\n",
+ old_phys_addr, new_phys_addr);
+
+ xen_remap_bucket(entry, entry->vaddr_base,
+ cache_size, address_index, false);
+ if (!test_bits(address_offset >> XC_PAGE_SHIFT,
+ test_bit_size >> XC_PAGE_SHIFT,
+ entry->valid_mapping)) {
+ DPRINTF("Unable to update a mapcache entry for %lx!\n", old_phys_addr);
+ return NULL;
+ }
+
+ return entry->vaddr_base + address_offset;
+}
+
+uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
+ hwaddr new_phys_addr,
+ hwaddr size)
+{
+ uint8_t *p;
+
+ mapcache_lock();
+ p = xen_replace_cache_entry_unlocked(old_phys_addr, new_phys_addr, size);
+ mapcache_unlock();
+ return p;
+}