xen-mapcache.c 17.1 KB
Newer Older
J
Jun Nakajima 已提交
1 2 3 4 5 6
/*
 * Copyright (C) 2011       Citrix Ltd.
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
7 8
 * Contributions after 2012-01-13 are licensed under the terms of the
 * GNU GPL, version 2 or (at your option) any later version.
J
Jun Nakajima 已提交
9 10
 */

P
Peter Maydell 已提交
11
#include "qemu/osdep.h"
12
#include "qemu/units.h"
13
#include "qemu/error-report.h"
J
Jun Nakajima 已提交
14 15 16

#include <sys/resource.h>

17
#include "hw/xen/xen-legacy-backend.h"
18
#include "qemu/bitmap.h"
J
Jun Nakajima 已提交
19 20 21

#include <xen/hvm/params.h>

22
#include "sysemu/xen-mapcache.h"
A
Anthony Xu 已提交
23
#include "trace.h"
J
Jun Nakajima 已提交
24 25 26 27 28 29 30 31 32 33 34 35


//#define MAPCACHE_DEBUG

#ifdef MAPCACHE_DEBUG
#  define DPRINTF(fmt, ...) do { \
    fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
} while (0)
#else
#  define DPRINTF(fmt, ...) do { } while (0)
#endif

S
Stefano Stabellini 已提交
36
#if HOST_LONG_BITS == 32
J
Jun Nakajima 已提交
37
#  define MCACHE_BUCKET_SHIFT 16
38
#  define MCACHE_MAX_SIZE     (1UL<<31) /* 2GB Cap */
S
Stefano Stabellini 已提交
39
#else
J
Jun Nakajima 已提交
40
#  define MCACHE_BUCKET_SHIFT 20
41
#  define MCACHE_MAX_SIZE     (1UL<<35) /* 32GB Cap */
J
Jun Nakajima 已提交
42 43 44
#endif
#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)

45 46 47 48 49
/* This is the size of the virtual address space reserve to QEMU that will not
 * be use by MapCache.
 * From empirical tests I observed that qemu use 75MB more than the
 * max_mcache_size.
 */
50
#define NON_MCACHE_MEMORY_SIZE (80 * MiB)
51

J
Jun Nakajima 已提交
52
typedef struct MapCacheEntry {
A
Avi Kivity 已提交
53
    hwaddr paddr_index;
J
Jun Nakajima 已提交
54
    uint8_t *vaddr_base;
55
    unsigned long *valid_mapping;
J
Jun Nakajima 已提交
56
    uint8_t lock;
57 58
#define XEN_MAPCACHE_ENTRY_DUMMY (1 << 0)
    uint8_t flags;
A
Avi Kivity 已提交
59
    hwaddr size;
J
Jun Nakajima 已提交
60 61 62 63 64
    struct MapCacheEntry *next;
} MapCacheEntry;

typedef struct MapCacheRev {
    uint8_t *vaddr_req;
A
Avi Kivity 已提交
65 66
    hwaddr paddr_index;
    hwaddr size;
J
Jun Nakajima 已提交
67
    QTAILQ_ENTRY(MapCacheRev) next;
68
    bool dma;
J
Jun Nakajima 已提交
69 70 71 72 73
} MapCacheRev;

typedef struct MapCache {
    MapCacheEntry *entry;
    unsigned long nr_buckets;
74
    QTAILQ_HEAD(, MapCacheRev) locked_entries;
J
Jun Nakajima 已提交
75 76

    /* For most cases (>99.9%), the page address is the same. */
77
    MapCacheEntry *last_entry;
J
Jun Nakajima 已提交
78 79
    unsigned long max_mcache_size;
    unsigned int mcache_bucket_shift;
80 81

    phys_offset_to_gaddr_t phys_offset_to_gaddr;
P
Paolo Bonzini 已提交
82
    QemuMutex lock;
83
    void *opaque;
J
Jun Nakajima 已提交
84 85 86 87
} MapCache;

static MapCache *mapcache;

P
Paolo Bonzini 已提交
88 89 90 91 92 93 94 95 96 97
static inline void mapcache_lock(void)
{
    qemu_mutex_lock(&mapcache->lock);
}

static inline void mapcache_unlock(void)
{
    qemu_mutex_unlock(&mapcache->lock);
}

98 99 100 101 102 103 104 105 106
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;
}

