From 8ea9252abe08631611effb905fbb4a015ec1514c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 15:58:43 +0200 Subject: memory: add memory_region_is_ram() Signed-off-by: Avi Kivity --- memory.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'memory.c') diff --git a/memory.c b/memory.c index a7e615ad15..4264b42222 100644 --- a/memory.c +++ b/memory.c @@ -832,6 +832,7 @@ void memory_region_init(MemoryRegion *mr, mr->offset = 0; mr->enabled = true; mr->terminates = false; + mr->ram = false; mr->readable = true; mr->readonly = false; mr->destructor = memory_region_destructor_none; @@ -998,6 +999,7 @@ void memory_region_init_ram(MemoryRegion *mr, uint64_t size) { memory_region_init(mr, name, size); + mr->ram = true; mr->terminates = true; mr->destructor = memory_region_destructor_ram; mr->ram_addr = qemu_ram_alloc(dev, name, size, mr); @@ -1011,6 +1013,7 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, void *ptr) { memory_region_init(mr, name, size); + mr->ram = true; mr->terminates = true; mr->destructor = memory_region_destructor_ram_from_ptr; mr->ram_addr = qemu_ram_alloc_from_ptr(dev, name, size, ptr, mr); @@ -1066,6 +1069,11 @@ uint64_t memory_region_size(MemoryRegion *mr) return int128_get64(mr->size); } +bool memory_region_is_ram(MemoryRegion *mr) +{ + return mr->ram; +} + void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset) { mr->offset = offset; -- cgit v1.2.3-55-g7522 From ce7923da4da4e5895ab737fbf2c9b603c764a933 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 16:05:11 +0200 Subject: memory: add memory_region_is_rom() Signed-off-by: Avi Kivity --- memory.c | 5 +++++ memory.h | 9 +++++++++ 2 files changed, 14 insertions(+) (limited to 'memory.c') diff --git a/memory.c b/memory.c index 4264b42222..01baeacf3c 100644 --- a/memory.c +++ b/memory.c @@ -1074,6 +1074,11 @@ bool memory_region_is_ram(MemoryRegion *mr) return mr->ram; } +bool memory_region_is_rom(MemoryRegion *mr) +{ + return mr->ram && mr->readonly; +} + void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset) { mr->offset = offset; diff --git a/memory.h b/memory.h index dccc9007df..91d6e8aef5 100644 --- a/memory.h +++ b/memory.h @@ -276,6 +276,15 @@ uint64_t memory_region_size(MemoryRegion *mr); */ bool memory_region_is_ram(MemoryRegion *mr); +/** + * memory_region_is_rom: check whether a memory region is ROM + * + * Returns %true is a memory region is read-only memory. + * + * @mr: the memory region being queried + */ +bool memory_region_is_rom(MemoryRegion *mr); + /** * memory_region_get_ram_ptr: Get a pointer into a RAM memory region. * -- cgit v1.2.3-55-g7522 From 55043ba37ee4b080a4f4f77b0ff672be3cbf8825 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 17:20:34 +0200 Subject: memory: add memory_region_is_logging() Signed-off-by: Avi Kivity --- memory.c | 5 +++++ memory.h | 9 +++++++++ 2 files changed, 14 insertions(+) (limited to 'memory.c') diff --git a/memory.c b/memory.c index 01baeacf3c..6e6163524b 100644 --- a/memory.c +++ b/memory.c @@ -1074,6 +1074,11 @@ bool memory_region_is_ram(MemoryRegion *mr) return mr->ram; } +bool memory_region_is_logging(MemoryRegion *mr) +{ + return mr->dirty_log_mask; +} + bool memory_region_is_rom(MemoryRegion *mr) { return mr->ram && mr->readonly; diff --git a/memory.h b/memory.h index 91d6e8aef5..87fb9740c7 100644 --- a/memory.h +++ b/memory.h @@ -276,6 +276,15 @@ uint64_t memory_region_size(MemoryRegion *mr); */ bool memory_region_is_ram(MemoryRegion *mr); +/** + * memory_region_is_logging: return whether a memory region is logging writes + * + * Returns %true if the memory region is logging writes + * + * @mr: the memory region being queried + */ +bool memory_region_is_logging(MemoryRegion *mr); + /** * memory_region_is_rom: check whether a memory region is ROM * -- cgit v1.2.3-55-g7522 From e2177955a899483b19bd54e547db3b61db95eaf7 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 15:00:18 +0200 Subject: memory: introduce memory_region_find() Given an address space (represented by the top-level memory region), returns the memory region that maps a given range. Useful for implementing DMA. The implementation is a simplistic binary search. Once we have a tree representation this can be optimized. Signed-off-by: Avi Kivity --- memory.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ memory.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) (limited to 'memory.c') diff --git a/memory.c b/memory.c index 6e6163524b..c3e64ba138 100644 --- a/memory.c +++ b/memory.c @@ -515,6 +515,20 @@ static AddressSpace address_space_io = { .ops = &address_space_ops_io, }; +static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) +{ + while (mr->parent) { + mr = mr->parent; + } + if (mr == address_space_memory.root) { + return &address_space_memory; + } + if (mr == address_space_io.root) { + return &address_space_io; + } + abort(); +} + /* Render a memory region into the global view. Ranges in @view obscure * ranges in @mr. */ @@ -1386,6 +1400,54 @@ void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset) memory_region_update_topology(mr); } +static int cmp_flatrange_addr(const void *addr_, const void *fr_) +{ + const AddrRange *addr = addr_; + const FlatRange *fr = fr_; + + if (int128_le(addrrange_end(*addr), fr->addr.start)) { + return -1; + } else if (int128_ge(addr->start, addrrange_end(fr->addr))) { + return 1; + } + return 0; +} + +static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr) +{ + return bsearch(&addr, as->current_map.ranges, as->current_map.nr, + sizeof(FlatRange), cmp_flatrange_addr); +} + +MemoryRegionSection memory_region_find(MemoryRegion *address_space, + target_phys_addr_t addr, uint64_t size) +{ + AddressSpace *as = memory_region_to_address_space(address_space); + AddrRange range = addrrange_make(int128_make64(addr), + int128_make64(size)); + FlatRange *fr = address_space_lookup(as, range); + MemoryRegionSection ret = { .mr = NULL, .size = 0 }; + + if (!fr) { + return ret; + } + + while (fr > as->current_map.ranges + && addrrange_intersects(fr[-1].addr, range)) { + --fr; + } + + ret.mr = fr->mr; + range = addrrange_intersection(range, fr->addr); + ret.offset_within_region = fr->offset_in_region; + ret.offset_within_region += int128_get64(int128_sub(range.start, + fr->addr.start)); + ret.size = int128_get64(range.size); + ret.offset_within_address_space = int128_get64(range.start); + return ret; +} + + void set_system_memory_map(MemoryRegion *mr) { address_space_memory.root = mr; diff --git a/memory.h b/memory.h index 87fb9740c7..4d8f39ad09 100644 --- a/memory.h +++ b/memory.h @@ -148,6 +148,24 @@ struct MemoryRegionPortio { #define PORTIO_END_OF_LIST() { } +typedef struct MemoryRegionSection MemoryRegionSection; + +/** + * MemoryRegionSection: describes a fragment of a #MemoryRegion + * + * @mr: the region, or %NULL if empty + * @offset_within_region: the beginning of the section, relative to @mr's start + * @size: the size of the section; will not exceed @mr's boundaries + * @offset_within_address_space: the address of the first byte of the section + * relative to the region's address space + */ +struct MemoryRegionSection { + MemoryRegion *mr; + target_phys_addr_t offset_within_region; + uint64_t size; + target_phys_addr_t offset_within_address_space; +}; + /** * memory_region_init: Initialize a memory region * @@ -568,6 +586,27 @@ void memory_region_set_address(MemoryRegion *mr, target_phys_addr_t addr); void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset); +/** + * memory_region_find: locate a MemoryRegion in an address space + * + * Locates the first #MemoryRegion within an address space given by + * @address_space that overlaps the range given by @addr and @size. + * + * Returns a #MemoryRegionSection that describes a contiguous overlap. + * It will have the following characteristics: + * .@offset_within_address_space >= @addr + * .@offset_within_address_space + .@size <= @addr + @size + * .@size = 0 iff no overlap was found + * .@mr is non-%NULL iff an overlap was found + * + * @address_space: a top-level (i.e. parentless) region that contains + * the region to be found + * @addr: start of the area within @address_space to be searched + * @size: size of the area to be searched + */ +MemoryRegionSection memory_region_find(MemoryRegion *address_space, + target_phys_addr_t addr, uint64_t size); + /** * memory_region_transaction_begin: Start a transaction. * -- cgit v1.2.3-55-g7522 From 86e775c654b775d3e295e8a33bb03cc03bdab68d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 16:24:49 +0200 Subject: memory: replace cpu_physical_sync_dirty_bitmap() with a memory API The function is still used as the implementation. Signed-off-by: Avi Kivity --- arch_init.c | 6 ++---- cpu-all.h | 3 --- exec-obsolete.h | 3 +++ memory.c | 4 ++++ memory.h | 10 ++++++++++ 5 files changed, 19 insertions(+), 7 deletions(-) (limited to 'memory.c') diff --git a/arch_init.c b/arch_init.c index a411fdf263..ceef26ef17 100644 --- a/arch_init.c +++ b/arch_init.c @@ -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; diff --git a/cpu-all.h b/cpu-all.h index 9d787151e1..f2c53827ef 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -569,9 +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); diff --git a/exec-obsolete.h b/exec-obsolete.h index 34b9fc56bd..5e5c4c63fb 100644 --- a/exec-obsolete.h +++ b/exec-obsolete.h @@ -63,6 +63,9 @@ static inline void cpu_register_physical_memory(target_phys_addr_t start_addr, void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + #endif #endif diff --git a/memory.c b/memory.c index c3e64ba138..ef5d647acc 100644 --- a/memory.c +++ b/memory.c @@ -1447,6 +1447,10 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, return ret; } +void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) +{ + cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX); +} void set_system_memory_map(MemoryRegion *mr) { diff --git a/memory.h b/memory.h index 4d8f39ad09..8197b45804 100644 --- a/memory.h +++ b/memory.h @@ -607,6 +607,16 @@ void memory_region_set_alias_offset(MemoryRegion *mr, MemoryRegionSection memory_region_find(MemoryRegion *address_space, target_phys_addr_t addr, uint64_t size); + +/** + * memory_global_sync_dirty_bitmap: synchronize the dirty log for all memory + * + * Synchronizes the dirty page log for an entire address space. + * @address_space: a top-level (i.e. parentless) region that contains the + * memory being synchronized + */ +void memory_global_sync_dirty_bitmap(MemoryRegion *address_space); + /** * memory_region_transaction_begin: Start a transaction. * -- cgit v1.2.3-55-g7522 From 7664e80c84700d8b7e88ae854d1d74806c63f013 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 11 Dec 2011 14:47:25 +0200 Subject: memory: add API for observing updates to the physical memory map Add an API that allows a client to observe changes in the global memory map: - region added (possibly with logging enabled) - region removed (possibly with logging enabled) - logging started on a region - logging stopped on a region - global logging started - global logging removed This API will eventually replace cpu_register_physical_memory_client(). Signed-off-by: Avi Kivity --- exec.c | 5 ++++ memory.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ memory.h | 47 ++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) (limited to 'memory.c') diff --git a/exec.c b/exec.c index 32782b48c9..36b61c91ac 100644 --- a/exec.c +++ b/exec.c @@ -1762,6 +1762,11 @@ static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start, static int cpu_notify_migration_log(int enable) { CPUPhysMemoryClient *client; + if (enable) { + memory_global_dirty_log_start(); + } else { + memory_global_dirty_log_stop(); + } QLIST_FOREACH(client, &memory_client_list, list) { int r = client->migration_log(client, enable); if (r < 0) diff --git a/memory.c b/memory.c index ef5d647acc..61e324bbf9 100644 --- a/memory.c +++ b/memory.c @@ -23,6 +23,10 @@ unsigned memory_region_transaction_depth = 0; static bool memory_region_update_pending = false; +static bool global_dirty_log = false; + +static QLIST_HEAD(, MemoryListener) memory_listeners + = QLIST_HEAD_INITIALIZER(memory_listeners); typedef struct AddrRange AddrRange; @@ -697,6 +701,32 @@ static void address_space_update_ioeventfds(AddressSpace *as) as->ioeventfd_nb = ioeventfd_nb; } +typedef void ListenerCallback(MemoryListener *listener, + MemoryRegionSection *mrs); + +/* Want "void (&MemoryListener::*callback)(const MemoryRegionSection& s)" */ +static void memory_listener_update_region(FlatRange *fr, AddressSpace *as, + size_t callback_offset) +{ + MemoryRegionSection section = { + .mr = fr->mr, + .address_space = as->root, + .offset_within_region = fr->offset_in_region, + .size = int128_get64(fr->addr.size), + .offset_within_address_space = int128_get64(fr->addr.start), + }; + MemoryListener *listener; + + QLIST_FOREACH(listener, &memory_listeners, link) { + ListenerCallback *callback + = *(ListenerCallback **)((void *)listener + callback_offset); + callback(listener, §ion); + } +} + +#define MEMORY_LISTENER_UPDATE_REGION(fr, as, callback) \ + memory_listener_update_region(fr, as, offsetof(MemoryListener, callback)) + static void address_space_update_topology_pass(AddressSpace *as, FlatView old_view, FlatView new_view, @@ -729,6 +759,7 @@ static void address_space_update_topology_pass(AddressSpace *as, /* In old, but (not in new, or in new but attributes changed). */ if (!adding) { + MEMORY_LISTENER_UPDATE_REGION(frold, as, region_del); as->ops->range_del(as, frold); } @@ -738,9 +769,11 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { if (frold->dirty_log_mask && !frnew->dirty_log_mask) { + MEMORY_LISTENER_UPDATE_REGION(frold, as, log_stop); as->ops->log_stop(as, frnew); } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) { as->ops->log_start(as, frnew); + MEMORY_LISTENER_UPDATE_REGION(frold, as, log_start); } } @@ -751,6 +784,7 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { as->ops->range_add(as, frnew); + MEMORY_LISTENER_UPDATE_REGION(frold, as, region_add); } ++inew; @@ -1130,6 +1164,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { + MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync); cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), int128_get64(addrrange_end(fr->addr))); } @@ -1449,7 +1484,65 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) { + AddressSpace *as = memory_region_to_address_space(address_space); + FlatRange *fr; + cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX); + FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync); + } +} + +void memory_global_dirty_log_start(void) +{ + MemoryListener *listener; + + global_dirty_log = true; + QLIST_FOREACH(listener, &memory_listeners, link) { + listener->log_global_start(listener); + } +} + +void memory_global_dirty_log_stop(void) +{ + MemoryListener *listener; + + global_dirty_log = false; + QLIST_FOREACH(listener, &memory_listeners, link) { + listener->log_global_stop(listener); + } +} + +static void listener_add_address_space(MemoryListener *listener, + AddressSpace *as) +{ + FlatRange *fr; + + if (global_dirty_log) { + listener->log_global_start(listener); + } + FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + MemoryRegionSection section = { + .mr = fr->mr, + .address_space = as->root, + .offset_within_region = fr->offset_in_region, + .size = int128_get64(fr->addr.size), + .offset_within_address_space = int128_get64(fr->addr.start), + }; + listener->region_add(listener, §ion); + } +} + +void memory_listener_register(MemoryListener *listener) +{ + QLIST_INSERT_HEAD(&memory_listeners, listener, link); + listener_add_address_space(listener, &address_space_memory); + listener_add_address_space(listener, &address_space_io); +} + +void memory_listener_unregister(MemoryListener *listener) +{ + QLIST_REMOVE(listener, link); } void set_system_memory_map(MemoryRegion *mr) diff --git a/memory.h b/memory.h index 8197b45804..5ba874e821 100644 --- a/memory.h +++ b/memory.h @@ -154,6 +154,7 @@ typedef struct MemoryRegionSection MemoryRegionSection; * MemoryRegionSection: describes a fragment of a #MemoryRegion * * @mr: the region, or %NULL if empty + * @address_space: the address space the region is mapped in * @offset_within_region: the beginning of the section, relative to @mr's start * @size: the size of the section; will not exceed @mr's boundaries * @offset_within_address_space: the address of the first byte of the section @@ -161,11 +162,31 @@ typedef struct MemoryRegionSection MemoryRegionSection; */ struct MemoryRegionSection { MemoryRegion *mr; + MemoryRegion *address_space; target_phys_addr_t offset_within_region; uint64_t size; target_phys_addr_t offset_within_address_space; }; +typedef struct MemoryListener MemoryListener; + +/** + * MemoryListener: callbacks structure for updates to the physical memory map + * + * Allows a component to adjust to changes in the guest-visible memory map. + * Use with memory_listener_register() and memory_listener_unregister(). + */ +struct MemoryListener { + void (*region_add)(MemoryListener *listener, MemoryRegionSection *section); + void (*region_del)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_start)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_global_start)(MemoryListener *listener); + void (*log_global_stop)(MemoryListener *listener); + QLIST_ENTRY(MemoryListener) link; +}; + /** * memory_region_init: Initialize a memory region * @@ -631,6 +652,32 @@ void memory_region_transaction_begin(void); */ void memory_region_transaction_commit(void); +/** + * memory_listener_register: register callbacks to be called when memory + * sections are mapped or unmapped into an address + * space + * + * @listener: an object containing the callbacks to be called + */ +void memory_listener_register(MemoryListener *listener); + +/** + * memory_listener_unregister: undo the effect of memory_listener_register() + * + * @listener: an object containing the callbacks to be removed + */ +void memory_listener_unregister(MemoryListener *listener); + +/** + * memory_global_dirty_log_start: begin dirty logging for all regions + */ +void memory_global_dirty_log_start(void); + +/** + * memory_global_dirty_log_stop: begin dirty logging for all regions + */ +void memory_global_dirty_log_stop(void); + void mtree_info(fprintf_function mon_printf, void *f); #endif -- cgit v1.2.3-55-g7522 From 9f213ed92c5ccc3d0aa19359bb1783760d01dae9 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 19:55:26 +0200 Subject: kvm: switch kvm slots to use host virtual address instead of ram_addr_t This simplifies a later switch to the memory API in slot management. Signed-off-by: Avi Kivity --- kvm-all.c | 29 +++++++++++++++++------------ kvm.h | 4 ++-- memory.c | 6 +++--- target-i386/kvm.c | 7 +++---- 4 files changed, 25 insertions(+), 21 deletions(-) (limited to 'memory.c') diff --git a/kvm-all.c b/kvm-all.c index ac048bce50..8d8f31e60d 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -50,7 +50,7 @@ typedef struct KVMSlot { target_phys_addr_t start_addr; ram_addr_t memory_size; - ram_addr_t phys_offset; + void *ram; int slot; int flags; } KVMSlot; @@ -146,17 +146,16 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s, return found; } -int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr, - target_phys_addr_t *phys_addr) +int kvm_physical_memory_addr_from_host(KVMState *s, void *ram, + target_phys_addr_t *phys_addr) { int i; for (i = 0; i < ARRAY_SIZE(s->slots); i++) { KVMSlot *mem = &s->slots[i]; - if (ram_addr >= mem->phys_offset && - ram_addr < mem->phys_offset + mem->memory_size) { - *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset); + if (ram >= mem->ram && ram < mem->ram + mem->memory_size) { + *phys_addr = mem->start_addr + (ram - mem->ram); return 1; } } @@ -171,7 +170,7 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) mem.slot = slot->slot; mem.guest_phys_addr = slot->start_addr; mem.memory_size = slot->memory_size; - mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset); + mem.userspace_addr = (unsigned long)slot->ram; mem.flags = slot->flags; if (s->migration_log) { mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; @@ -527,6 +526,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; KVMSlot *mem, old; int err; + void *ram = NULL; /* kvm works in page size chunks, but the function may be called with sub-page size and unaligned start address. */ @@ -536,6 +536,10 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, /* KVM does not support read-only slots */ phys_offset &= ~IO_MEM_ROM; + if ((phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + ram = qemu_safe_ram_ptr(phys_offset); + } + while (1) { mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); if (!mem) { @@ -544,7 +548,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && (start_addr + size <= mem->start_addr + mem->memory_size) && - (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { + (ram - start_addr == mem->ram - mem->start_addr)) { /* The new slot fits into the existing one and comes with * identical parameters - update flags and done. */ kvm_slot_dirty_pages_log_change(mem, log_dirty); @@ -576,7 +580,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, mem = kvm_alloc_slot(s); mem->memory_size = old.memory_size; mem->start_addr = old.start_addr; - mem->phys_offset = old.phys_offset; + mem->ram = old.ram; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -588,6 +592,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, start_addr += old.memory_size; phys_offset += old.memory_size; + ram += old.memory_size; size -= old.memory_size; continue; } @@ -597,7 +602,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, mem = kvm_alloc_slot(s); mem->memory_size = start_addr - old.start_addr; mem->start_addr = old.start_addr; - mem->phys_offset = old.phys_offset; + mem->ram = old.ram; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -621,7 +626,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, mem->start_addr = start_addr + size; size_delta = mem->start_addr - old.start_addr; mem->memory_size = old.memory_size - size_delta; - mem->phys_offset = old.phys_offset + size_delta; + mem->ram = old.ram + size_delta; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -644,7 +649,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, mem = kvm_alloc_slot(s); mem->memory_size = size; mem->start_addr = start_addr; - mem->phys_offset = phys_offset; + mem->ram = ram; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); diff --git a/kvm.h b/kvm.h index 243b063f92..c1de81a11c 100644 --- a/kvm.h +++ b/kvm.h @@ -188,8 +188,8 @@ static inline void cpu_synchronize_post_init(CPUState *env) #if !defined(CONFIG_USER_ONLY) -int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr, - target_phys_addr_t *phys_addr); +int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, + target_phys_addr_t *phys_addr); #endif #endif diff --git a/memory.c b/memory.c index 61e324bbf9..9e3f87a110 100644 --- a/memory.c +++ b/memory.c @@ -769,11 +769,11 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { if (frold->dirty_log_mask && !frnew->dirty_log_mask) { - MEMORY_LISTENER_UPDATE_REGION(frold, as, log_stop); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_stop); as->ops->log_stop(as, frnew); } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) { as->ops->log_start(as, frnew); - MEMORY_LISTENER_UPDATE_REGION(frold, as, log_start); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_start); } } @@ -784,7 +784,7 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { as->ops->range_add(as, frnew); - MEMORY_LISTENER_UPDATE_REGION(frold, as, region_add); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, region_add); } ++inew; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5bfc21fc53..74d81efbd1 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -253,8 +253,7 @@ int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) if ((env->mcg_cap & MCG_SER_P) && addr && (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO)) { if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, - &paddr)) { + !kvm_physical_memory_addr_from_host(env->kvm_state, addr, &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!\n"); /* Hope we are lucky for AO MCE */ @@ -286,8 +285,8 @@ int kvm_arch_on_sigbus(int code, void *addr) /* Hope we are lucky for AO MCE */ if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, - &paddr)) { + !kvm_physical_memory_addr_from_host(first_cpu->kvm_state, addr, + &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!: %p\n", addr); return 0; -- cgit v1.2.3-55-g7522 From e34911c420c617151fe5bc95a4b6f269cca0483b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 12:06:23 +0200 Subject: memory: temporarily add memory_region_get_ram_addr() This is a layering violation, but needed while the code contains naked calls to qemu_get_ram_ptr() and the like. Signed-off-by: Avi Kivity --- memory.c | 6 ++++++ memory.h | 10 ++++++++++ 2 files changed, 16 insertions(+) (limited to 'memory.c') diff --git a/memory.c b/memory.c index 9e3f87a110..6a637d4e5b 100644 --- a/memory.c +++ b/memory.c @@ -1435,6 +1435,12 @@ void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset) memory_region_update_topology(mr); } +ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr) +{ + assert(mr->backend_registered); + return mr->ram_addr; +} + static int cmp_flatrange_addr(const void *addr_, const void *fr_) { const AddrRange *addr = addr_; diff --git a/memory.h b/memory.h index 5ba874e821..a82226a752 100644 --- a/memory.h +++ b/memory.h @@ -558,6 +558,16 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr, target_phys_addr_t offset, MemoryRegion *subregion, unsigned priority); + +/** + * memory_region_get_ram_addr: Get the ram address associated with a memory + * region + * + * DO NOT USE THIS FUCNTION. This is a temporary workaround while the Xen + * code is being reworked. + */ +ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr); + /** * memory_region_del_subregion: Remove a subregion. * -- cgit v1.2.3-55-g7522 From dcd97e33af43ae0bfa7e8c39ce8cebcfe7af6cb4 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 12:53:48 +0200 Subject: memory: remove CPUPhysMemoryClient No longer used. Signed-off-by: Avi Kivity --- cpu-all.h | 6 -- cpu-common.h | 23 -------- exec-obsolete.h | 3 - exec.c | 169 ++------------------------------------------------------ memory.c | 12 ---- 5 files changed, 5 insertions(+), 208 deletions(-) (limited to 'memory.c') diff --git a/cpu-all.h b/cpu-all.h index f2c53827ef..734833abda 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -569,12 +569,6 @@ int cpu_physical_memory_set_dirty_tracking(int enable); int cpu_physical_memory_get_dirty_tracking(void); -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 */ diff --git a/cpu-common.h b/cpu-common.h index 8295e4fea4..eee2fafe86 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -71,29 +71,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 diff --git a/exec-obsolete.h b/exec-obsolete.h index 5e5c4c63fb..34b9fc56bd 100644 --- a/exec-obsolete.h +++ b/exec-obsolete.h @@ -63,9 +63,6 @@ static inline void cpu_register_physical_memory(target_phys_addr_t start_addr, void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); -int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr); - #endif #endif diff --git a/exec.c b/exec.c index 36b61c91ac..e1f7462eeb 100644 --- a/exec.c +++ b/exec.c @@ -1732,129 +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; - if (enable) { - memory_global_dirty_log_start(); - } else { - memory_global_dirty_log_stop(); - } - 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) @@ -2131,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; } @@ -2140,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; @@ -2681,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; diff --git a/memory.c b/memory.c index 6a637d4e5b..a90eefd8d1 100644 --- a/memory.c +++ b/memory.c @@ -338,11 +338,6 @@ static void as_memory_range_add(AddressSpace *as, FlatRange *fr) static void as_memory_range_del(AddressSpace *as, FlatRange *fr) { - if (fr->dirty_log_mask) { - Int128 end = addrrange_end(fr->addr); - cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), - int128_get64(end)); - } cpu_register_physical_memory(int128_get64(fr->addr.start), int128_get64(fr->addr.size), IO_MEM_UNASSIGNED); @@ -350,14 +345,10 @@ static void as_memory_range_del(AddressSpace *as, FlatRange *fr) static void as_memory_log_start(AddressSpace *as, FlatRange *fr) { - cpu_physical_log_start(int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); } static void as_memory_log_stop(AddressSpace *as, FlatRange *fr) { - cpu_physical_log_stop(int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); } static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd) @@ -1165,8 +1156,6 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync); - cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), - int128_get64(addrrange_end(fr->addr))); } } } @@ -1493,7 +1482,6 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) AddressSpace *as = memory_region_to_address_space(address_space); FlatRange *fr; - cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX); FOR_EACH_FLAT_RANGE(fr, &as->current_map) { MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync); } -- cgit v1.2.3-55-g7522