Commit f3c6a169 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'qemu-kvm/memory/page_desc' into staging

* qemu-kvm/memory/page_desc: (22 commits)
  Remove cpu_get_physical_page_desc()
  sparc: avoid cpu_get_physical_page_desc()
  virtio-balloon: avoid cpu_get_physical_page_desc()
  vhost: avoid cpu_get_physical_page_desc()
  kvm: avoid cpu_get_physical_page_desc()
  memory: remove CPUPhysMemoryClient
  xen: convert to MemoryListener API
  memory: temporarily add memory_region_get_ram_addr()
  xen, vga: add API for registering the framebuffer
  vhost: convert to MemoryListener API
  kvm: convert to MemoryListener API
  kvm: switch kvm slots to use host virtual address instead of ram_addr_t
  memory: add API for observing updates to the physical memory map
  memory: replace cpu_physical_sync_dirty_bitmap() with a memory API
  framebuffer: drop use of cpu_physical_sync_dirty_bitmap()
  loader: remove calls to cpu_get_physical_page_desc()
  framebuffer: drop use of cpu_get_physical_page_desc()
  memory: introduce memory_region_find()
  memory: add memory_region_is_logging()
  memory: add memory_region_is_rom()
  ...
parents 8d3bc517 586c6230
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include "net.h"
#include "gdbstub.h"
#include "hw/smbios.h"
#include "exec-memory.h"

#ifdef TARGET_SPARC
int graphic_width = 1024;
@@ -263,10 +264,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
        return 0;
    }

    if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
        qemu_file_set_error(f, -EINVAL);
        return -EINVAL;
    }
    memory_global_sync_dirty_bitmap(get_system_memory());

    if (stage == 1) {
        RAMBlock *block;
+0 −9
Original line number Diff line number Diff line
@@ -569,15 +569,6 @@ int cpu_physical_memory_set_dirty_tracking(int enable);

int cpu_physical_memory_get_dirty_tracking(void);

int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
                                   target_phys_addr_t end_addr);

int cpu_physical_log_start(target_phys_addr_t start_addr,
                           ram_addr_t size);

int cpu_physical_log_stop(target_phys_addr_t start_addr,
                          ram_addr_t size);

void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
#endif /* !CONFIG_USER_ONLY */

+0 −24
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ typedef unsigned long ram_addr_t;
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);

ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
/* This should only be used for ram local to a device.  */
void *qemu_get_ram_ptr(ram_addr_t addr);
@@ -71,29 +70,6 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
void cpu_unregister_map_client(void *cookie);

struct CPUPhysMemoryClient;
typedef struct CPUPhysMemoryClient CPUPhysMemoryClient;
struct CPUPhysMemoryClient {
    void (*set_memory)(struct CPUPhysMemoryClient *client,
                       target_phys_addr_t start_addr,
                       ram_addr_t size,
                       ram_addr_t phys_offset,
                       bool log_dirty);
    int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
                             target_phys_addr_t start_addr,
                             target_phys_addr_t end_addr);
    int (*migration_log)(struct CPUPhysMemoryClient *client,
                         int enable);
    int (*log_start)(struct CPUPhysMemoryClient *client,
                     target_phys_addr_t phys_addr, ram_addr_t size);
    int (*log_stop)(struct CPUPhysMemoryClient *client,
                    target_phys_addr_t phys_addr, ram_addr_t size);
    QLIST_ENTRY(CPUPhysMemoryClient) list;
};

void cpu_register_phys_memory_client(CPUPhysMemoryClient *);
void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *);