107
void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
J
Jun Nakajima 已提交
108 109 110 111
{
    unsigned long size;
    struct rlimit rlimit_as;

112
    mapcache = g_malloc0(sizeof (MapCache));
J
Jun Nakajima 已提交
113

114 115
    mapcache->phys_offset_to_gaddr = f;
    mapcache->opaque = opaque;
P
Paolo Bonzini 已提交
116
    qemu_mutex_init(&mapcache->lock);
117

J
Jun Nakajima 已提交
118 119
    QTAILQ_INIT(&mapcache->locked_entries);

120 121 122 123
    if (geteuid() == 0) {
        rlimit_as.rlim_cur = RLIM_INFINITY;
        rlimit_as.rlim_max = RLIM_INFINITY;
        mapcache->max_mcache_size = MCACHE_MAX_SIZE;
124
    } else {
125 126 127 128
        getrlimit(RLIMIT_AS, &rlimit_as);
        rlimit_as.rlim_cur = rlimit_as.rlim_max;

        if (rlimit_as.rlim_max != RLIM_INFINITY) {
129
            warn_report("QEMU's maximum size of virtual"
A
Alistair Francis 已提交
130
                        " memory is not infinity");
131 132 133 134 135 136 137
        }
        if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) {
            mapcache->max_mcache_size = rlimit_as.rlim_max -
                NON_MCACHE_MEMORY_SIZE;
        } else {
            mapcache->max_mcache_size = MCACHE_MAX_SIZE;
        }
138 139
    }

J
Jun Nakajima 已提交
140 141 142 143 144 145 146 147 148
    setrlimit(RLIMIT_AS, &rlimit_as);

    mapcache->nr_buckets =
        (((mapcache->max_mcache_size >> XC_PAGE_SHIFT) +
          (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
         (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));

    size = mapcache->nr_buckets * sizeof (MapCacheEntry);
    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
J
Jan Kiszka 已提交
149 150
    DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__,
            mapcache->nr_buckets, size);
151
    mapcache->entry = g_malloc0(size);
J
Jun Nakajima 已提交
152 153
}

J
Jan Kiszka 已提交
154
static void xen_remap_bucket(MapCacheEntry *entry,
155
                             void *vaddr,
A
Avi Kivity 已提交
156
                             hwaddr size,
157 158
                             hwaddr address_index,
                             bool dummy)
J
Jun Nakajima 已提交
159 160 161 162
{
    uint8_t *vaddr_base;
    xen_pfn_t *pfns;
    int *err;
163
    unsigned int i;
A
Avi Kivity 已提交
164
    hwaddr nb_pfn = size >> XC_PAGE_SHIFT;
J
Jun Nakajima 已提交
165

J
Jan Kiszka 已提交
166
    trace_xen_remap_bucket(address_index);
J
Jun Nakajima 已提交
167

168 169
    pfns = g_malloc0(nb_pfn * sizeof (xen_pfn_t));
    err = g_malloc0(nb_pfn * sizeof (int));
J
Jun Nakajima 已提交
170 171

    if (entry->vaddr_base != NULL) {
172 173 174
        if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
            ram_block_notify_remove(entry->vaddr_base, entry->size);
        }
175
        if (munmap(entry->vaddr_base, entry->size) != 0) {
J
Jun Nakajima 已提交
176 177 178 179
            perror("unmap fails");
            exit(-1);
        }
    }
180 181
    g_free(entry->valid_mapping);
    entry->valid_mapping = NULL;
J
Jun Nakajima 已提交
182 183 184 185 186

    for (i = 0; i < nb_pfn; i++) {
        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
    }

187 188 189 190
    /*
     * If the caller has requested the mapping at a specific address use
     * MAP_FIXED to make sure it's honored.
     */
191
    if (!dummy) {
192
        vaddr_base = xenforeignmemory_map2(xen_fmem, xen_domid, vaddr,
193 194
                                           PROT_READ | PROT_WRITE,
                                           vaddr ? MAP_FIXED : 0,
195 196
                                           nb_pfn, pfns, err);
        if (vaddr_base == NULL) {
197
            perror("xenforeignmemory_map2");
198 199 200 201 202 203 204
            exit(-1);
        }
    } else {
        /*
         * We create dummy mappings where we are unable to create a foreign
         * mapping immediately due to certain circumstances (i.e. on resume now)
         */
205
        vaddr_base = mmap(vaddr, size, PROT_READ | PROT_WRITE,
206 207
                          MAP_ANON | MAP_SHARED | (vaddr ? MAP_FIXED : 0),
                          -1, 0);
208
        if (vaddr_base == MAP_FAILED) {
209 210 211
            perror("mmap");
            exit(-1);
        }
J
Jun Nakajima 已提交
212 213
    }

