From b82e711a655012c8b0736ebc94a58d22ffba7d37 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Sat, 17 Feb 2018 23:37:43 -0500 Subject: [PATCH] memory: Add address_space_init_shareable() This will either create a new AS or return a pointer to an already existing equivalent one, if we have already created an AS for the specified root memory region. The motivation is to reuse address spaces as much as possible. It's going to be quite common that bus masters out in device land have pointers to the same memory region for their mastering yet each will need to create its own address space. Let the memory API implement sharing for them. Aside from the perf optimisations, this should reduce the amount of redundant output on info mtree as well. Thee returned value will be malloced, but the malloc will be automatically freed when the AS runs out of refs. Backports commit f0c02d15b57da6f5463e3768aa0cfeedccf4b8f4 from qemu --- qemu/aarch64.h | 1 + qemu/aarch64eb.h | 1 + qemu/arm.h | 1 + qemu/armeb.h | 1 + qemu/header_gen.py | 1 + qemu/include/exec/memory.h | 19 +++++++++++ qemu/m68k.h | 1 + qemu/memory.c | 64 ++++++++++++++++++++++++++++++++------ qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/powerpc.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/x86_64.h | 1 + 16 files changed, 88 insertions(+), 9 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index bc7bda24..e1dce13d 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_aarch64 #define address_space_init address_space_init_aarch64 #define address_space_init_dispatch address_space_init_dispatch_aarch64 +#define address_space_init_shareable address_space_init_shareable_aarch64 #define address_space_lookup_region address_space_lookup_region_aarch64 #define address_space_map address_space_map_aarch64 #define address_space_read address_space_read_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 1693d98c..c303099f 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_aarch64eb #define address_space_init address_space_init_aarch64eb #define address_space_init_dispatch address_space_init_dispatch_aarch64eb +#define address_space_init_shareable address_space_init_shareable_aarch64eb #define address_space_lookup_region address_space_lookup_region_aarch64eb #define address_space_map address_space_map_aarch64eb #define address_space_read address_space_read_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index 1948188d..2c127406 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_arm #define address_space_init address_space_init_arm #define address_space_init_dispatch address_space_init_dispatch_arm +#define address_space_init_shareable address_space_init_shareable_arm #define address_space_lookup_region address_space_lookup_region_arm #define address_space_map address_space_map_arm #define address_space_read address_space_read_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index 4c6f3026..b61ed70c 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_armeb #define address_space_init address_space_init_armeb #define address_space_init_dispatch address_space_init_dispatch_armeb +#define address_space_init_shareable address_space_init_shareable_armeb #define address_space_lookup_region address_space_lookup_region_armeb #define address_space_map address_space_map_armeb #define address_space_read address_space_read_armeb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 8267baef..f644c37c 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -97,6 +97,7 @@ symbols = ( 'address_space_get_flatview', 'address_space_init', 'address_space_init_dispatch', + 'address_space_init_shareable', 'address_space_lookup_region', 'address_space_map', 'address_space_read', diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index 893249ab..b0a6289a 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -219,6 +219,8 @@ struct AddressSpace { /* All fields are private. */ char *name; MemoryRegion *root; + int ref_count; + bool malloced; struct FlatView *current_map; struct AddressSpaceDispatch *dispatch; struct AddressSpaceDispatch *next_dispatch; @@ -901,6 +903,23 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr, */ void address_space_init(struct uc_struct *uc, AddressSpace *as, MemoryRegion *root, const char *name); +/** + * address_space_init_shareable: return an address space for a memory region, + * creating it if it does not already exist + * + * @root: a #MemoryRegion that routes addresses for the address space + * @name: an address space name. The name is only used for debugging + * output. + * + * This function will return a pointer to an existing AddressSpace + * which was initialized with the specified MemoryRegion, or it will + * create and initialize one if it does not already exist. The ASes + * are reference-counted, so the memory will be freed automatically + * when the AddressSpace is destroyed via address_space_destroy. + */ +AddressSpace *address_space_init_shareable(struct uc_struct* uc, + MemoryRegion *root, + const char *name); /** * address_space_destroy: destroy an address space diff --git a/qemu/m68k.h b/qemu/m68k.h index 0cd208ef..bf6a87d8 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_m68k #define address_space_init address_space_init_m68k #define address_space_init_dispatch address_space_init_dispatch_m68k +#define address_space_init_shareable address_space_init_shareable_m68k #define address_space_lookup_region address_space_lookup_region_m68k #define address_space_map address_space_map_m68k #define address_space_read address_space_read_m68k diff --git a/qemu/memory.c b/qemu/memory.c index d4b8f977..7be7cd96 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -1679,8 +1679,10 @@ void address_space_init(struct uc_struct *uc, AddressSpace *as, MemoryRegion *ro } memory_region_transaction_begin(uc); + as->ref_count = 1; as->uc = uc; as->root = root; + as->malloced = false; as->current_map = g_new(FlatView, 1); flatview_init(as->current_map); QTAILQ_INSERT_TAIL(&uc->address_spaces, as, address_spaces_link); @@ -1690,9 +1692,53 @@ void address_space_init(struct uc_struct *uc, AddressSpace *as, MemoryRegion *ro memory_region_transaction_commit(uc); } -void address_space_destroy(AddressSpace *as) +static void do_address_space_destroy(AddressSpace *as) { MemoryListener *listener; + bool do_free = as->malloced; + + address_space_destroy_dispatch(as); + + // TODO(danghvu): why assert fail here? + //QTAILQ_FOREACH(listener, &as->uc->memory_listeners, link) { + // assert(listener->address_space_filter != as); + //} + + flatview_unref(as->current_map); + g_free(as->name); + // Unicorn: commented out + //g_free(as->ioeventfds); + memory_region_unref(as->root); + if (do_free) { + g_free(as); + } +} + +AddressSpace *address_space_init_shareable(struct uc_struct *uc, MemoryRegion *root, const char *name) +{ + AddressSpace *as; + + QTAILQ_FOREACH(as, &uc->address_spaces, address_spaces_link) { + if (root == as->root && as->malloced) { + as->ref_count++; + return as; + } + } + + as = g_malloc0(sizeof *as); + address_space_init(uc, as, root, name); + as->malloced = true; + return as; +} + +void address_space_destroy(AddressSpace *as) +{ + MemoryRegion *root = as->root; + + as->ref_count--; + if (as->ref_count) { + return; + } /* Flush out anything from MemoryListeners listening in on this */ memory_region_transaction_begin(as->uc); @@ -1701,15 +1747,15 @@ void address_space_destroy(AddressSpace *as) QTAILQ_REMOVE(&as->uc->address_spaces, as, address_spaces_link); address_space_unregister(as); - address_space_destroy_dispatch(as); + /* At this point, as->dispatch and as->current_map are dummy + * entries that the guest should never use. Wait for the old + * values to expire before freeing the data. + */ + as->root = root; + do_address_space_destroy(as); - // TODO(danghvu): why assert fail here? - QTAILQ_FOREACH(listener, &as->uc->memory_listeners, link) { - // assert(listener->address_space_filter != as); - } - - flatview_unref(as->current_map); - g_free(as->name); + // Unicorn: Commented out and call it directly + // call_rcu(as, do_address_space_destroy, rcu); } typedef struct MemoryRegionList MemoryRegionList; diff --git a/qemu/mips.h b/qemu/mips.h index 81d1dd2f..35853c2c 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_mips #define address_space_init address_space_init_mips #define address_space_init_dispatch address_space_init_dispatch_mips +#define address_space_init_shareable address_space_init_shareable_mips #define address_space_lookup_region address_space_lookup_region_mips #define address_space_map address_space_map_mips #define address_space_read address_space_read_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index e93a1c06..209e4bf0 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_mips64 #define address_space_init address_space_init_mips64 #define address_space_init_dispatch address_space_init_dispatch_mips64 +#define address_space_init_shareable address_space_init_shareable_mips64 #define address_space_lookup_region address_space_lookup_region_mips64 #define address_space_map address_space_map_mips64 #define address_space_read address_space_read_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 45a117e2..763c0f1e 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_mips64el #define address_space_init address_space_init_mips64el #define address_space_init_dispatch address_space_init_dispatch_mips64el +#define address_space_init_shareable address_space_init_shareable_mips64el #define address_space_lookup_region address_space_lookup_region_mips64el #define address_space_map address_space_map_mips64el #define address_space_read address_space_read_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 2d8dd39f..1582aa7b 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_mipsel #define address_space_init address_space_init_mipsel #define address_space_init_dispatch address_space_init_dispatch_mipsel +#define address_space_init_shareable address_space_init_shareable_mipsel #define address_space_lookup_region address_space_lookup_region_mipsel #define address_space_map address_space_map_mipsel #define address_space_read address_space_read_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 7cdcb05e..fbca936e 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_powerpc #define address_space_init address_space_init_powerpc #define address_space_init_dispatch address_space_init_dispatch_powerpc +#define address_space_init_shareable address_space_init_shareable_powerpc #define address_space_lookup_region address_space_lookup_region_powerpc #define address_space_map address_space_map_powerpc #define address_space_read address_space_read_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index fb76eced..c9cc139f 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_sparc #define address_space_init address_space_init_sparc #define address_space_init_dispatch address_space_init_dispatch_sparc +#define address_space_init_shareable address_space_init_shareable_sparc #define address_space_lookup_region address_space_lookup_region_sparc #define address_space_map address_space_map_sparc #define address_space_read address_space_read_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index ae0536ef..8d942b6e 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_sparc64 #define address_space_init address_space_init_sparc64 #define address_space_init_dispatch address_space_init_dispatch_sparc64 +#define address_space_init_shareable address_space_init_shareable_sparc64 #define address_space_lookup_region address_space_lookup_region_sparc64 #define address_space_map address_space_map_sparc64 #define address_space_read address_space_read_sparc64 diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 6f9c1d63..d0f05acf 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -91,6 +91,7 @@ #define address_space_get_flatview address_space_get_flatview_x86_64 #define address_space_init address_space_init_x86_64 #define address_space_init_dispatch address_space_init_dispatch_x86_64 +#define address_space_init_shareable address_space_init_shareable_x86_64 #define address_space_lookup_region address_space_lookup_region_x86_64 #define address_space_map address_space_map_x86_64 #define address_space_read address_space_read_x86_64