/* Coalesced MMIO regions are areas where write operations can be reordered.
 * This usually implies that write operations are side-effect free.  This allows
 * batching which can make a major impact on performance when using
+5 −170
Original line number Diff line number Diff line
@@ -1732,124 +1732,6 @@ const CPULogItem cpu_log_items[] = {
    { 0, NULL, NULL },
};

#ifndef CONFIG_USER_ONLY
static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
    = QLIST_HEAD_INITIALIZER(memory_client_list);

static void cpu_notify_set_memory(target_phys_addr_t start_addr,
                                  ram_addr_t size,
                                  ram_addr_t phys_offset,
                                  bool log_dirty)
{
    CPUPhysMemoryClient *client;
    QLIST_FOREACH(client, &memory_client_list, list) {
        client->set_memory(client, start_addr, size, phys_offset, log_dirty);
    }
}

static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start,
                                        target_phys_addr_t end)
{
    CPUPhysMemoryClient *client;
    QLIST_FOREACH(client, &memory_client_list, list) {
        int r = client->sync_dirty_bitmap(client, start, end);
        if (r < 0)
            return r;
    }
    return 0;
}

static int cpu_notify_migration_log(int enable)
{
    CPUPhysMemoryClient *client;
    QLIST_FOREACH(client, &memory_client_list, list) {
        int r = client->migration_log(client, enable);
        if (r < 0)
            return r;
    }
    return 0;
}

struct last_map {
    target_phys_addr_t start_addr;
    ram_addr_t size;
    ram_addr_t phys_offset;
};

/* The l1_phys_map provides the upper P_L1_BITs of the guest physical
 * address.  Each intermediate table provides the next L2_BITs of guest
 * physical address space.  The number of levels vary based on host and
 * guest configuration, making it efficient to build the final guest
 * physical address by seeding the L1 offset and shifting and adding in
 * each L2 offset as we recurse through them. */
static void phys_page_for_each_1(CPUPhysMemoryClient *client, int level,
                                 void **lp, target_phys_addr_t addr,
                                 struct last_map *map)
{
    int i;

    if (*lp == NULL) {
        return;
    }
    if (level == 0) {
        PhysPageDesc *pd = *lp;
        addr <<= L2_BITS + TARGET_PAGE_BITS;
        for (i = 0; i < L2_SIZE; ++i) {
            if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
                target_phys_addr_t start_addr = addr | i << TARGET_PAGE_BITS;

                if (map->size &&
                    start_addr == map->start_addr + map->size &&
                    pd[i].phys_offset == map->phys_offset + map->size) {

                    map->size += TARGET_PAGE_SIZE;
                    continue;
                } else if (map->size) {
                    client->set_memory(client, map->start_addr,
                                       map->size, map->phys_offset, false);
                }

                map->start_addr = start_addr;
                map->size = TARGET_PAGE_SIZE;
                map->phys_offset = pd[i].phys_offset;
            }
        }
    } else {
        void **pp = *lp;
        for (i = 0; i < L2_SIZE; ++i) {
            phys_page_for_each_1(client, level - 1, pp + i,
                                 (addr << L2_BITS) | i, map);
        }
    }
}

static void phys_page_for_each(CPUPhysMemoryClient *client)
{
    int i;
    struct last_map map = { };

    for (i = 0; i < P_L1_SIZE; ++i) {
        phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
                             l1_phys_map + i, i, &map);
    }
    if (map.size) {
        client->set_memory(client, map.start_addr, map.size, map.phys_offset,
                           false);
    }
}

void cpu_register_phys_memory_client(CPUPhysMemoryClient *client)
{
    QLIST_INSERT_HEAD(&memory_client_list, client, list);
    phys_page_for_each(client);
}

void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client)
{
    QLIST_REMOVE(client, list);
}
#endif

static int cmp1(const char *s1, int n, const char *s2)
{
    if (strlen(s2) != n)
@@ -2126,7 +2008,11 @@ int cpu_physical_memory_set_dirty_tracking(int enable)
{
    int ret = 0;
    in_migration = enable;
    ret = cpu_notify_migration_log(!!enable);
    if (enable) {
        memory_global_dirty_log_start();
    } else {
        memory_global_dirty_log_stop();
    }
    return ret;
}

@@ -2135,45 +2021,6 @@ int cpu_physical_memory_get_dirty_tracking(void)
    return in_migration;
}

int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
                                   target_phys_addr_t end_addr)
{
    int ret;

    ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr);
    return ret;
}

int cpu_physical_log_start(target_phys_addr_t start_addr,
                           ram_addr_t size)
{
    CPUPhysMemoryClient *client;
    QLIST_FOREACH(client, &memory_client_list, list) {
        if (client->log_start) {
            int r = client->log_start(client, start_addr, size);
            if (r < 0) {
                return r;
            }
        }
    }
    return 0;
}

int cpu_physical_log_stop(target_phys_addr_t start_addr,
                          ram_addr_t size)
{
    CPUPhysMemoryClient *client;
    QLIST_FOREACH(client, &memory_client_list, list) {
        if (client->log_stop) {
            int r = client->log_stop(client, start_addr, size);
            if (r < 0) {
                return r;
            }
        }
    }
    return 0;
}

static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
{
    ram_addr_t ram_addr;
@@ -2676,7 +2523,6 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
    subpage_t *subpage;

    assert(size);
    cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);

    if (phys_offset == IO_MEM_UNASSIGNED) {
        region_offset = start_addr;
@@ -2749,17 +2595,6 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
    }
}

/* XXX: temporary until new memory mapping API */
ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
{
    PhysPageDesc *p;

    p = phys_page_find(addr >> TARGET_PAGE_BITS);
    if (!p)
        return IO_MEM_UNASSIGNED;
    return p->phys_offset;
}

void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
{
    if (kvm_enabled())
+14 −18
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
   
void framebuffer_update_display(
    DisplayState *ds,
    MemoryRegion *address_space,
    target_phys_addr_t base,
    int cols, /* Width in pixels.  */
    int rows, /* Leight in pixels.  */
@@ -42,28 +43,22 @@ void framebuffer_update_display(
    int dirty;
    int i;
    ram_addr_t addr;
    ram_addr_t pd;
    ram_addr_t pd2;
    MemoryRegionSection mem_section;
    MemoryRegion *mem;

    i = *first_row;
    *first_row = -1;
    src_len = src_width * rows;

    cpu_physical_sync_dirty_bitmap(base, base + src_len);
    pd = cpu_get_physical_page_desc(base);
    pd2 = cpu_get_physical_page_desc(base + src_len - 1);
    /* We should reall check that this is a continuous ram region.
       Instead we just check that the first and last pages are
       both ram, and the right distance apart.  */
    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM
        || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
        return;
    }
    pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK);
    if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) {
    mem_section = memory_region_find(address_space, base, src_len);
    if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
        return;
    }
    mem = mem_section.mr;
    assert(mem);
    assert(mem_section.offset_within_address_space == base);

    memory_region_sync_dirty_bitmap(mem);
    src_base = cpu_physical_memory_map(base, &src_len, 0);
    /* If we can't map the framebuffer then bail.  We could try harder,
       but it's not really worth it as dirty flag tracking will probably
@@ -82,7 +77,7 @@ void framebuffer_update_display(
        dest -= dest_row_pitch * (rows - 1);
    }
    first = -1;
    addr = pd;
    addr = mem_section.offset_within_region;

    addr += i * src_width;
    src += i * src_width;
@@ -93,8 +88,8 @@ void framebuffer_update_display(
        dirty = 0;
        dirty_offset = 0;
        while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
            dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset,
                                                   VGA_DIRTY_FLAG);
            dirty |= memory_region_get_dirty(mem, addr + dirty_offset,
                                             DIRTY_MEMORY_VGA);
            dirty_offset += TARGET_PAGE_SIZE;
        }

@@ -112,7 +107,8 @@ void framebuffer_update_display(
    if (first < 0) {
        return;
    }
    cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG);
    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
                              DIRTY_MEMORY_VGA);
    *first_row = first;
    *last_row = last;
    return;
Loading