214 215 216 217
    if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
        ram_block_notify_add(vaddr_base, size);
    }

J
Jun Nakajima 已提交
218 219
    entry->vaddr_base = vaddr_base;
    entry->paddr_index = address_index;
220
    entry->size = size;
221
    entry->valid_mapping = (unsigned long *) g_malloc0(sizeof(unsigned long) *
222
            BITS_TO_LONGS(size >> XC_PAGE_SHIFT));
J
Jun Nakajima 已提交
223

224 225 226 227 228 229
    if (dummy) {
        entry->flags |= XEN_MAPCACHE_ENTRY_DUMMY;
    } else {
        entry->flags &= ~(XEN_MAPCACHE_ENTRY_DUMMY);
    }

230 231 232 233
    bitmap_zero(entry->valid_mapping, nb_pfn);
    for (i = 0; i < nb_pfn; i++) {
        if (!err[i]) {
            bitmap_set(entry->valid_mapping, i, 1);
J
Jun Nakajima 已提交
234 235 236
        }
    }

237 238
    g_free(pfns);
    g_free(err);
J
Jun Nakajima 已提交
239 240
}

P
Paolo Bonzini 已提交
241
static uint8_t *xen_map_cache_unlocked(hwaddr phys_addr, hwaddr size,
242
                                       uint8_t lock, bool dma)
J
Jun Nakajima 已提交
243
{
244 245
    MapCacheEntry *entry, *pentry = NULL,
                  *free_entry = NULL, *free_pentry = NULL;
A
Avi Kivity 已提交
246 247
    hwaddr address_index;
    hwaddr address_offset;
248 249
    hwaddr cache_size = size;
    hwaddr test_bit_size;
250
    bool translated G_GNUC_UNUSED = false;
251
    bool dummy = false;
252 253 254 255

tryagain:
    address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
    address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);
J
Jun Nakajima 已提交
256

J
Jan Kiszka 已提交
257
    trace_xen_map_cache(phys_addr);
J
Jun Nakajima 已提交
258

259
    /* test_bit_size is always a multiple of XC_PAGE_SIZE */
260
    if (size) {
261
        test_bit_size = size + (phys_addr & (XC_PAGE_SIZE - 1));
262

263 264
        if (test_bit_size % XC_PAGE_SIZE) {
            test_bit_size += XC_PAGE_SIZE - (test_bit_size % XC_PAGE_SIZE);
265 266
        }
    } else {
267
        test_bit_size = XC_PAGE_SIZE;
268 269
    }

270 271
    if (mapcache->last_entry != NULL &&
        mapcache->last_entry->paddr_index == address_index &&
272
        !lock && !size &&
273
        test_bits(address_offset >> XC_PAGE_SHIFT,
274
                  test_bit_size >> XC_PAGE_SHIFT,
275
                  mapcache->last_entry->valid_mapping)) {
276 277
        trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);
        return mapcache->last_entry->vaddr_base + address_offset;
J
Jun Nakajima 已提交
278 279
    }

280
    /* size is always a multiple of MCACHE_BUCKET_SIZE */
281
    if (size) {
282 283 284
        cache_size = size + address_offset;
        if (cache_size % MCACHE_BUCKET_SIZE) {
            cache_size += MCACHE_BUCKET_SIZE - (cache_size % MCACHE_BUCKET_SIZE);
285 286
        }
    } else {
287
        cache_size = MCACHE_BUCKET_SIZE;
288
    }
289

J
Jun Nakajima 已提交
290 291
    entry = &mapcache->entry[address_index % mapcache->nr_buckets];

292
    while (entry && (lock || entry->lock) && entry->vaddr_base &&
293
            (entry->paddr_index != address_index || entry->size != cache_size ||
294
             !test_bits(address_offset >> XC_PAGE_SHIFT,
295
                 test_bit_size >> XC_PAGE_SHIFT,
296
                 entry->valid_mapping))) {
297 298 299 300
        if (!free_entry && !entry->lock) {
            free_entry = entry;
            free_pentry = pentry;
        }
J
Jun Nakajima 已提交
301 302 303
        pentry = entry;
        entry = entry->next;
    }
304 305 306 307
    if (!entry && free_entry) {
        entry = free_entry;
        pentry = free_pentry;
    }
