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 <avi@redhat.com>
This commit is contained in:
		
							parent
							
								
									86e775c654
								
							
						
					
					
						commit
						7664e80c84
					
				
							
								
								
									
										5
									
								
								exec.c
								
								
								
								
							
							
						
						
									
										5
									
								
								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)
 | 
					static int cpu_notify_migration_log(int enable)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUPhysMemoryClient *client;
 | 
					    CPUPhysMemoryClient *client;
 | 
				
			||||||
 | 
					    if (enable) {
 | 
				
			||||||
 | 
					        memory_global_dirty_log_start();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        memory_global_dirty_log_stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    QLIST_FOREACH(client, &memory_client_list, list) {
 | 
					    QLIST_FOREACH(client, &memory_client_list, list) {
 | 
				
			||||||
        int r = client->migration_log(client, enable);
 | 
					        int r = client->migration_log(client, enable);
 | 
				
			||||||
        if (r < 0)
 | 
					        if (r < 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										93
									
								
								memory.c
								
								
								
								
							
							
						
						
									
										93
									
								
								memory.c
								
								
								
								
							| 
						 | 
					@ -23,6 +23,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned memory_region_transaction_depth = 0;
 | 
					unsigned memory_region_transaction_depth = 0;
 | 
				
			||||||
static bool memory_region_update_pending = false;
 | 
					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;
 | 
					typedef struct AddrRange AddrRange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -697,6 +701,32 @@ static void address_space_update_ioeventfds(AddressSpace *as)
 | 
				
			||||||
    as->ioeventfd_nb = ioeventfd_nb;
 | 
					    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,
 | 
					static void address_space_update_topology_pass(AddressSpace *as,
 | 
				
			||||||
                                               FlatView old_view,
 | 
					                                               FlatView old_view,
 | 
				
			||||||
                                               FlatView new_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). */
 | 
					            /* In old, but (not in new, or in new but attributes changed). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!adding) {
 | 
					            if (!adding) {
 | 
				
			||||||
 | 
					                MEMORY_LISTENER_UPDATE_REGION(frold, as, region_del);
 | 
				
			||||||
                as->ops->range_del(as, frold);
 | 
					                as->ops->range_del(as, frold);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -738,9 +769,11 @@ static void address_space_update_topology_pass(AddressSpace *as,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (adding) {
 | 
					            if (adding) {
 | 
				
			||||||
                if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
 | 
					                if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
 | 
				
			||||||
 | 
					                    MEMORY_LISTENER_UPDATE_REGION(frold, as, log_stop);
 | 
				
			||||||
                    as->ops->log_stop(as, frnew);
 | 
					                    as->ops->log_stop(as, frnew);
 | 
				
			||||||
                } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
 | 
					                } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
 | 
				
			||||||
                    as->ops->log_start(as, frnew);
 | 
					                    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) {
 | 
					            if (adding) {
 | 
				
			||||||
                as->ops->range_add(as, frnew);
 | 
					                as->ops->range_add(as, frnew);
 | 
				
			||||||
 | 
					                MEMORY_LISTENER_UPDATE_REGION(frold, as, region_add);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ++inew;
 | 
					            ++inew;
 | 
				
			||||||
| 
						 | 
					@ -1130,6 +1164,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
 | 
					    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
 | 
				
			||||||
        if (fr->mr == mr) {
 | 
					        if (fr->mr == mr) {
 | 
				
			||||||
 | 
					            MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync);
 | 
				
			||||||
            cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start),
 | 
					            cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start),
 | 
				
			||||||
                                           int128_get64(addrrange_end(fr->addr)));
 | 
					                                           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)
 | 
					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);
 | 
					    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)
 | 
					void set_system_memory_map(MemoryRegion *mr)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										47
									
								
								memory.h
								
								
								
								
							
							
						
						
									
										47
									
								
								memory.h
								
								
								
								
							| 
						 | 
					@ -154,6 +154,7 @@ typedef struct MemoryRegionSection MemoryRegionSection;
 | 
				
			||||||
 * MemoryRegionSection: describes a fragment of a #MemoryRegion
 | 
					 * MemoryRegionSection: describes a fragment of a #MemoryRegion
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @mr: the region, or %NULL if empty
 | 
					 * @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
 | 
					 * @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
 | 
					 * @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
 | 
					 * @offset_within_address_space: the address of the first byte of the section
 | 
				
			||||||
| 
						 | 
					@ -161,11 +162,31 @@ typedef struct MemoryRegionSection MemoryRegionSection;
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct MemoryRegionSection {
 | 
					struct MemoryRegionSection {
 | 
				
			||||||
    MemoryRegion *mr;
 | 
					    MemoryRegion *mr;
 | 
				
			||||||
 | 
					    MemoryRegion *address_space;
 | 
				
			||||||
    target_phys_addr_t offset_within_region;
 | 
					    target_phys_addr_t offset_within_region;
 | 
				
			||||||
    uint64_t size;
 | 
					    uint64_t size;
 | 
				
			||||||
    target_phys_addr_t offset_within_address_space;
 | 
					    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
 | 
					 * memory_region_init: Initialize a memory region
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -631,6 +652,32 @@ void memory_region_transaction_begin(void);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void memory_region_transaction_commit(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);
 | 
					void mtree_info(fprintf_function mon_printf, void *f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue