memory: maintain a list of address spaces
Instead of embedding knowledge of the memory and I/O address spaces in the memory core, maintain a list of all address spaces. This list will later be extended dynamically for other bus masters. Reviewed-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
9ad2bbc167
commit
0d673e36a7
75
memory.c
75
memory.c
|
@ -28,6 +28,9 @@ static bool global_dirty_log = false;
|
||||||
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
|
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
|
||||||
= QTAILQ_HEAD_INITIALIZER(memory_listeners);
|
= QTAILQ_HEAD_INITIALIZER(memory_listeners);
|
||||||
|
|
||||||
|
static QTAILQ_HEAD(, AddressSpace) address_spaces
|
||||||
|
= QTAILQ_HEAD_INITIALIZER(address_spaces);
|
||||||
|
|
||||||
typedef struct AddrRange AddrRange;
|
typedef struct AddrRange AddrRange;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -449,14 +452,15 @@ static AddressSpace address_space_io;
|
||||||
|
|
||||||
static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
|
static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
|
AddressSpace *as;
|
||||||
|
|
||||||
while (mr->parent) {
|
while (mr->parent) {
|
||||||
mr = mr->parent;
|
mr = mr->parent;
|
||||||
}
|
}
|
||||||
if (mr == address_space_memory.root) {
|
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||||
return &address_space_memory;
|
if (mr == as->root) {
|
||||||
}
|
return as;
|
||||||
if (mr == address_space_io.root) {
|
}
|
||||||
return &address_space_io;
|
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -729,16 +733,15 @@ void memory_region_transaction_begin(void)
|
||||||
|
|
||||||
void memory_region_transaction_commit(void)
|
void memory_region_transaction_commit(void)
|
||||||
{
|
{
|
||||||
|
AddressSpace *as;
|
||||||
|
|
||||||
assert(memory_region_transaction_depth);
|
assert(memory_region_transaction_depth);
|
||||||
--memory_region_transaction_depth;
|
--memory_region_transaction_depth;
|
||||||
if (!memory_region_transaction_depth) {
|
if (!memory_region_transaction_depth) {
|
||||||
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
|
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
|
||||||
|
|
||||||
if (address_space_memory.root) {
|
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||||
address_space_update_topology(&address_space_memory);
|
address_space_update_topology(as);
|
||||||
}
|
|
||||||
if (address_space_io.root) {
|
|
||||||
address_space_update_topology(&address_space_io);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
|
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
|
||||||
|
@ -1072,12 +1075,14 @@ void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
||||||
|
|
||||||
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
|
AddressSpace *as;
|
||||||
FlatRange *fr;
|
FlatRange *fr;
|
||||||
|
|
||||||
FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
|
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||||
if (fr->mr == mr) {
|
FOR_EACH_FLAT_RANGE(fr, as->current_map) {
|
||||||
MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
|
if (fr->mr == mr) {
|
||||||
Forward, log_sync);
|
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1120,13 +1125,13 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
|
||||||
return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
|
return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void memory_region_update_coalesced_range(MemoryRegion *mr)
|
static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
|
||||||
{
|
{
|
||||||
FlatRange *fr;
|
FlatRange *fr;
|
||||||
CoalescedMemoryRange *cmr;
|
CoalescedMemoryRange *cmr;
|
||||||
AddrRange tmp;
|
AddrRange tmp;
|
||||||
|
|
||||||
FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) {
|
FOR_EACH_FLAT_RANGE(fr, as->current_map) {
|
||||||
if (fr->mr == mr) {
|
if (fr->mr == mr) {
|
||||||
qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
|
qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
|
||||||
int128_get64(fr->addr.size));
|
int128_get64(fr->addr.size));
|
||||||
|
@ -1145,6 +1150,15 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void memory_region_update_coalesced_range(MemoryRegion *mr)
|
||||||
|
{
|
||||||
|
AddressSpace *as;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||||
|
memory_region_update_coalesced_range_as(mr, as);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void memory_region_set_coalescing(MemoryRegion *mr)
|
void memory_region_set_coalescing(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
memory_region_clear_coalescing(mr);
|
memory_region_clear_coalescing(mr);
|
||||||
|
@ -1450,10 +1464,6 @@ static void listener_add_address_space(MemoryListener *listener,
|
||||||
{
|
{
|
||||||
FlatRange *fr;
|
FlatRange *fr;
|
||||||
|
|
||||||
if (!as->root) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listener->address_space_filter
|
if (listener->address_space_filter
|
||||||
&& listener->address_space_filter != as->root) {
|
&& listener->address_space_filter != as->root) {
|
||||||
return;
|
return;
|
||||||
|
@ -1478,6 +1488,7 @@ static void listener_add_address_space(MemoryListener *listener,
|
||||||
void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
|
void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
|
||||||
{
|
{
|
||||||
MemoryListener *other = NULL;
|
MemoryListener *other = NULL;
|
||||||
|
AddressSpace *as;
|
||||||
|
|
||||||
listener->address_space_filter = filter;
|
listener->address_space_filter = filter;
|
||||||
if (QTAILQ_EMPTY(&memory_listeners)
|
if (QTAILQ_EMPTY(&memory_listeners)
|
||||||
|
@ -1492,8 +1503,10 @@ void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
|
||||||
}
|
}
|
||||||
QTAILQ_INSERT_BEFORE(other, listener, link);
|
QTAILQ_INSERT_BEFORE(other, listener, link);
|
||||||
}
|
}
|
||||||
listener_add_address_space(listener, &address_space_memory);
|
|
||||||
listener_add_address_space(listener, &address_space_io);
|
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||||
|
listener_add_address_space(listener, as);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_listener_unregister(MemoryListener *listener)
|
void memory_listener_unregister(MemoryListener *listener)
|
||||||
|
@ -1507,17 +1520,21 @@ void address_space_init(AddressSpace *as, MemoryRegion *root)
|
||||||
as->root = root;
|
as->root = root;
|
||||||
as->current_map = g_new(FlatView, 1);
|
as->current_map = g_new(FlatView, 1);
|
||||||
flatview_init(as->current_map);
|
flatview_init(as->current_map);
|
||||||
|
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
|
||||||
|
as->name = NULL;
|
||||||
memory_region_transaction_commit();
|
memory_region_transaction_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_system_memory_map(MemoryRegion *mr)
|
void set_system_memory_map(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
address_space_init(&address_space_memory, mr);
|
address_space_init(&address_space_memory, mr);
|
||||||
|
address_space_memory.name = "memory";
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_system_io_map(MemoryRegion *mr)
|
void set_system_io_map(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
address_space_init(&address_space_io, mr);
|
address_space_init(&address_space_io, mr);
|
||||||
|
address_space_io.name = "I/O";
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
|
uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
|
||||||
|
@ -1637,16 +1654,16 @@ void mtree_info(fprintf_function mon_printf, void *f)
|
||||||
{
|
{
|
||||||
MemoryRegionListHead ml_head;
|
MemoryRegionListHead ml_head;
|
||||||
MemoryRegionList *ml, *ml2;
|
MemoryRegionList *ml, *ml2;
|
||||||
|
AddressSpace *as;
|
||||||
|
|
||||||
QTAILQ_INIT(&ml_head);
|
QTAILQ_INIT(&ml_head);
|
||||||
|
|
||||||
mon_printf(f, "memory\n");
|
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
|
||||||
mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
|
if (!as->name) {
|
||||||
|
continue;
|
||||||
if (address_space_io.root &&
|
}
|
||||||
!QTAILQ_EMPTY(&address_space_io.root->subregions)) {
|
mon_printf(f, "%s\n", as->name);
|
||||||
mon_printf(f, "I/O\n");
|
mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head);
|
||||||
mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mon_printf(f, "aliases\n");
|
mon_printf(f, "aliases\n");
|
||||||
|
|
2
memory.h
2
memory.h
|
@ -164,10 +164,12 @@ typedef struct AddressSpace AddressSpace;
|
||||||
*/
|
*/
|
||||||
struct AddressSpace {
|
struct AddressSpace {
|
||||||
/* All fields are private. */
|
/* All fields are private. */
|
||||||
|
const char *name;
|
||||||
MemoryRegion *root;
|
MemoryRegion *root;
|
||||||
struct FlatView *current_map;
|
struct FlatView *current_map;
|
||||||
int ioeventfd_nb;
|
int ioeventfd_nb;
|
||||||
struct MemoryRegionIoeventfd *ioeventfds;
|
struct MemoryRegionIoeventfd *ioeventfds;
|
||||||
|
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct MemoryRegionSection MemoryRegionSection;
|
typedef struct MemoryRegionSection MemoryRegionSection;
|
||||||
|
|
Loading…
Reference in New Issue