J
Jun Nakajima 已提交
308
    if (!entry) {
309
        entry = g_malloc0(sizeof (MapCacheEntry));
J
Jun Nakajima 已提交
310
        pentry->next = entry;
311
        xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
J
Jun Nakajima 已提交
312 313
    } else if (!entry->lock) {
        if (!entry->vaddr_base || entry->paddr_index != address_index ||
314
                entry->size != cache_size ||
315
                !test_bits(address_offset >> XC_PAGE_SHIFT,
316
                    test_bit_size >> XC_PAGE_SHIFT,
317
                    entry->valid_mapping)) {
318
            xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
J
Jun Nakajima 已提交
319 320 321
        }
    }

322
    if(!test_bits(address_offset >> XC_PAGE_SHIFT,
323
                test_bit_size >> XC_PAGE_SHIFT,
324
                entry->valid_mapping)) {
325
        mapcache->last_entry = NULL;
326
#ifdef XEN_COMPAT_PHYSMAP
327
        if (!translated && mapcache->phys_offset_to_gaddr) {
328
            phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size);
329 330
            translated = true;
            goto tryagain;
331
        }
332
#endif
333 334 335
        if (!dummy && runstate_check(RUN_STATE_INMIGRATE)) {
            dummy = true;
            goto tryagain;
336
        }
J
Jan Kiszka 已提交
337
        trace_xen_map_cache_return(NULL);
J
Jun Nakajima 已提交
338 339 340
        return NULL;
    }

341
    mapcache->last_entry = entry;
J
Jun Nakajima 已提交
342
    if (lock) {
343
        MapCacheRev *reventry = g_malloc0(sizeof(MapCacheRev));
J
Jun Nakajima 已提交
344
        entry->lock++;
345
        reventry->dma = dma;
346 347
        reventry->vaddr_req = mapcache->last_entry->vaddr_base + address_offset;
        reventry->paddr_index = mapcache->last_entry->paddr_index;
348
        reventry->size = entry->size;
J
Jun Nakajima 已提交
349 350 351
        QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
    }

352 353
    trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);
    return mapcache->last_entry->vaddr_base + address_offset;
J
Jun Nakajima 已提交
354 355
}

P
Paolo Bonzini 已提交
356
uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
357
                       uint8_t lock, bool dma)
P
Paolo Bonzini 已提交
358 359 360 361
{
    uint8_t *p;

    mapcache_lock();
362
    p = xen_map_cache_unlocked(phys_addr, size, lock, dma);
P
Paolo Bonzini 已提交
363 364 365 366
    mapcache_unlock();
    return p;
}

J
Jan Kiszka 已提交
367
ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
J
Jun Nakajima 已提交
368
{
369
    MapCacheEntry *entry = NULL;
J
Jun Nakajima 已提交
370
    MapCacheRev *reventry;
A
Avi Kivity 已提交
371 372
    hwaddr paddr_index;
    hwaddr size;
P
Paolo Bonzini 已提交
373
    ram_addr_t raddr;
J
Jun Nakajima 已提交
374 375
    int found = 0;

P
Paolo Bonzini 已提交
376
    mapcache_lock();
J
Jun Nakajima 已提交
377 378 379
    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
        if (reventry->vaddr_req == ptr) {
            paddr_index = reventry->paddr_index;
380
            size = reventry->size;
J
Jun Nakajima 已提交
381 382 383 384 385
            found = 1;
            break;
        }
    }
    if (!found) {
J
Jan Kiszka 已提交
386
        fprintf(stderr, "%s, could not find %p\n", __func__, ptr);
J
Jun Nakajima 已提交
387 388 389 390 391 392 393 394
        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
            DPRINTF("   "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index,
                    reventry->vaddr_req);
        }
        abort();
        return 0;
    }

395 396 397 398 399 400
    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
    while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
        entry = entry->next;
    }
    if (!entry) {
        DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr);
P
Paolo Bonzini 已提交
401 402 403 404
        raddr = 0;
    } else {
        raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
             ((unsigned long) ptr - (unsigned long) entry->vaddr_base);
405
    }
P
Paolo Bonzini 已提交
406 407
    mapcache_unlock();
    return raddr;
J
Jun Nakajima 已提交
408 409
}

