Commit 432d268c authored by Jun Nakajima's avatar Jun Nakajima Committed by Alexander Graf
Browse files

xen: Introduce the Xen mapcache



On IA32 host or IA32 PAE host, at present, generally, we can't create
an HVM guest with more than 2G memory, because generally it's almost
impossible for Qemu to find a large enough and consecutive virtual
address space to map an HVM guest's whole physical address space.
The attached patch fixes this issue using dynamic mapping based on
little blocks of memory.

Each call to qemu_get_ram_ptr makes a call to qemu_map_cache with the
lock option, so mapcache will not unmap these ram_ptr.

Blocks that do not belong to the RAM, but usually to a device ROM or to
a framebuffer, are handled in a separate function. So the whole RAMBlock
can be map.

Signed-off-by: default avatarJun Nakajima <jun.nakajima@intel.com>
Signed-off-by: default avatarAnthony PERARD <anthony.perard@citrix.com>
Signed-off-by: default avatarStefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 9c11a8ac
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -214,8 +214,11 @@ else
  CONFIG_NO_XEN = y
endif
# xen support
CONFIG_NO_XEN_MAPCACHE = $(if $(subst n,,$(CONFIG_XEN_MAPCACHE)),n,y)
obj-i386-$(CONFIG_XEN) += xen-all.o
obj-$(CONFIG_NO_XEN) += xen-stub.o
obj-i386-$(CONFIG_XEN_MAPCACHE) += xen-mapcache.o
obj-$(CONFIG_NO_XEN_MAPCACHE) += xen-mapcache-stub.o

# Inter-VM PCI shared memory
CONFIG_IVSHMEM =
+3 −0
Original line number Diff line number Diff line
@@ -3299,6 +3299,9 @@ case "$target_arch2" in
  i386|x86_64)
    if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
      echo "CONFIG_XEN=y" >> $config_target_mak
      if test "$cpu" = "i386" -o "$cpu" = "x86_64"; then
          echo "CONFIG_XEN_MAPCACHE=y" >> $config_target_mak
      fi
    fi
esac
case "$target_arch2" in
+44 −4
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include "hw/qdev.h"
#include "osdep.h"
#include "kvm.h"
#include "hw/xen.h"
#include "qemu-timer.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
@@ -51,6 +52,8 @@
#include <libutil.h>
#endif
#endif
#else /* !CONFIG_USER_ONLY */
#include "xen-mapcache.h"
#endif

//#define DEBUG_TB_INVALIDATE
@@ -2889,6 +2892,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
        }
    }

    new_block->offset = find_ram_offset(size);
    if (host) {
        new_block->host = host;
        new_block->flags |= RAM_PREALLOC_MASK;
@@ -2911,13 +2915,15 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
                                   PROT_EXEC|PROT_READ|PROT_WRITE,
                                   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#else
            if (xen_mapcache_enabled()) {
                xen_ram_alloc(new_block->offset, size);
            } else {
                new_block->host = qemu_vmalloc(size);
            }
#endif
            qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
        }
    }

    new_block->offset = find_ram_offset(size);
    new_block->length = size;

    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
@@ -2962,7 +2968,11 @@ void qemu_ram_free(ram_addr_t addr)
#if defined(TARGET_S390X) && defined(CONFIG_KVM)
                munmap(block->host, block->length);
#else
                if (xen_mapcache_enabled()) {
                    qemu_invalidate_entry(block->host);
                } else {
                    qemu_vfree(block->host);
                }
#endif
            }
            qemu_free(block);
@@ -3051,6 +3061,16 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
                QLIST_REMOVE(block, next);
                QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
            }
            if (xen_mapcache_enabled()) {
                /* We need to check if the requested address is in the RAM
                 * because we don't want to map the entire memory in QEMU.
                 */
                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);
                }
            }
            return block->host + (addr - block->offset);
        }
    }
@@ -3070,6 +3090,16 @@ void *qemu_safe_ram_ptr(ram_addr_t addr)

    QLIST_FOREACH(block, &ram_list.blocks, next) {
        if (addr - block->offset < block->length) {
            if (xen_mapcache_enabled()) {
                /* We need to check if the requested address is in the RAM
                 * because we don't want to map the entire memory in QEMU.
                 */
                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);
                }
            }
            return block->host + (addr - block->offset);
        }
    }
@@ -3086,11 +3116,21 @@ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
    uint8_t *host = ptr;

    QLIST_FOREACH(block, &ram_list.blocks, next) {
        /* This case append when the block is not mapped. */
        if (block->host == NULL) {
            continue;
        }
        if (host - block->host < block->length) {
            *ram_addr = block->offset + (host - block->host);
            return 0;
        }
    }

    if (xen_mapcache_enabled()) {
        *ram_addr = qemu_ram_addr_from_mapcache(ptr);
        return 0;
    }

    return -1;
}

+13 −0
Original line number Diff line number Diff line
@@ -31,6 +31,15 @@ static inline int xen_enabled(void)
#endif
}

static inline int xen_mapcache_enabled(void)
{
#ifdef CONFIG_XEN_MAPCACHE
    return xen_enabled();
#else
    return 0;
#endif
}

int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
void xen_piix3_set_irq(void *opaque, int irq_num, int level);
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
@@ -41,6 +50,10 @@ int xen_init(void);
int xen_hvm_init(void);
void xen_vcpu_init(void);

#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size);
#endif

#if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
#  define HVM_MAX_VCPUS 32
#endif
+9 −0
Original line number Diff line number Diff line
@@ -63,6 +63,15 @@ static inline int xc_fd(int xen_xc)
}


static inline int xc_domain_populate_physmap_exact
    (XenXC xc_handle, uint32_t domid, unsigned long nr_extents,
     unsigned int extent_order, unsigned int mem_flags, xen_pfn_t *extent_start)
{
    return xc_domain_memory_populate_physmap
        (xc_handle, domid, nr_extents, extent_order, mem_flags, extent_start);
}


/* Xen 4.1 */
#else

Loading