mirror of https://gitee.com/openkylin/qemu.git
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>
This commit is contained in:
parent
759235653d
commit
5ba3d75645
|
@ -2107,6 +2107,24 @@ EOF
|
||||||
# Xen unstable
|
# Xen unstable
|
||||||
elif
|
elif
|
||||||
cat > $TMPC <<EOF &&
|
cat > $TMPC <<EOF &&
|
||||||
|
#undef XC_WANT_COMPAT_MAP_FOREIGN_API
|
||||||
|
#include <xenforeignmemory.h>
|
||||||
|
int main(void) {
|
||||||
|
xenforeignmemory_handle *xfmem;
|
||||||
|
|
||||||
|
xfmem = xenforeignmemory_open(0, 0);
|
||||||
|
xenforeignmemory_map2(xfmem, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs"
|
||||||
|
then
|
||||||
|
xen_stable_libs="-lxendevicemodel $xen_stable_libs"
|
||||||
|
xen_ctrl_version=41000
|
||||||
|
xen=yes
|
||||||
|
elif
|
||||||
|
cat > $TMPC <<EOF &&
|
||||||
#undef XC_WANT_COMPAT_DEVICEMODEL_API
|
#undef XC_WANT_COMPAT_DEVICEMODEL_API
|
||||||
#define __XEN_TOOLS__
|
#define __XEN_TOOLS__
|
||||||
#include <xendevicemodel.h>
|
#include <xendevicemodel.h>
|
||||||
|
|
|
@ -151,6 +151,7 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_remap_bucket(MapCacheEntry *entry,
|
static void xen_remap_bucket(MapCacheEntry *entry,
|
||||||
|
void *vaddr,
|
||||||
hwaddr size,
|
hwaddr size,
|
||||||
hwaddr address_index,
|
hwaddr address_index,
|
||||||
bool dummy)
|
bool dummy)
|
||||||
|
@ -167,7 +168,9 @@ static void xen_remap_bucket(MapCacheEntry *entry,
|
||||||
err = g_malloc0(nb_pfn * sizeof (int));
|
err = g_malloc0(nb_pfn * sizeof (int));
|
||||||
|
|
||||||
if (entry->vaddr_base != NULL) {
|
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) {
|
if (munmap(entry->vaddr_base, entry->size) != 0) {
|
||||||
perror("unmap fails");
|
perror("unmap fails");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -181,11 +184,11 @@ static void xen_remap_bucket(MapCacheEntry *entry,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dummy) {
|
if (!dummy) {
|
||||||
vaddr_base = xenforeignmemory_map(xen_fmem, xen_domid,
|
vaddr_base = xenforeignmemory_map2(xen_fmem, xen_domid, vaddr,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE, 0,
|
||||||
nb_pfn, pfns, err);
|
nb_pfn, pfns, err);
|
||||||
if (vaddr_base == NULL) {
|
if (vaddr_base == NULL) {
|
||||||
perror("xenforeignmemory_map");
|
perror("xenforeignmemory_map2");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,7 +196,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
|
||||||
* We create dummy mappings where we are unable to create a foreign
|
* We create dummy mappings where we are unable to create a foreign
|
||||||
* mapping immediately due to certain circumstances (i.e. on resume now)
|
* 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);
|
MAP_ANON | MAP_SHARED, -1, 0);
|
||||||
if (vaddr_base == NULL) {
|
if (vaddr_base == NULL) {
|
||||||
perror("mmap");
|
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->vaddr_base = vaddr_base;
|
||||||
entry->paddr_index = address_index;
|
entry->paddr_index = address_index;
|
||||||
entry->size = size;
|
entry->size = size;
|
||||||
|
@ -213,7 +220,6 @@ static void xen_remap_bucket(MapCacheEntry *entry,
|
||||||
entry->flags &= ~(XEN_MAPCACHE_ENTRY_DUMMY);
|
entry->flags &= ~(XEN_MAPCACHE_ENTRY_DUMMY);
|
||||||
}
|
}
|
||||||
|
|
||||||
ram_block_notify_add(entry->vaddr_base, entry->size);
|
|
||||||
bitmap_zero(entry->valid_mapping, nb_pfn);
|
bitmap_zero(entry->valid_mapping, nb_pfn);
|
||||||
for (i = 0; i < nb_pfn; i++) {
|
for (i = 0; i < nb_pfn; i++) {
|
||||||
if (!err[i]) {
|
if (!err[i]) {
|
||||||
|
@ -286,14 +292,14 @@ tryagain:
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
entry = g_malloc0(sizeof (MapCacheEntry));
|
entry = g_malloc0(sizeof (MapCacheEntry));
|
||||||
pentry->next = entry;
|
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) {
|
} else if (!entry->lock) {
|
||||||
if (!entry->vaddr_base || entry->paddr_index != address_index ||
|
if (!entry->vaddr_base || entry->paddr_index != address_index ||
|
||||||
entry->size != cache_size ||
|
entry->size != cache_size ||
|
||||||
!test_bits(address_offset >> XC_PAGE_SHIFT,
|
!test_bits(address_offset >> XC_PAGE_SHIFT,
|
||||||
test_bit_size >> XC_PAGE_SHIFT,
|
test_bit_size >> XC_PAGE_SHIFT,
|
||||||
entry->valid_mapping)) {
|
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();
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -78,6 +78,20 @@ static inline void *xenforeignmemory_map(xc_interface *h, uint32_t dom,
|
||||||
|
|
||||||
extern xenforeignmemory_handle *xen_fmem;
|
extern xenforeignmemory_handle *xen_fmem;
|
||||||
|
|
||||||
|
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 41000
|
||||||
|
|
||||||
|
static inline void *xenforeignmemory_map2(xenforeignmemory_handle *h,
|
||||||
|
uint32_t dom, void *addr,
|
||||||
|
int prot, int flags, size_t pages,
|
||||||
|
const xen_pfn_t arr[/*pages*/],
|
||||||
|
int err[/*pages*/])
|
||||||
|
{
|
||||||
|
assert(addr == NULL && flags == 0);
|
||||||
|
return xenforeignmemory_map(h, dom, prot, pages, arr, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40900
|
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40900
|
||||||
|
|
||||||
typedef xc_interface xendevicemodel_handle;
|
typedef xc_interface xendevicemodel_handle;
|
||||||
|
|
|
@ -21,7 +21,9 @@ uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
|
||||||
ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
|
ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
|
||||||
void xen_invalidate_map_cache_entry(uint8_t *buffer);
|
void xen_invalidate_map_cache_entry(uint8_t *buffer);
|
||||||
void xen_invalidate_map_cache(void);
|
void xen_invalidate_map_cache(void);
|
||||||
|
uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
|
||||||
|
hwaddr new_phys_addr,
|
||||||
|
hwaddr size);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline void xen_map_cache_init(phys_offset_to_gaddr_t f,
|
static inline void xen_map_cache_init(phys_offset_to_gaddr_t f,
|
||||||
|
@ -50,6 +52,13 @@ static inline void xen_invalidate_map_cache(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
|
||||||
|
hwaddr new_phys_addr,
|
||||||
|
hwaddr size)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* XEN_MAPCACHE_H */
|
#endif /* XEN_MAPCACHE_H */
|
||||||
|
|
Loading…
Reference in New Issue