diff --git a/cputlb.c b/cputlb.c index 51b5897d37..9027557604 100644 --- a/cputlb.c +++ b/cputlb.c @@ -21,11 +21,11 @@ #include "cpu.h" #include "exec-all.h" #include "memory.h" +#include "exec-memory.h" #include "cputlb.h" -#define WANT_EXEC_OBSOLETE -#include "exec-obsolete.h" +#include "memory-internal.h" //#define DEBUG_TLB //#define DEBUG_TLB_CHECK @@ -252,7 +252,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, if (size != TARGET_PAGE_SIZE) { tlb_add_large_page(env, vaddr, size); } - section = phys_page_find(paddr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, paddr >> TARGET_PAGE_BITS); #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx " prot=%x idx=%d pd=0x%08lx\n", diff --git a/cputlb.h b/cputlb.h index 2dc2c96cd8..d537b7740f 100644 --- a/cputlb.h +++ b/cputlb.h @@ -26,7 +26,8 @@ void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr, target_ulong vaddr); void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start, uintptr_t length); -MemoryRegionSection *phys_page_find(target_phys_addr_t index); +MemoryRegionSection *phys_page_find(struct AddressSpaceDispatch *d, + target_phys_addr_t index); void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length); void tlb_set_dirty(CPUArchState *env, target_ulong vaddr); extern int tlb_flush_count; diff --git a/dma-helpers.c b/dma-helpers.c index 433d8b21b3..3f09dcb072 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -14,7 +14,8 @@ /* #define DEBUG_IOMMU */ -static void do_dma_memory_set(dma_addr_t addr, uint8_t c, dma_addr_t len) +static void do_dma_memory_set(AddressSpace *as, + dma_addr_t addr, uint8_t c, dma_addr_t len) { #define FILLBUF_SIZE 512 uint8_t fillbuf[FILLBUF_SIZE]; @@ -23,7 +24,7 @@ static void do_dma_memory_set(dma_addr_t addr, uint8_t c, dma_addr_t len) memset(fillbuf, c, FILLBUF_SIZE); while (len > 0) { l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; - cpu_physical_memory_rw(addr, fillbuf, l, true); + address_space_rw(as, addr, fillbuf, l, true); len -= l; addr += l; } @@ -36,7 +37,7 @@ int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) if (dma_has_iommu(dma)) { return iommu_dma_memory_set(dma, addr, c, len); } - do_dma_memory_set(addr, c, len); + do_dma_memory_set(dma->as, addr, c, len); return 0; } @@ -332,8 +333,7 @@ int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr, plen = len; } - cpu_physical_memory_rw(paddr, buf, plen, - dir == DMA_DIRECTION_FROM_DEVICE); + address_space_rw(dma->as, paddr, buf, plen, dir == DMA_DIRECTION_FROM_DEVICE); len -= plen; addr += plen; @@ -366,7 +366,7 @@ int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, plen = len; } - do_dma_memory_set(paddr, c, plen); + do_dma_memory_set(dma->as, paddr, c, plen); len -= plen; addr += plen; @@ -375,13 +375,14 @@ int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, return 0; } -void dma_context_init(DMAContext *dma, DMATranslateFunc translate, +void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, DMAMapFunc map, DMAUnmapFunc unmap) { #ifdef DEBUG_IOMMU fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n", dma, translate, map, unmap); #endif + dma->as = as; dma->translate = translate; dma->map = map; dma->unmap = unmap; @@ -407,14 +408,13 @@ void *iommu_dma_memory_map(DMAContext *dma, dma_addr_t addr, dma_addr_t *len, /* * If this is true, the virtual region is contiguous, * but the translated physical region isn't. We just - * clamp *len, much like cpu_physical_memory_map() does. + * clamp *len, much like address_space_map() does. */ if (plen < *len) { *len = plen; } - buf = cpu_physical_memory_map(paddr, &plen, - dir == DMA_DIRECTION_FROM_DEVICE); + buf = address_space_map(dma->as, paddr, &plen, dir == DMA_DIRECTION_FROM_DEVICE); *len = plen; return buf; @@ -428,8 +428,7 @@ void iommu_dma_memory_unmap(DMAContext *dma, void *buffer, dma_addr_t len, return; } - cpu_physical_memory_unmap(buffer, len, - dir == DMA_DIRECTION_FROM_DEVICE, - access_len); + address_space_unmap(dma->as, buffer, len, dir == DMA_DIRECTION_FROM_DEVICE, + access_len); } diff --git a/dma.h b/dma.h index 1a33603f22..1bd6f4a651 100644 --- a/dma.h +++ b/dma.h @@ -11,6 +11,7 @@ #define DMA_H #include +#include "memory.h" #include "hw/hw.h" #include "block.h" #include "kvm.h" @@ -61,6 +62,7 @@ typedef void DMAUnmapFunc(DMAContext *dma, dma_addr_t access_len); struct DMAContext { + AddressSpace *as; DMATranslateFunc *translate; DMAMapFunc *map; DMAUnmapFunc *unmap; @@ -93,7 +95,7 @@ static inline void dma_barrier(DMAContext *dma, DMADirection dir) static inline bool dma_has_iommu(DMAContext *dma) { - return !!dma; + return dma && dma->translate; } /* Checks that the given range of addresses is valid for DMA. This is @@ -120,8 +122,7 @@ static inline int dma_memory_rw_relaxed(DMAContext *dma, dma_addr_t addr, { if (!dma_has_iommu(dma)) { /* Fast-path for no IOMMU */ - cpu_physical_memory_rw(addr, buf, len, - dir == DMA_DIRECTION_FROM_DEVICE); + address_space_rw(dma->as, addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE); return 0; } else { return iommu_dma_memory_rw(dma, addr, buf, len, dir); @@ -179,8 +180,7 @@ static inline void *dma_memory_map(DMAContext *dma, target_phys_addr_t xlen = *len; void *p; - p = cpu_physical_memory_map(addr, &xlen, - dir == DMA_DIRECTION_FROM_DEVICE); + p = address_space_map(dma->as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE); *len = xlen; return p; } else { @@ -196,9 +196,8 @@ static inline void dma_memory_unmap(DMAContext *dma, DMADirection dir, dma_addr_t access_len) { if (!dma_has_iommu(dma)) { - cpu_physical_memory_unmap(buffer, (target_phys_addr_t)len, - dir == DMA_DIRECTION_FROM_DEVICE, - access_len); + address_space_unmap(dma->as, buffer, (target_phys_addr_t)len, + dir == DMA_DIRECTION_FROM_DEVICE, access_len); } else { iommu_dma_memory_unmap(dma, buffer, len, dir, access_len); } @@ -242,7 +241,7 @@ DEFINE_LDST_DMA(q, q, 64, be); #undef DEFINE_LDST_DMA -void dma_context_init(DMAContext *dma, DMATranslateFunc translate, +void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, DMAMapFunc map, DMAUnmapFunc unmap); struct ScatterGatherEntry { diff --git a/exec-memory.h b/exec-memory.h index 1cd92eec71..ac1d07dfe4 100644 --- a/exec-memory.h +++ b/exec-memory.h @@ -33,11 +33,8 @@ MemoryRegion *get_system_memory(void); */ MemoryRegion *get_system_io(void); -/* Set the root memory region. This region is the system memory map. */ -void set_system_memory_map(MemoryRegion *mr); - -/* Set the I/O memory region. This region is the I/O memory map. */ -void set_system_io_map(MemoryRegion *mr); +extern AddressSpace address_space_memory; +extern AddressSpace address_space_io; #endif diff --git a/exec.c b/exec.c index 4a86b0f4c4..5b55e3e9ed 100644 --- a/exec.c +++ b/exec.c @@ -59,8 +59,7 @@ #include "cputlb.h" -#define WANT_EXEC_OBSOLETE -#include "exec-obsolete.h" +#include "memory-internal.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -102,6 +101,9 @@ RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) }; static MemoryRegion *system_memory; static MemoryRegion *system_io; +AddressSpace address_space_io; +AddressSpace address_space_memory; + MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty; static MemoryRegion io_mem_subpage_ram; @@ -170,7 +172,6 @@ uintptr_t qemu_host_page_mask; static void *l1_map[V_L1_SIZE]; #if !defined(CONFIG_USER_ONLY) -typedef struct PhysPageEntry PhysPageEntry; static MemoryRegionSection *phys_sections; static unsigned phys_sections_nb, phys_sections_nb_alloc; @@ -179,22 +180,12 @@ static uint16_t phys_section_notdirty; static uint16_t phys_section_rom; static uint16_t phys_section_watch; -struct PhysPageEntry { - uint16_t is_leaf : 1; - /* index into phys_sections (is_leaf) or phys_map_nodes (!is_leaf) */ - uint16_t ptr : 15; -}; - /* Simple allocator for PhysPageEntry nodes */ static PhysPageEntry (*phys_map_nodes)[L2_SIZE]; static unsigned phys_map_nodes_nb, phys_map_nodes_nb_alloc; #define PHYS_MAP_NODE_NIL (((uint16_t)~0) >> 1) -/* This is a multi-level map on the physical address space. - The bottom level has pointers to MemoryRegionSections. */ -static PhysPageEntry phys_map = { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 }; - static void io_mem_init(void); static void memory_map_init(void); @@ -442,18 +433,19 @@ static void phys_page_set_level(PhysPageEntry *lp, target_phys_addr_t *index, } } -static void phys_page_set(target_phys_addr_t index, target_phys_addr_t nb, +static void phys_page_set(AddressSpaceDispatch *d, + target_phys_addr_t index, target_phys_addr_t nb, uint16_t leaf) { /* Wildly overreserve - it doesn't matter much. */ phys_map_node_reserve(3 * P_L2_LEVELS); - phys_page_set_level(&phys_map, &index, &nb, leaf, P_L2_LEVELS - 1); + phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1); } -MemoryRegionSection *phys_page_find(target_phys_addr_t index) +MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, target_phys_addr_t index) { - PhysPageEntry lp = phys_map; + PhysPageEntry lp = d->phys_map; PhysPageEntry *p; int i; uint16_t s_index = phys_section_unassigned; @@ -1486,7 +1478,7 @@ void tb_invalidate_phys_addr(target_phys_addr_t addr) ram_addr_t ram_addr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || (section->mr->rom_device && section->mr->readable))) { return; @@ -2224,9 +2216,9 @@ static void destroy_l2_mapping(PhysPageEntry *lp, unsigned level) lp->ptr = PHYS_MAP_NODE_NIL; } -static void destroy_all_mappings(void) +static void destroy_all_mappings(AddressSpaceDispatch *d) { - destroy_l2_mapping(&phys_map, P_L2_LEVELS - 1); + destroy_l2_mapping(&d->phys_map, P_L2_LEVELS - 1); phys_map_nodes_reset(); } @@ -2246,12 +2238,12 @@ static void phys_sections_clear(void) phys_sections_nb = 0; } -static void register_subpage(MemoryRegionSection *section) +static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section) { subpage_t *subpage; target_phys_addr_t base = section->offset_within_address_space & TARGET_PAGE_MASK; - MemoryRegionSection *existing = phys_page_find(base >> TARGET_PAGE_BITS); + MemoryRegionSection *existing = phys_page_find(d, base >> TARGET_PAGE_BITS); MemoryRegionSection subsection = { .offset_within_address_space = base, .size = TARGET_PAGE_SIZE, @@ -2263,7 +2255,7 @@ static void register_subpage(MemoryRegionSection *section) if (!(existing->mr->subpage)) { subpage = subpage_init(base); subsection.mr = &subpage->iomem; - phys_page_set(base >> TARGET_PAGE_BITS, 1, + phys_page_set(d, base >> TARGET_PAGE_BITS, 1, phys_section_add(&subsection)); } else { subpage = container_of(existing->mr, subpage_t, iomem); @@ -2274,7 +2266,7 @@ static void register_subpage(MemoryRegionSection *section) } -static void register_multipage(MemoryRegionSection *section) +static void register_multipage(AddressSpaceDispatch *d, MemoryRegionSection *section) { target_phys_addr_t start_addr = section->offset_within_address_space; ram_addr_t size = section->size; @@ -2284,13 +2276,13 @@ static void register_multipage(MemoryRegionSection *section) assert(size); addr = start_addr; - phys_page_set(addr >> TARGET_PAGE_BITS, size >> TARGET_PAGE_BITS, + phys_page_set(d, addr >> TARGET_PAGE_BITS, size >> TARGET_PAGE_BITS, section_index); } -void cpu_register_physical_memory_log(MemoryRegionSection *section, - bool readonly) +static void mem_add(MemoryListener *listener, MemoryRegionSection *section) { + AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); MemoryRegionSection now = *section, remain = *section; if ((now.offset_within_address_space & ~TARGET_PAGE_MASK) @@ -2298,7 +2290,7 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, now.size = MIN(TARGET_PAGE_ALIGN(now.offset_within_address_space) - now.offset_within_address_space, now.size); - register_subpage(&now); + register_subpage(d, &now); remain.size -= now.size; remain.offset_within_address_space += now.size; remain.offset_within_region += now.size; @@ -2307,10 +2299,10 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, now = remain; if (remain.offset_within_region & ~TARGET_PAGE_MASK) { now.size = TARGET_PAGE_SIZE; - register_subpage(&now); + register_subpage(d, &now); } else { now.size &= TARGET_PAGE_MASK; - register_multipage(&now); + register_multipage(d, &now); } remain.size -= now.size; remain.offset_within_address_space += now.size; @@ -2318,23 +2310,10 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, } now = remain; if (now.size) { - register_subpage(&now); + register_subpage(d, &now); } } - -void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) -{ - if (kvm_enabled()) - kvm_coalesce_mmio_region(addr, size); -} - -void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) -{ - if (kvm_enabled()) - kvm_uncoalesce_mmio_region(addr, size); -} - void qemu_flush_coalesced_mmio_buffer(void) { if (kvm_enabled()) @@ -3182,18 +3161,24 @@ static void io_mem_init(void) "watch", UINT64_MAX); } +static void mem_begin(MemoryListener *listener) +{ + AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); + + destroy_all_mappings(d); + d->phys_map.ptr = PHYS_MAP_NODE_NIL; +} + static void core_begin(MemoryListener *listener) { - destroy_all_mappings(); phys_sections_clear(); - phys_map.ptr = PHYS_MAP_NODE_NIL; phys_section_unassigned = dummy_section(&io_mem_unassigned); phys_section_notdirty = dummy_section(&io_mem_notdirty); phys_section_rom = dummy_section(&io_mem_rom); phys_section_watch = dummy_section(&io_mem_watch); } -static void core_commit(MemoryListener *listener) +static void tcg_commit(MemoryListener *listener) { CPUArchState *env; @@ -3205,38 +3190,6 @@ static void core_commit(MemoryListener *listener) } } -static void core_region_add(MemoryListener *listener, - MemoryRegionSection *section) -{ - cpu_register_physical_memory_log(section, section->readonly); -} - -static void core_region_del(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void core_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ - cpu_register_physical_memory_log(section, section->readonly); -} - -static void core_log_start(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void core_log_stop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void core_log_sync(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void core_log_global_start(MemoryListener *listener) { cpu_physical_memory_set_dirty_tracking(1); @@ -3247,26 +3200,6 @@ static void core_log_global_stop(MemoryListener *listener) cpu_physical_memory_set_dirty_tracking(0); } -static void core_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - -static void core_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - -static void io_begin(MemoryListener *listener) -{ -} - -static void io_commit(MemoryListener *listener) -{ -} - static void io_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -3285,90 +3218,63 @@ static void io_region_del(MemoryListener *listener, isa_unassign_ioport(section->offset_within_address_space, section->size); } -static void io_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_start(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_stop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_sync(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_global_start(MemoryListener *listener) -{ -} - -static void io_log_global_stop(MemoryListener *listener) -{ -} - -static void io_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - -static void io_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - static MemoryListener core_memory_listener = { .begin = core_begin, - .commit = core_commit, - .region_add = core_region_add, - .region_del = core_region_del, - .region_nop = core_region_nop, - .log_start = core_log_start, - .log_stop = core_log_stop, - .log_sync = core_log_sync, .log_global_start = core_log_global_start, .log_global_stop = core_log_global_stop, - .eventfd_add = core_eventfd_add, - .eventfd_del = core_eventfd_del, - .priority = 0, + .priority = 1, }; static MemoryListener io_memory_listener = { - .begin = io_begin, - .commit = io_commit, .region_add = io_region_add, .region_del = io_region_del, - .region_nop = io_region_nop, - .log_start = io_log_start, - .log_stop = io_log_stop, - .log_sync = io_log_sync, - .log_global_start = io_log_global_start, - .log_global_stop = io_log_global_stop, - .eventfd_add = io_eventfd_add, - .eventfd_del = io_eventfd_del, .priority = 0, }; +static MemoryListener tcg_memory_listener = { + .commit = tcg_commit, +}; + +void address_space_init_dispatch(AddressSpace *as) +{ + AddressSpaceDispatch *d = g_new(AddressSpaceDispatch, 1); + + d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 }; + d->listener = (MemoryListener) { + .begin = mem_begin, + .region_add = mem_add, + .region_nop = mem_add, + .priority = 0, + }; + as->dispatch = d; + memory_listener_register(&d->listener, as); +} + +void address_space_destroy_dispatch(AddressSpace *as) +{ + AddressSpaceDispatch *d = as->dispatch; + + memory_listener_unregister(&d->listener); + destroy_l2_mapping(&d->phys_map, P_L2_LEVELS - 1); + g_free(d); + as->dispatch = NULL; +} + static void memory_map_init(void) { system_memory = g_malloc(sizeof(*system_memory)); memory_region_init(system_memory, "system", INT64_MAX); - set_system_memory_map(system_memory); + address_space_init(&address_space_memory, system_memory); + address_space_memory.name = "memory"; system_io = g_malloc(sizeof(*system_io)); memory_region_init(system_io, "io", 65536); - set_system_io_map(system_io); + address_space_init(&address_space_io, system_io); + address_space_io.name = "I/O"; - memory_listener_register(&core_memory_listener, system_memory); - memory_listener_register(&io_memory_listener, system_io); + memory_listener_register(&core_memory_listener, &address_space_memory); + memory_listener_register(&io_memory_listener, &address_space_io); + memory_listener_register(&tcg_memory_listener, &address_space_memory); } MemoryRegion *get_system_memory(void) @@ -3438,9 +3344,10 @@ static void invalidate_and_set_dirty(target_phys_addr_t addr, xen_modified_memory(addr, length); } -void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, - int len, int is_write) +void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, + int len, bool is_write) { + AddressSpaceDispatch *d = as->dispatch; int l; uint8_t *ptr; uint32_t val; @@ -3452,7 +3359,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(page >> TARGET_PAGE_BITS); + section = phys_page_find(d, page >> TARGET_PAGE_BITS); if (is_write) { if (!memory_region_is_ram(section->mr)) { @@ -3523,10 +3430,36 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } +void address_space_write(AddressSpace *as, target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + address_space_rw(as, addr, (uint8_t *)buf, len, true); +} + +/** + * address_space_read: read from an address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + */ +void address_space_read(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, int len) +{ + address_space_rw(as, addr, buf, len, false); +} + + +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + return address_space_rw(&address_space_memory, addr, buf, len, is_write); +} + /* used for ROM loading : can write in RAM and ROM */ void cpu_physical_memory_write_rom(target_phys_addr_t addr, const uint8_t *buf, int len) { + AddressSpaceDispatch *d = address_space_memory.dispatch; int l; uint8_t *ptr; target_phys_addr_t page; @@ -3537,7 +3470,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(page >> TARGET_PAGE_BITS); + section = phys_page_find(d, page >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3611,10 +3544,12 @@ static void cpu_notify_map_clients(void) * Use cpu_register_map_client() to know when retrying the map operation is * likely to succeed. */ -void *cpu_physical_memory_map(target_phys_addr_t addr, - target_phys_addr_t *plen, - int is_write) +void *address_space_map(AddressSpace *as, + target_phys_addr_t addr, + target_phys_addr_t *plen, + bool is_write) { + AddressSpaceDispatch *d = as->dispatch; target_phys_addr_t len = *plen; target_phys_addr_t todo = 0; int l; @@ -3629,7 +3564,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(page >> TARGET_PAGE_BITS); + section = phys_page_find(d, page >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) && !section->readonly)) { if (todo || bounce.buffer) { @@ -3639,7 +3574,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, bounce.addr = addr; bounce.len = l; if (!is_write) { - cpu_physical_memory_read(addr, bounce.buffer, l); + address_space_read(as, addr, bounce.buffer, l); } *plen = l; @@ -3660,12 +3595,12 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, return ret; } -/* Unmaps a memory region previously mapped by cpu_physical_memory_map(). +/* Unmaps a memory region previously mapped by address_space_map(). * Will also mark the memory as dirty if is_write == 1. access_len gives * the amount of memory that was actually read or written by the caller. */ -void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, - int is_write, target_phys_addr_t access_len) +void address_space_unmap(AddressSpace *as, void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) { if (buffer != bounce.buffer) { if (is_write) { @@ -3686,13 +3621,26 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, return; } if (is_write) { - cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len); + address_space_write(as, bounce.addr, bounce.buffer, access_len); } qemu_vfree(bounce.buffer); bounce.buffer = NULL; cpu_notify_map_clients(); } +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write) +{ + return address_space_map(&address_space_memory, addr, plen, is_write); +} + +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) +{ + return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len); +} + /* warning: addr must be aligned */ static inline uint32_t ldl_phys_internal(target_phys_addr_t addr, enum device_endian endian) @@ -3701,7 +3649,7 @@ static inline uint32_t ldl_phys_internal(target_phys_addr_t addr, uint32_t val; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3760,7 +3708,7 @@ static inline uint64_t ldq_phys_internal(target_phys_addr_t addr, uint64_t val; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3827,7 +3775,7 @@ static inline uint32_t lduw_phys_internal(target_phys_addr_t addr, uint64_t val; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3886,7 +3834,7 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -3918,7 +3866,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -3947,7 +3895,7 @@ static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val, uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -4014,7 +3962,7 @@ static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val, uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -4250,7 +4198,8 @@ bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr) { MemoryRegionSection *section; - section = phys_page_find(phys_addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, + phys_addr >> TARGET_PAGE_BITS); return !(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr)); diff --git a/hw/pci.c b/hw/pci.c index 2ca6ff6fec..7eeaac0d3d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -33,6 +33,7 @@ #include "qmp-commands.h" #include "msi.h" #include "msix.h" +#include "exec-memory.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -777,6 +778,17 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_dev->bus = bus; if (bus->dma_context_fn) { pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); + } else { + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is + * taken unconditionally */ + /* FIXME: inherit memory region from bus creator */ + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", + get_system_memory(), 0, + memory_region_size(get_system_memory())); + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); + pci_dev->dma = g_new(DMAContext, 1); + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); } pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); @@ -830,6 +842,13 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) qemu_free_irqs(pci_dev->irq); pci_dev->bus->devices[pci_dev->devfn] = NULL; pci_config_free(pci_dev); + + if (!pci_dev->bus->dma_context_fn) { + address_space_destroy(&pci_dev->bus_master_as); + memory_region_destroy(&pci_dev->bus_master_enable_region); + g_free(pci_dev->dma); + pci_dev->dma = NULL; + } } static void pci_unregister_io_regions(PCIDevice *pci_dev) @@ -1051,8 +1070,12 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) range_covers_byte(addr, l, PCI_COMMAND)) pci_update_mappings(d); - if (range_covers_byte(addr, l, PCI_COMMAND)) + if (range_covers_byte(addr, l, PCI_COMMAND)) { pci_update_irq_disabled(d, was_irq_disabled); + memory_region_set_enabled(&d->bus_master_enable_region, + pci_get_word(d->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + } msi_write_config(d, addr, val, l); msix_write_config(d, addr, val, l); diff --git a/hw/pci.h b/hw/pci.h index d50d26c8ac..1f902f5b59 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -211,6 +211,8 @@ struct PCIDevice { int32_t devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; + AddressSpace bus_master_as; + MemoryRegion bus_master_enable_region; DMAContext *dma; /* do not access the following fields */ diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index 38034c07bd..33f84e27aa 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -21,6 +21,7 @@ #include "qdev.h" #include "kvm_ppc.h" #include "dma.h" +#include "exec-memory.h" #include "hw/spapr.h" @@ -124,7 +125,7 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size) } tcet = g_malloc0(sizeof(*tcet)); - dma_context_init(&tcet->dma, spapr_tce_translate, NULL, NULL); + dma_context_init(&tcet->dma, &address_space_memory, spapr_tce_translate, NULL, NULL); tcet->liobn = liobn; tcet->window_size = window_size; diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 639371e7a2..f5db4a8567 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -930,25 +930,6 @@ static int vfio_dma_map(VFIOContainer *container, target_phys_addr_t iova, return -errno; } -static void vfio_listener_dummy1(MemoryListener *listener) -{ - /* We don't do batching (begin/commit) or care about logging */ -} - -static void vfio_listener_dummy2(MemoryListener *listener, - MemoryRegionSection *section) -{ - /* We don't do logging or care about nops */ -} - -static void vfio_listener_dummy3(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ - /* We don't care about eventfds */ -} - static bool vfio_listener_skipped_section(MemoryRegionSection *section) { return !memory_region_is_ram(section->mr); @@ -1040,18 +1021,8 @@ static void vfio_listener_region_del(MemoryListener *listener, } static MemoryListener vfio_memory_listener = { - .begin = vfio_listener_dummy1, - .commit = vfio_listener_dummy1, .region_add = vfio_listener_region_add, .region_del = vfio_listener_region_del, - .region_nop = vfio_listener_dummy2, - .log_start = vfio_listener_dummy2, - .log_stop = vfio_listener_dummy2, - .log_sync = vfio_listener_dummy2, - .log_global_start = vfio_listener_dummy1, - .log_global_stop = vfio_listener_dummy1, - .eventfd_add = vfio_listener_dummy3, - .eventfd_del = vfio_listener_dummy3, }; static void vfio_listener_release(VFIOContainer *container) @@ -1536,8 +1507,7 @@ static int vfio_connect_container(VFIOGroup *group) container->iommu_data.listener = vfio_memory_listener; container->iommu_data.release = vfio_listener_release; - memory_listener_register(&container->iommu_data.listener, - get_system_memory()); + memory_listener_register(&container->iommu_data.listener, &address_space_memory); } else { error_report("vfio: No available IOMMU models\n"); g_free(container); diff --git a/hw/vhost.c b/hw/vhost.c index d0ce5aad9b..0b4ac3f1df 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -434,8 +434,7 @@ static void vhost_set_memory(MemoryListener *listener, static bool vhost_section(MemoryRegionSection *section) { - return section->address_space == get_system_memory() - && memory_region_is_ram(section->mr); + return memory_region_is_ram(section->mr); } static void vhost_begin(MemoryListener *listener) @@ -793,7 +792,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - memory_listener_register(&hdev->memory_listener, NULL); + memory_listener_register(&hdev->memory_listener, &address_space_memory); hdev->force = force; return 0; fail: diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 838bcea4d6..d3d7c8bc3c 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -59,6 +59,7 @@ #include "xen_backend.h" #include "xen_pt.h" #include "range.h" +#include "exec-memory.h" #define XEN_PT_NR_IRQS (256) static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0}; @@ -600,14 +601,6 @@ static void xen_pt_region_update(XenPCIPassthroughState *s, } } -static void xen_pt_begin(MemoryListener *l) -{ -} - -static void xen_pt_commit(MemoryListener *l) -{ -} - static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec) { XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, @@ -624,36 +617,31 @@ static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec) xen_pt_region_update(s, sec, false); } -static void xen_pt_region_nop(MemoryListener *l, MemoryRegionSection *s) +static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec) { + XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, + io_listener); + + xen_pt_region_update(s, sec, true); } -static void xen_pt_log_fns(MemoryListener *l, MemoryRegionSection *s) +static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec) { -} + XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, + io_listener); -static void xen_pt_log_global_fns(MemoryListener *l) -{ -} - -static void xen_pt_eventfd_fns(MemoryListener *l, MemoryRegionSection *s, - bool match_data, uint64_t data, EventNotifier *n) -{ + xen_pt_region_update(s, sec, false); } static const MemoryListener xen_pt_memory_listener = { - .begin = xen_pt_begin, - .commit = xen_pt_commit, .region_add = xen_pt_region_add, - .region_nop = xen_pt_region_nop, .region_del = xen_pt_region_del, - .log_start = xen_pt_log_fns, - .log_stop = xen_pt_log_fns, - .log_sync = xen_pt_log_fns, - .log_global_start = xen_pt_log_global_fns, - .log_global_stop = xen_pt_log_global_fns, - .eventfd_add = xen_pt_eventfd_fns, - .eventfd_del = xen_pt_eventfd_fns, + .priority = 10, +}; + +static const MemoryListener xen_pt_io_listener = { + .region_add = xen_pt_io_region_add, + .region_del = xen_pt_io_region_del, .priority = 10, }; @@ -694,6 +682,7 @@ static int xen_pt_initfn(PCIDevice *d) } s->memory_listener = xen_pt_memory_listener; + s->io_listener = xen_pt_io_listener; /* Handle real device's MMIO/PIO BARs */ xen_pt_register_regions(s); @@ -760,7 +749,8 @@ static int xen_pt_initfn(PCIDevice *d) } out: - memory_listener_register(&s->memory_listener, NULL); + memory_listener_register(&s->memory_listener, &address_space_memory); + memory_listener_register(&s->io_listener, &address_space_io); XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n", bus, slot, func); @@ -815,6 +805,7 @@ static void xen_pt_unregister_device(PCIDevice *d) xen_pt_unregister_regions(s); memory_listener_unregister(&s->memory_listener); + memory_listener_unregister(&s->io_listener); xen_host_pci_device_put(&s->real_device); } diff --git a/hw/xen_pt.h b/hw/xen_pt.h index 112477a881..f15e69a290 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -209,6 +209,7 @@ struct XenPCIPassthroughState { MemoryRegion rom; MemoryListener memory_listener; + MemoryListener io_listener; }; int xen_pt_config_init(XenPCIPassthroughState *s); diff --git a/kvm-all.c b/kvm-all.c index 92a71374ed..c2c69093ec 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -454,9 +454,10 @@ static int kvm_physical_sync_dirty_bitmap(MemoryRegionSection *section) return ret; } -int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) +static void kvm_coalesce_mmio_region(MemoryListener *listener, + MemoryRegionSection *secion, + target_phys_addr_t start, target_phys_addr_t size) { - int ret = -ENOSYS; KVMState *s = kvm_state; if (s->coalesced_mmio) { @@ -466,15 +467,14 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) zone.size = size; zone.pad = 0; - ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone); + (void)kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone); } - - return ret; } -int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) +static void kvm_uncoalesce_mmio_region(MemoryListener *listener, + MemoryRegionSection *secion, + target_phys_addr_t start, target_phys_addr_t size) { - int ret = -ENOSYS; KVMState *s = kvm_state; if (s->coalesced_mmio) { @@ -484,10 +484,8 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) zone.size = size; zone.pad = 0; - ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone); + (void)kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone); } - - return ret; } int kvm_check_extension(KVMState *s, unsigned int extension) @@ -703,14 +701,6 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) } } -static void kvm_begin(MemoryListener *listener) -{ -} - -static void kvm_commit(MemoryListener *listener) -{ -} - static void kvm_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -723,11 +713,6 @@ static void kvm_region_del(MemoryListener *listener, kvm_set_phys_mem(section, false); } -static void kvm_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void kvm_log_sync(MemoryListener *listener, MemoryRegionSection *section) { @@ -755,9 +740,12 @@ static void kvm_log_global_stop(struct MemoryListener *listener) assert(r >= 0); } -static void kvm_mem_ioeventfd_add(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_mem_ioeventfd_add(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; assert(match_data && section->size <= 8); @@ -769,9 +757,12 @@ static void kvm_mem_ioeventfd_add(MemoryRegionSection *section, } } -static void kvm_mem_ioeventfd_del(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_mem_ioeventfd_del(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space, @@ -781,9 +772,12 @@ static void kvm_mem_ioeventfd_del(MemoryRegionSection *section, } } -static void kvm_io_ioeventfd_add(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_io_ioeventfd_add(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; assert(match_data && section->size == 2); @@ -795,10 +789,13 @@ static void kvm_io_ioeventfd_add(MemoryRegionSection *section, } } -static void kvm_io_ioeventfd_del(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_io_ioeventfd_del(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space, @@ -808,47 +805,24 @@ static void kvm_io_ioeventfd_del(MemoryRegionSection *section, } } -static void kvm_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ - if (section->address_space == get_system_memory()) { - kvm_mem_ioeventfd_add(section, match_data, data, - event_notifier_get_fd(e)); - } else { - kvm_io_ioeventfd_add(section, match_data, data, - event_notifier_get_fd(e)); - } -} - -static void kvm_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ - if (section->address_space == get_system_memory()) { - kvm_mem_ioeventfd_del(section, match_data, data, - event_notifier_get_fd(e)); - } else { - kvm_io_ioeventfd_del(section, match_data, data, - event_notifier_get_fd(e)); - } -} - static MemoryListener kvm_memory_listener = { - .begin = kvm_begin, - .commit = kvm_commit, .region_add = kvm_region_add, .region_del = kvm_region_del, - .region_nop = kvm_region_nop, .log_start = kvm_log_start, .log_stop = kvm_log_stop, .log_sync = kvm_log_sync, .log_global_start = kvm_log_global_start, .log_global_stop = kvm_log_global_stop, - .eventfd_add = kvm_eventfd_add, - .eventfd_del = kvm_eventfd_del, + .eventfd_add = kvm_mem_ioeventfd_add, + .eventfd_del = kvm_mem_ioeventfd_del, + .coalesced_mmio_add = kvm_coalesce_mmio_region, + .coalesced_mmio_del = kvm_uncoalesce_mmio_region, + .priority = 10, +}; + +static MemoryListener kvm_io_listener = { + .eventfd_add = kvm_io_ioeventfd_add, + .eventfd_del = kvm_io_ioeventfd_del, .priority = 10, }; @@ -1401,7 +1375,8 @@ int kvm_init(void) } kvm_state = s; - memory_listener_register(&kvm_memory_listener, NULL); + memory_listener_register(&kvm_memory_listener, &address_space_memory); + memory_listener_register(&kvm_io_listener, &address_space_io); s->many_ioeventfds = kvm_check_many_ioeventfds(); diff --git a/kvm-stub.c b/kvm-stub.c index 3c52eb5bc6..a3455e2203 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -29,16 +29,6 @@ int kvm_init_vcpu(CPUArchState *env) return -ENOSYS; } -int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) -{ - return -ENOSYS; -} - -int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) -{ - return -ENOSYS; -} - int kvm_init(void) { return -ENOSYS; diff --git a/kvm.h b/kvm.h index dea2998fd4..eefcb492f0 100644 --- a/kvm.h +++ b/kvm.h @@ -129,8 +129,6 @@ void *kvm_vmalloc(ram_addr_t size); void *kvm_arch_vmalloc(ram_addr_t size); void kvm_setup_guest_memory(void *start, size_t size); -int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); -int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); void kvm_flush_coalesced_mmio_buffer(void); #endif diff --git a/exec-obsolete.h b/memory-internal.h similarity index 86% rename from exec-obsolete.h rename to memory-internal.h index 286e2f75e1..4d33cc9530 100644 --- a/exec-obsolete.h +++ b/memory-internal.h @@ -16,16 +16,33 @@ * The functions declared here will be removed soon. */ -#ifndef EXEC_OBSOLETE_H -#define EXEC_OBSOLETE_H - -#ifndef WANT_EXEC_OBSOLETE -#error Do not include exec-obsolete.h -#endif +#ifndef MEMORY_INTERNAL_H +#define MEMORY_INTERNAL_H #ifndef CONFIG_USER_ONLY #include "hw/xen.h" +typedef struct PhysPageEntry PhysPageEntry; + +struct PhysPageEntry { + uint16_t is_leaf : 1; + /* index into phys_sections (is_leaf) or phys_map_nodes (!is_leaf) */ + uint16_t ptr : 15; +}; + +typedef struct AddressSpaceDispatch AddressSpaceDispatch; + +struct AddressSpaceDispatch { + /* This is a multi-level map on the physical address space. + * The bottom level has pointers to MemoryRegionSections. + */ + PhysPageEntry phys_map; + MemoryListener listener; +}; + +void address_space_init_dispatch(AddressSpace *as); +void address_space_destroy_dispatch(AddressSpace *as); + ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr); ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr); @@ -34,8 +51,6 @@ void qemu_ram_free_from_ptr(ram_addr_t addr); struct MemoryRegion; struct MemoryRegionSection; -void cpu_register_physical_memory_log(struct MemoryRegionSection *section, - bool readonly); 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); diff --git a/memory.c b/memory.c index 4f3ade06dd..2f68d67c21 100644 --- a/memory.c +++ b/memory.c @@ -20,8 +20,7 @@ #include "kvm.h" #include -#define WANT_EXEC_OBSOLETE -#include "exec-obsolete.h" +#include "memory-internal.h" unsigned memory_region_transaction_depth = 0; static bool global_dirty_log = false; @@ -29,6 +28,9 @@ static bool global_dirty_log = false; static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners = QTAILQ_HEAD_INITIALIZER(memory_listeners); +static QTAILQ_HEAD(, AddressSpace) address_spaces + = QTAILQ_HEAD_INITIALIZER(address_spaces); + typedef struct AddrRange AddrRange; /* @@ -97,13 +99,17 @@ static bool memory_listener_match(MemoryListener *listener, switch (_direction) { \ case Forward: \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - _listener->_callback(_listener, ##_args); \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ } \ break; \ case Reverse: \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ memory_listeners, link) { \ - _listener->_callback(_listener, ##_args); \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ } \ break; \ default: \ @@ -118,7 +124,8 @@ static bool memory_listener_match(MemoryListener *listener, switch (_direction) { \ case Forward: \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - if (memory_listener_match(_listener, _section)) { \ + if (_listener->_callback \ + && memory_listener_match(_listener, _section)) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -126,7 +133,8 @@ static bool memory_listener_match(MemoryListener *listener, case Reverse: \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ memory_listeners, link) { \ - if (memory_listener_match(_listener, _section)) { \ + if (_listener->_callback \ + && memory_listener_match(_listener, _section)) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -139,7 +147,7 @@ static bool memory_listener_match(MemoryListener *listener, #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \ MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ .mr = (fr)->mr, \ - .address_space = (as)->root, \ + .address_space = (as), \ .offset_within_region = (fr)->offset_in_region, \ .size = int128_get64((fr)->addr.size), \ .offset_within_address_space = int128_get64((fr)->addr.start), \ @@ -217,17 +225,8 @@ struct FlatView { unsigned nr_allocated; }; -typedef struct AddressSpace AddressSpace; typedef struct AddressSpaceOps AddressSpaceOps; -/* A system address space - I/O, memory, etc. */ -struct AddressSpace { - MemoryRegion *root; - FlatView current_map; - int ioeventfd_nb; - MemoryRegionIoeventfd *ioeventfds; -}; - #define FOR_EACH_FLAT_RANGE(var, view) \ for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) @@ -365,8 +364,6 @@ static void access_with_adjusted_size(target_phys_addr_t addr, } } -static AddressSpace address_space_memory; - static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset, unsigned width, bool write) { @@ -455,18 +452,17 @@ const IORangeOps memory_region_iorange_ops = { .destructor = memory_region_iorange_destructor, }; -static AddressSpace address_space_io; - static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) { + AddressSpace *as; + 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; + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (mr == as->root) { + return as; + } } abort(); } @@ -568,8 +564,10 @@ static FlatView generate_memory_topology(MemoryRegion *mr) flatview_init(&view); - render_memory_region(&view, mr, int128_zero(), - addrrange_make(int128_zero(), int128_2_64()), false); + if (mr) { + render_memory_region(&view, mr, int128_zero(), + addrrange_make(int128_zero(), int128_2_64()), false); + } flatview_simplify(&view); return view; @@ -597,7 +595,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, fds_new[inew]))) { fd = &fds_old[iold]; section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fd->addr.start), .size = int128_get64(fd->addr.size), }; @@ -610,7 +608,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, fds_old[iold]))) { fd = &fds_new[inew]; section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fd->addr.start), .size = int128_get64(fd->addr.size), }; @@ -632,7 +630,7 @@ static void address_space_update_ioeventfds(AddressSpace *as) AddrRange tmp; unsigned i; - FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { for (i = 0; i < fr->mr->ioeventfd_nb; ++i) { tmp = addrrange_shift(fr->mr->ioeventfds[i].addr, int128_sub(fr->addr.start, @@ -720,13 +718,13 @@ static void address_space_update_topology_pass(AddressSpace *as, static void address_space_update_topology(AddressSpace *as) { - FlatView old_view = as->current_map; + FlatView old_view = *as->current_map; FlatView new_view = generate_memory_topology(as->root); address_space_update_topology_pass(as, old_view, new_view, false); address_space_update_topology_pass(as, old_view, new_view, true); - as->current_map = new_view; + *as->current_map = new_view; flatview_destroy(&old_view); address_space_update_ioeventfds(as); } @@ -739,16 +737,15 @@ void memory_region_transaction_begin(void) void memory_region_transaction_commit(void) { + AddressSpace *as; + assert(memory_region_transaction_depth); --memory_region_transaction_depth; if (!memory_region_transaction_depth) { MEMORY_LISTENER_CALL_GLOBAL(begin, Forward); - if (address_space_memory.root) { - address_space_update_topology(&address_space_memory); - } - if (address_space_io.root) { - address_space_update_topology(&address_space_io); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + address_space_update_topology(as); } MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); @@ -1082,12 +1079,14 @@ void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr, void memory_region_sync_dirty_bitmap(MemoryRegion *mr) { + AddressSpace *as; FlatRange *fr; - FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { - if (fr->mr == mr) { - MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, - Forward, log_sync); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { + if (fr->mr == mr) { + MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); + } } } } @@ -1130,16 +1129,24 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) 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; CoalescedMemoryRange *cmr; AddrRange tmp; + MemoryRegionSection section; - FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { if (fr->mr == mr) { - qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); + section = (MemoryRegionSection) { + .address_space = as, + .offset_within_address_space = int128_get64(fr->addr.start), + .size = int128_get64(fr->addr.size), + }; + + MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, §ion, + int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); QTAILQ_FOREACH(cmr, &mr->coalesced, link) { tmp = addrrange_shift(cmr->addr, int128_sub(fr->addr.start, @@ -1148,13 +1155,23 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr) continue; } tmp = addrrange_intersection(tmp, fr->addr); - qemu_register_coalesced_mmio(int128_get64(tmp.start), - int128_get64(tmp.size)); + MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, §ion, + int128_get64(tmp.start), + int128_get64(tmp.size)); } } } } +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) { memory_region_clear_coalescing(mr); @@ -1400,7 +1417,7 @@ static int cmp_flatrange_addr(const void *addr_, const void *fr_) static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr) { - return bsearch(&addr, as->current_map.ranges, as->current_map.nr, + return bsearch(&addr, as->current_map->ranges, as->current_map->nr, sizeof(FlatRange), cmp_flatrange_addr); } @@ -1417,7 +1434,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, return ret; } - while (fr > as->current_map.ranges + while (fr > as->current_map->ranges && addrrange_intersects(fr[-1].addr, range)) { --fr; } @@ -1438,7 +1455,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) AddressSpace *as = memory_region_to_address_space(address_space); FlatRange *fr; - FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); } } @@ -1461,29 +1478,35 @@ static void listener_add_address_space(MemoryListener *listener, FlatRange *fr; if (listener->address_space_filter - && listener->address_space_filter != as->root) { + && listener->address_space_filter != as) { return; } if (global_dirty_log) { - listener->log_global_start(listener); + if (listener->log_global_start) { + listener->log_global_start(listener); + } } - FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + + FOR_EACH_FLAT_RANGE(fr, as->current_map) { MemoryRegionSection section = { .mr = fr->mr, - .address_space = as->root, + .address_space = as, .offset_within_region = fr->offset_in_region, .size = int128_get64(fr->addr.size), .offset_within_address_space = int128_get64(fr->addr.start), .readonly = fr->readonly, }; - listener->region_add(listener, §ion); + if (listener->region_add) { + listener->region_add(listener, §ion); + } } } -void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) +void memory_listener_register(MemoryListener *listener, AddressSpace *filter) { MemoryListener *other = NULL; + AddressSpace *as; listener->address_space_filter = filter; if (QTAILQ_EMPTY(&memory_listeners) @@ -1498,8 +1521,10 @@ void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) } 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) @@ -1507,18 +1532,28 @@ void memory_listener_unregister(MemoryListener *listener) QTAILQ_REMOVE(&memory_listeners, listener, link); } -void set_system_memory_map(MemoryRegion *mr) +void address_space_init(AddressSpace *as, MemoryRegion *root) { memory_region_transaction_begin(); - address_space_memory.root = mr; + as->root = root; + as->current_map = g_new(FlatView, 1); + flatview_init(as->current_map); + QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); + as->name = NULL; memory_region_transaction_commit(); + address_space_init_dispatch(as); } -void set_system_io_map(MemoryRegion *mr) +void address_space_destroy(AddressSpace *as) { + /* Flush out anything from MemoryListeners listening in on this */ memory_region_transaction_begin(); - address_space_io.root = mr; + as->root = NULL; memory_region_transaction_commit(); + QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); + address_space_destroy_dispatch(as); + flatview_destroy(as->current_map); + g_free(as->current_map); } uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) @@ -1638,16 +1673,16 @@ void mtree_info(fprintf_function mon_printf, void *f) { MemoryRegionListHead ml_head; MemoryRegionList *ml, *ml2; + AddressSpace *as; QTAILQ_INIT(&ml_head); - mon_printf(f, "memory\n"); - mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head); - - if (address_space_io.root && - !QTAILQ_EMPTY(&address_space_io.root->subregions)) { - mon_printf(f, "I/O\n"); - mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (!as->name) { + continue; + } + mon_printf(f, "%s\n", as->name); + mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head); } mon_printf(f, "aliases\n"); diff --git a/memory.h b/memory.h index 37ce1517ca..79393f1a76 100644 --- a/memory.h +++ b/memory.h @@ -157,6 +157,22 @@ struct MemoryRegionPortio { #define PORTIO_END_OF_LIST() { } +typedef struct AddressSpace AddressSpace; + +/** + * AddressSpace: describes a mapping of addresses to #MemoryRegion objects + */ +struct AddressSpace { + /* All fields are private. */ + const char *name; + MemoryRegion *root; + struct FlatView *current_map; + int ioeventfd_nb; + struct MemoryRegionIoeventfd *ioeventfds; + struct AddressSpaceDispatch *dispatch; + QTAILQ_ENTRY(AddressSpace) address_spaces_link; +}; + typedef struct MemoryRegionSection MemoryRegionSection; /** @@ -172,7 +188,7 @@ typedef struct MemoryRegionSection MemoryRegionSection; */ struct MemoryRegionSection { MemoryRegion *mr; - MemoryRegion *address_space; + AddressSpace *address_space; target_phys_addr_t offset_within_region; uint64_t size; target_phys_addr_t offset_within_address_space; @@ -202,9 +218,13 @@ struct MemoryListener { bool match_data, uint64_t data, EventNotifier *e); void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section, bool match_data, uint64_t data, EventNotifier *e); + void (*coalesced_mmio_add)(MemoryListener *listener, MemoryRegionSection *section, + target_phys_addr_t addr, target_phys_addr_t len); + void (*coalesced_mmio_del)(MemoryListener *listener, MemoryRegionSection *section, + target_phys_addr_t addr, target_phys_addr_t len); /* Lower = earlier (during add), later (during del) */ unsigned priority; - MemoryRegion *address_space_filter; + AddressSpace *address_space_filter; QTAILQ_ENTRY(MemoryListener) link; }; @@ -755,7 +775,7 @@ void memory_region_transaction_commit(void); * @listener: an object containing the callbacks to be called * @filter: if non-%NULL, only regions in this address space will be observed */ -void memory_listener_register(MemoryListener *listener, MemoryRegion *filter); +void memory_listener_register(MemoryListener *listener, AddressSpace *filter); /** * memory_listener_unregister: undo the effect of memory_listener_register() @@ -776,6 +796,87 @@ void memory_global_dirty_log_stop(void); void mtree_info(fprintf_function mon_printf, void *f); +/** + * address_space_init: initializes an address space + * + * @as: an uninitialized #AddressSpace + * @root: a #MemoryRegion that routes addesses for the address space + */ +void address_space_init(AddressSpace *as, MemoryRegion *root); + + +/** + * address_space_destroy: destroy an address space + * + * Releases all resources associated with an address space. After an address space + * is destroyed, its root memory region (given by address_space_init()) may be destroyed + * as well. + * + * @as: address space to be destroyed + */ +void address_space_destroy(AddressSpace *as); + +/** + * address_space_rw: read from or write to an address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + * @is_write: indicates the transfer direction + */ +void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, + int len, bool is_write); + +/** + * address_space_write: write to address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + */ +void address_space_write(AddressSpace *as, target_phys_addr_t addr, + const uint8_t *buf, int len); + +/** + * address_space_read: read from an address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + */ +void address_space_read(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, int len); + +/* address_space_map: map a physical memory region into a host virtual address + * + * May map a subset of the requested range, given by and returned in @plen. + * May return %NULL if resources needed to perform the mapping are exhausted. + * Use only for reads OR writes - not for read-modify-write operations. + * Use cpu_register_map_client() to know when retrying the map operation is + * likely to succeed. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @plen: pointer to length of buffer; updated on return + * @is_write: indicates the transfer direction + */ +void *address_space_map(AddressSpace *as, target_phys_addr_t addr, + target_phys_addr_t *plen, bool is_write); + +/* address_space_unmap: Unmaps a memory region previously mapped by address_space_map() + * + * Will also mark the memory as dirty if @is_write == %true. @access_len gives + * the amount of memory that was actually read or written by the caller. + * + * @as: #AddressSpace used + * @addr: address within that address space + * @len: buffer length as returned by address_space_map() + * @access_len: amount of data actually transferred + * @is_write: indicates the transfer direction + */ +void address_space_unmap(AddressSpace *as, void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len); + + #endif #endif diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index e9b3caed49..fdccd58e3d 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -20,7 +20,6 @@ #include "cpu.h" #include "memory.h" -#include "cputlb.h" #include "host-utils.h" #include "helper.h" #include @@ -81,7 +80,7 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) #endif /* basic checks */ - if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { + if (cpu_physical_memory_is_io(sccb)) { return -PGM_ADDRESSING; } if (sccb & ~0x7ffffff8ul) { diff --git a/xen-all.c b/xen-all.c index bcb7ef7c84..9d1e168826 100644 --- a/xen-all.c +++ b/xen-all.c @@ -454,14 +454,6 @@ static void xen_set_memory(struct MemoryListener *listener, } } -static void xen_begin(MemoryListener *listener) -{ -} - -static void xen_commit(MemoryListener *listener) -{ -} - static void xen_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -474,11 +466,6 @@ static void xen_region_del(MemoryListener *listener, xen_set_memory(listener, section, false); } -static void xen_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void xen_sync_dirty_bitmap(XenIOState *state, target_phys_addr_t start_addr, ram_addr_t size) @@ -565,33 +552,14 @@ static void xen_log_global_stop(MemoryListener *listener) xen_in_migration = false; } -static void xen_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ -} - -static void xen_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ -} - static MemoryListener xen_memory_listener = { - .begin = xen_begin, - .commit = xen_commit, .region_add = xen_region_add, .region_del = xen_region_del, - .region_nop = xen_region_nop, .log_start = xen_log_start, .log_stop = xen_log_stop, .log_sync = xen_log_sync, .log_global_start = xen_log_global_start, .log_global_stop = xen_log_global_stop, - .eventfd_add = xen_eventfd_add, - .eventfd_del = xen_eventfd_del, .priority = 10, }; @@ -1173,7 +1141,7 @@ int xen_hvm_init(void) state->memory_listener = xen_memory_listener; QLIST_INIT(&state->physmap); - memory_listener_register(&state->memory_listener, get_system_memory()); + memory_listener_register(&state->memory_listener, &address_space_memory); state->log_for_dirtybit = NULL; /* Initialize backend core & drivers */