P
Paolo Bonzini 已提交
410
static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
J
Jun Nakajima 已提交
411 412 413
{
    MapCacheEntry *entry = NULL, *pentry = NULL;
    MapCacheRev *reventry;
A
Avi Kivity 已提交
414 415
    hwaddr paddr_index;
    hwaddr size;
J
Jun Nakajima 已提交
416 417 418 419 420
    int found = 0;

    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
        if (reventry->vaddr_req == buffer) {
            paddr_index = reventry->paddr_index;
421
            size = reventry->size;
J
Jun Nakajima 已提交
422 423 424 425 426
            found = 1;
            break;
        }
    }
    if (!found) {
J
Jan Kiszka 已提交
427
        DPRINTF("%s, could not find %p\n", __func__, buffer);
J
Jun Nakajima 已提交
428 429 430 431 432 433
        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
            DPRINTF("   "TARGET_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
        }
        return;
    }
    QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
434
    g_free(reventry);
J
Jun Nakajima 已提交
435

436 437 438
    if (mapcache->last_entry != NULL &&
        mapcache->last_entry->paddr_index == paddr_index) {
        mapcache->last_entry = NULL;
439 440
    }

J
Jun Nakajima 已提交
441
    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
442
    while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
J
Jun Nakajima 已提交
443 444 445 446 447 448 449 450 451 452 453 454 455
        pentry = entry;
        entry = entry->next;
    }
    if (!entry) {
        DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
        return;
    }
    entry->lock--;
    if (entry->lock > 0 || pentry == NULL) {
        return;
    }

    pentry->next = entry->next;
P
Paolo Bonzini 已提交
456
    ram_block_notify_remove(entry->vaddr_base, entry->size);
457
    if (munmap(entry->vaddr_base, entry->size) != 0) {
J
Jun Nakajima 已提交
458 459 460
        perror("unmap fails");
        exit(-1);
    }
461 462
    g_free(entry->valid_mapping);
    g_free(entry);
J
Jun Nakajima 已提交
463 464
}

P
Paolo Bonzini 已提交
465 466 467 468 469 470 471
void xen_invalidate_map_cache_entry(uint8_t *buffer)
{
    mapcache_lock();
    xen_invalidate_map_cache_entry_unlocked(buffer);
    mapcache_unlock();
}

J
Jan Kiszka 已提交
472
void xen_invalidate_map_cache(void)
J
Jun Nakajima 已提交
473 474 475 476 477
{
    unsigned long i;
    MapCacheRev *reventry;

    /* Flush pending AIO before destroying the mapcache */
478
    bdrv_drain_all();
J
Jun Nakajima 已提交
479

P
Paolo Bonzini 已提交
480 481
    mapcache_lock();

J
Jun Nakajima 已提交
482
    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
483 484 485 486 487
        if (!reventry->dma) {
            continue;
        }
        fprintf(stderr, "Locked DMA mapping while invalidating mapcache!"
                " "TARGET_FMT_plx" -> %p is present\n",
J
Jun Nakajima 已提交
488 489 490 491 492 493 494 495 496
                reventry->paddr_index, reventry->vaddr_req);
    }

    for (i = 0; i < mapcache->nr_buckets; i++) {
        MapCacheEntry *entry = &mapcache->entry[i];

        if (entry->vaddr_base == NULL) {
            continue;
        }
497 498 499
        if (entry->lock > 0) {
            continue;
        }
J
Jun Nakajima 已提交
500

501
        if (munmap(entry->vaddr_base, entry->size) != 0) {
J
Jun Nakajima 已提交
502 503 504 505 506 507
            perror("unmap fails");
            exit(-1);
        }

        entry->paddr_index = 0;
        entry->vaddr_base = NULL;
508
        entry->size = 0;
509
        g_free(entry->valid_mapping);
510
        entry->valid_mapping = NULL;
J
Jun Nakajima 已提交
511 512
    }

513
    mapcache->last_entry = NULL;
J
Jun Nakajima 已提交
514 515 516

    mapcache_unlock();
}
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545

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) {
546
        DPRINTF("Trying to update an entry for "TARGET_FMT_plx \
547 548 549 550 551 552 553
                "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);

554 555
    fprintf(stderr, "Replacing a dummy mapcache entry for "TARGET_FMT_plx \
            " with "TARGET_FMT_plx"\n", old_phys_addr, new_phys_addr);
556 557 558 559 560 561

    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)) {
562 563
        DPRINTF("Unable to update a mapcache entry for "TARGET_FMT_plx"!\n",
                old_phys_addr);
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
        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;
}