Merge remote-tracking branch 'qemu-kvm/memory/dma' into staging

* qemu-kvm/memory/dma: (23 commits)
  pci: honor PCI_COMMAND_MASTER
  pci: give each device its own address space
  memory: add address_space_destroy()
  dma: make dma access its own address space
  memory: per-AddressSpace dispatch
  s390: avoid reaching into memory core internals
  memory: use AddressSpace for MemoryListener filtering
  memory: move tcg flush into a tcg memory listener
  memory: move address_space_memory and address_space_io out of memory core
  memory: manage coalesced mmio via a MemoryListener
  xen: drop no-op MemoryListener callbacks
  kvm: drop no-op MemoryListener callbacks
  xen_pt: drop no-op MemoryListener callbacks
  vfio: drop no-op MemoryListener callbacks
  memory: drop no-op MemoryListener callbacks
  memory: provide defaults for MemoryListener operations
  memory: maintain a list of address spaces
  memory: export AddressSpace
  memory: prepare AddressSpace for exporting
  xen_pt: use separate MemoryListeners for memory and I/O
  ...
This commit is contained in:
Anthony Liguori 2012-10-22 13:26:07 -05:00
commit d3e2efc5b5
21 changed files with 485 additions and 472 deletions

View File

@ -21,11 +21,11 @@
#include "cpu.h" #include "cpu.h"
#include "exec-all.h" #include "exec-all.h"
#include "memory.h" #include "memory.h"
#include "exec-memory.h"
#include "cputlb.h" #include "cputlb.h"
#define WANT_EXEC_OBSOLETE #include "memory-internal.h"
#include "exec-obsolete.h"
//#define DEBUG_TLB //#define DEBUG_TLB
//#define DEBUG_TLB_CHECK //#define DEBUG_TLB_CHECK
@ -252,7 +252,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
if (size != TARGET_PAGE_SIZE) { if (size != TARGET_PAGE_SIZE) {
tlb_add_large_page(env, vaddr, 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) #if defined(DEBUG_TLB)
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
" prot=%x idx=%d pd=0x%08lx\n", " prot=%x idx=%d pd=0x%08lx\n",

View File

@ -26,7 +26,8 @@ void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
target_ulong vaddr); target_ulong vaddr);
void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start, void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
uintptr_t length); 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 cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length);
void tlb_set_dirty(CPUArchState *env, target_ulong vaddr); void tlb_set_dirty(CPUArchState *env, target_ulong vaddr);
extern int tlb_flush_count; extern int tlb_flush_count;

View File

@ -14,7 +14,8 @@
/* #define DEBUG_IOMMU */ /* #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 #define FILLBUF_SIZE 512
uint8_t fillbuf[FILLBUF_SIZE]; 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); memset(fillbuf, c, FILLBUF_SIZE);
while (len > 0) { while (len > 0) {
l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; 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; len -= l;
addr += 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)) { if (dma_has_iommu(dma)) {
return iommu_dma_memory_set(dma, addr, c, len); 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; return 0;
} }
@ -332,8 +333,7 @@ int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr,
plen = len; plen = len;
} }
cpu_physical_memory_rw(paddr, buf, plen, address_space_rw(dma->as, paddr, buf, plen, dir == DMA_DIRECTION_FROM_DEVICE);
dir == DMA_DIRECTION_FROM_DEVICE);
len -= plen; len -= plen;
addr += plen; addr += plen;
@ -366,7 +366,7 @@ int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c,
plen = len; plen = len;
} }
do_dma_memory_set(paddr, c, plen); do_dma_memory_set(dma->as, paddr, c, plen);
len -= plen; len -= plen;
addr += plen; addr += plen;
@ -375,13 +375,14 @@ int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c,
return 0; return 0;
} }
void dma_context_init(DMAContext *dma, DMATranslateFunc translate, void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate,
DMAMapFunc map, DMAUnmapFunc unmap) DMAMapFunc map, DMAUnmapFunc unmap)
{ {
#ifdef DEBUG_IOMMU #ifdef DEBUG_IOMMU
fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n", fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n",
dma, translate, map, unmap); dma, translate, map, unmap);
#endif #endif
dma->as = as;
dma->translate = translate; dma->translate = translate;
dma->map = map; dma->map = map;
dma->unmap = unmap; 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, * If this is true, the virtual region is contiguous,
* but the translated physical region isn't. We just * 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) { if (plen < *len) {
*len = plen; *len = plen;
} }
buf = cpu_physical_memory_map(paddr, &plen, buf = address_space_map(dma->as, paddr, &plen, dir == DMA_DIRECTION_FROM_DEVICE);
dir == DMA_DIRECTION_FROM_DEVICE);
*len = plen; *len = plen;
return buf; return buf;
@ -428,8 +428,7 @@ void iommu_dma_memory_unmap(DMAContext *dma, void *buffer, dma_addr_t len,
return; return;
} }
cpu_physical_memory_unmap(buffer, len, address_space_unmap(dma->as, buffer, len, dir == DMA_DIRECTION_FROM_DEVICE,
dir == DMA_DIRECTION_FROM_DEVICE, access_len);
access_len);
} }

17
dma.h
View File

@ -11,6 +11,7 @@
#define DMA_H #define DMA_H
#include <stdio.h> #include <stdio.h>
#include "memory.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "block.h" #include "block.h"
#include "kvm.h" #include "kvm.h"
@ -61,6 +62,7 @@ typedef void DMAUnmapFunc(DMAContext *dma,
dma_addr_t access_len); dma_addr_t access_len);
struct DMAContext { struct DMAContext {
AddressSpace *as;
DMATranslateFunc *translate; DMATranslateFunc *translate;
DMAMapFunc *map; DMAMapFunc *map;
DMAUnmapFunc *unmap; DMAUnmapFunc *unmap;
@ -93,7 +95,7 @@ static inline void dma_barrier(DMAContext *dma, DMADirection dir)
static inline bool dma_has_iommu(DMAContext *dma) 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 /* 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)) { if (!dma_has_iommu(dma)) {
/* Fast-path for no IOMMU */ /* Fast-path for no IOMMU */
cpu_physical_memory_rw(addr, buf, len, address_space_rw(dma->as, addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE);
dir == DMA_DIRECTION_FROM_DEVICE);
return 0; return 0;
} else { } else {
return iommu_dma_memory_rw(dma, addr, buf, len, dir); 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; target_phys_addr_t xlen = *len;
void *p; void *p;
p = cpu_physical_memory_map(addr, &xlen, p = address_space_map(dma->as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE);
dir == DMA_DIRECTION_FROM_DEVICE);
*len = xlen; *len = xlen;
return p; return p;
} else { } else {
@ -196,9 +196,8 @@ static inline void dma_memory_unmap(DMAContext *dma,
DMADirection dir, dma_addr_t access_len) DMADirection dir, dma_addr_t access_len)
{ {
if (!dma_has_iommu(dma)) { if (!dma_has_iommu(dma)) {
cpu_physical_memory_unmap(buffer, (target_phys_addr_t)len, address_space_unmap(dma->as, buffer, (target_phys_addr_t)len,
dir == DMA_DIRECTION_FROM_DEVICE, dir == DMA_DIRECTION_FROM_DEVICE, access_len);
access_len);
} else { } else {
iommu_dma_memory_unmap(dma, buffer, len, dir, access_len); 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 #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); DMAMapFunc map, DMAUnmapFunc unmap);
struct ScatterGatherEntry { struct ScatterGatherEntry {

View File

@ -33,11 +33,8 @@ MemoryRegion *get_system_memory(void);
*/ */
MemoryRegion *get_system_io(void); MemoryRegion *get_system_io(void);
/* Set the root memory region. This region is the system memory map. */ extern AddressSpace address_space_memory;
void set_system_memory_map(MemoryRegion *mr); extern AddressSpace address_space_io;
/* Set the I/O memory region. This region is the I/O memory map. */
void set_system_io_map(MemoryRegion *mr);
#endif #endif

317
exec.c
View File

@ -59,8 +59,7 @@
#include "cputlb.h" #include "cputlb.h"
#define WANT_EXEC_OBSOLETE #include "memory-internal.h"
#include "exec-obsolete.h"
//#define DEBUG_TB_INVALIDATE //#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH //#define DEBUG_FLUSH
@ -102,6 +101,9 @@ RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) };
static MemoryRegion *system_memory; static MemoryRegion *system_memory;
static MemoryRegion *system_io; 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; MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty;
static MemoryRegion io_mem_subpage_ram; static MemoryRegion io_mem_subpage_ram;
@ -170,7 +172,6 @@ uintptr_t qemu_host_page_mask;
static void *l1_map[V_L1_SIZE]; static void *l1_map[V_L1_SIZE];
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
typedef struct PhysPageEntry PhysPageEntry;
static MemoryRegionSection *phys_sections; static MemoryRegionSection *phys_sections;
static unsigned phys_sections_nb, phys_sections_nb_alloc; 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_rom;
static uint16_t phys_section_watch; 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 */ /* Simple allocator for PhysPageEntry nodes */
static PhysPageEntry (*phys_map_nodes)[L2_SIZE]; static PhysPageEntry (*phys_map_nodes)[L2_SIZE];
static unsigned phys_map_nodes_nb, phys_map_nodes_nb_alloc; static unsigned phys_map_nodes_nb, phys_map_nodes_nb_alloc;
#define PHYS_MAP_NODE_NIL (((uint16_t)~0) >> 1) #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 io_mem_init(void);
static void memory_map_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) uint16_t leaf)
{ {
/* Wildly overreserve - it doesn't matter much. */ /* Wildly overreserve - it doesn't matter much. */
phys_map_node_reserve(3 * P_L2_LEVELS); 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; PhysPageEntry *p;
int i; int i;
uint16_t s_index = phys_section_unassigned; 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; ram_addr_t ram_addr;
MemoryRegionSection *section; 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) if (!(memory_region_is_ram(section->mr)
|| (section->mr->rom_device && section->mr->readable))) { || (section->mr->rom_device && section->mr->readable))) {
return; return;
@ -2224,9 +2216,9 @@ static void destroy_l2_mapping(PhysPageEntry *lp, unsigned level)
lp->ptr = PHYS_MAP_NODE_NIL; 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(); phys_map_nodes_reset();
} }
@ -2246,12 +2238,12 @@ static void phys_sections_clear(void)
phys_sections_nb = 0; phys_sections_nb = 0;
} }
static void register_subpage(MemoryRegionSection *section) static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section)
{ {
subpage_t *subpage; subpage_t *subpage;
target_phys_addr_t base = section->offset_within_address_space target_phys_addr_t base = section->offset_within_address_space
& TARGET_PAGE_MASK; & TARGET_PAGE_MASK;
MemoryRegionSection *existing = phys_page_find(base >> TARGET_PAGE_BITS); MemoryRegionSection *existing = phys_page_find(d, base >> TARGET_PAGE_BITS);
MemoryRegionSection subsection = { MemoryRegionSection subsection = {
.offset_within_address_space = base, .offset_within_address_space = base,
.size = TARGET_PAGE_SIZE, .size = TARGET_PAGE_SIZE,
@ -2263,7 +2255,7 @@ static void register_subpage(MemoryRegionSection *section)
if (!(existing->mr->subpage)) { if (!(existing->mr->subpage)) {
subpage = subpage_init(base); subpage = subpage_init(base);
subsection.mr = &subpage->iomem; 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)); phys_section_add(&subsection));
} else { } else {
subpage = container_of(existing->mr, subpage_t, iomem); 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; target_phys_addr_t start_addr = section->offset_within_address_space;
ram_addr_t size = section->size; ram_addr_t size = section->size;
@ -2284,13 +2276,13 @@ static void register_multipage(MemoryRegionSection *section)
assert(size); assert(size);
addr = start_addr; 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); section_index);
} }
void cpu_register_physical_memory_log(MemoryRegionSection *section, static void mem_add(MemoryListener *listener, MemoryRegionSection *section)
bool readonly)
{ {
AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener);
MemoryRegionSection now = *section, remain = *section; MemoryRegionSection now = *section, remain = *section;
if ((now.offset_within_address_space & ~TARGET_PAGE_MASK) 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.size = MIN(TARGET_PAGE_ALIGN(now.offset_within_address_space)
- now.offset_within_address_space, - now.offset_within_address_space,
now.size); now.size);
register_subpage(&now); register_subpage(d, &now);
remain.size -= now.size; remain.size -= now.size;
remain.offset_within_address_space += now.size; remain.offset_within_address_space += now.size;
remain.offset_within_region += now.size; remain.offset_within_region += now.size;
@ -2307,10 +2299,10 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section,
now = remain; now = remain;
if (remain.offset_within_region & ~TARGET_PAGE_MASK) { if (remain.offset_within_region & ~TARGET_PAGE_MASK) {
now.size = TARGET_PAGE_SIZE; now.size = TARGET_PAGE_SIZE;
register_subpage(&now); register_subpage(d, &now);
} else { } else {
now.size &= TARGET_PAGE_MASK; now.size &= TARGET_PAGE_MASK;
register_multipage(&now); register_multipage(d, &now);
} }
remain.size -= now.size; remain.size -= now.size;
remain.offset_within_address_space += now.size; remain.offset_within_address_space += now.size;
@ -2318,23 +2310,10 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section,
} }
now = remain; now = remain;
if (now.size) { 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) void qemu_flush_coalesced_mmio_buffer(void)
{ {
if (kvm_enabled()) if (kvm_enabled())
@ -3182,18 +3161,24 @@ static void io_mem_init(void)
"watch", UINT64_MAX); "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) static void core_begin(MemoryListener *listener)
{ {
destroy_all_mappings();
phys_sections_clear(); phys_sections_clear();
phys_map.ptr = PHYS_MAP_NODE_NIL;
phys_section_unassigned = dummy_section(&io_mem_unassigned); phys_section_unassigned = dummy_section(&io_mem_unassigned);
phys_section_notdirty = dummy_section(&io_mem_notdirty); phys_section_notdirty = dummy_section(&io_mem_notdirty);
phys_section_rom = dummy_section(&io_mem_rom); phys_section_rom = dummy_section(&io_mem_rom);
phys_section_watch = dummy_section(&io_mem_watch); phys_section_watch = dummy_section(&io_mem_watch);
} }
static void core_commit(MemoryListener *listener) static void tcg_commit(MemoryListener *listener)
{ {
CPUArchState *env; 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) static void core_log_global_start(MemoryListener *listener)
{ {
cpu_physical_memory_set_dirty_tracking(1); 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); 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, static void io_region_add(MemoryListener *listener,
MemoryRegionSection *section) MemoryRegionSection *section)
{ {
@ -3285,90 +3218,63 @@ static void io_region_del(MemoryListener *listener,
isa_unassign_ioport(section->offset_within_address_space, section->size); 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 = { static MemoryListener core_memory_listener = {
.begin = core_begin, .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_start = core_log_global_start,
.log_global_stop = core_log_global_stop, .log_global_stop = core_log_global_stop,
.eventfd_add = core_eventfd_add, .priority = 1,
.eventfd_del = core_eventfd_del,
.priority = 0,
}; };
static MemoryListener io_memory_listener = { static MemoryListener io_memory_listener = {
.begin = io_begin,
.commit = io_commit,
.region_add = io_region_add, .region_add = io_region_add,
.region_del = io_region_del, .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, .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) static void memory_map_init(void)
{ {
system_memory = g_malloc(sizeof(*system_memory)); system_memory = g_malloc(sizeof(*system_memory));
memory_region_init(system_memory, "system", INT64_MAX); 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)); system_io = g_malloc(sizeof(*system_io));
memory_region_init(system_io, "io", 65536); 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(&core_memory_listener, &address_space_memory);
memory_listener_register(&io_memory_listener, system_io); memory_listener_register(&io_memory_listener, &address_space_io);
memory_listener_register(&tcg_memory_listener, &address_space_memory);
} }
MemoryRegion *get_system_memory(void) 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); xen_modified_memory(addr, length);
} }
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf,
int len, int is_write) int len, bool is_write)
{ {
AddressSpaceDispatch *d = as->dispatch;
int l; int l;
uint8_t *ptr; uint8_t *ptr;
uint32_t val; 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; l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len) if (l > len)
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 (is_write) {
if (!memory_region_is_ram(section->mr)) { 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 */ /* used for ROM loading : can write in RAM and ROM */
void cpu_physical_memory_write_rom(target_phys_addr_t addr, void cpu_physical_memory_write_rom(target_phys_addr_t addr,
const uint8_t *buf, int len) const uint8_t *buf, int len)
{ {
AddressSpaceDispatch *d = address_space_memory.dispatch;
int l; int l;
uint8_t *ptr; uint8_t *ptr;
target_phys_addr_t page; 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; l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len) if (l > len)
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) || if (!(memory_region_is_ram(section->mr) ||
memory_region_is_romd(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 * Use cpu_register_map_client() to know when retrying the map operation is
* likely to succeed. * likely to succeed.
*/ */
void *cpu_physical_memory_map(target_phys_addr_t addr, void *address_space_map(AddressSpace *as,
target_phys_addr_t *plen, target_phys_addr_t addr,
int is_write) target_phys_addr_t *plen,
bool is_write)
{ {
AddressSpaceDispatch *d = as->dispatch;
target_phys_addr_t len = *plen; target_phys_addr_t len = *plen;
target_phys_addr_t todo = 0; target_phys_addr_t todo = 0;
int l; int l;
@ -3629,7 +3564,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
l = (page + TARGET_PAGE_SIZE) - addr; l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len) if (l > len)
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 (!(memory_region_is_ram(section->mr) && !section->readonly)) {
if (todo || bounce.buffer) { if (todo || bounce.buffer) {
@ -3639,7 +3574,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
bounce.addr = addr; bounce.addr = addr;
bounce.len = l; bounce.len = l;
if (!is_write) { if (!is_write) {
cpu_physical_memory_read(addr, bounce.buffer, l); address_space_read(as, addr, bounce.buffer, l);
} }
*plen = l; *plen = l;
@ -3660,12 +3595,12 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
return ret; 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 * 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. * 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, void address_space_unmap(AddressSpace *as, void *buffer, target_phys_addr_t len,
int is_write, target_phys_addr_t access_len) int is_write, target_phys_addr_t access_len)
{ {
if (buffer != bounce.buffer) { if (buffer != bounce.buffer) {
if (is_write) { if (is_write) {
@ -3686,13 +3621,26 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
return; return;
} }
if (is_write) { 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); qemu_vfree(bounce.buffer);
bounce.buffer = NULL; bounce.buffer = NULL;
cpu_notify_map_clients(); 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 */ /* warning: addr must be aligned */
static inline uint32_t ldl_phys_internal(target_phys_addr_t addr, static inline uint32_t ldl_phys_internal(target_phys_addr_t addr,
enum device_endian endian) enum device_endian endian)
@ -3701,7 +3649,7 @@ static inline uint32_t ldl_phys_internal(target_phys_addr_t addr,
uint32_t val; uint32_t val;
MemoryRegionSection *section; 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) || if (!(memory_region_is_ram(section->mr) ||
memory_region_is_romd(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; uint64_t val;
MemoryRegionSection *section; 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) || if (!(memory_region_is_ram(section->mr) ||
memory_region_is_romd(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; uint64_t val;
MemoryRegionSection *section; 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) || if (!(memory_region_is_ram(section->mr) ||
memory_region_is_romd(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; uint8_t *ptr;
MemoryRegionSection *section; 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) { if (!memory_region_is_ram(section->mr) || section->readonly) {
addr = memory_region_section_addr(section, addr); 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; uint8_t *ptr;
MemoryRegionSection *section; 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) { if (!memory_region_is_ram(section->mr) || section->readonly) {
addr = memory_region_section_addr(section, addr); 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; uint8_t *ptr;
MemoryRegionSection *section; 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) { if (!memory_region_is_ram(section->mr) || section->readonly) {
addr = memory_region_section_addr(section, addr); 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; uint8_t *ptr;
MemoryRegionSection *section; 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) { if (!memory_region_is_ram(section->mr) || section->readonly) {
addr = memory_region_section_addr(section, addr); 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; 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) || return !(memory_region_is_ram(section->mr) ||
memory_region_is_romd(section->mr)); memory_region_is_romd(section->mr));

View File

@ -33,6 +33,7 @@
#include "qmp-commands.h" #include "qmp-commands.h"
#include "msi.h" #include "msi.h"
#include "msix.h" #include "msix.h"
#include "exec-memory.h"
//#define DEBUG_PCI //#define DEBUG_PCI
#ifdef DEBUG_PCI #ifdef DEBUG_PCI
@ -777,6 +778,17 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
pci_dev->bus = bus; pci_dev->bus = bus;
if (bus->dma_context_fn) { if (bus->dma_context_fn) {
pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); 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; pci_dev->devfn = devfn;
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); 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); qemu_free_irqs(pci_dev->irq);
pci_dev->bus->devices[pci_dev->devfn] = NULL; pci_dev->bus->devices[pci_dev->devfn] = NULL;
pci_config_free(pci_dev); 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) 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)) range_covers_byte(addr, l, PCI_COMMAND))
pci_update_mappings(d); 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); 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); msi_write_config(d, addr, val, l);
msix_write_config(d, addr, val, l); msix_write_config(d, addr, val, l);

View File

@ -211,6 +211,8 @@ struct PCIDevice {
int32_t devfn; int32_t devfn;
char name[64]; char name[64];
PCIIORegion io_regions[PCI_NUM_REGIONS]; PCIIORegion io_regions[PCI_NUM_REGIONS];
AddressSpace bus_master_as;
MemoryRegion bus_master_enable_region;
DMAContext *dma; DMAContext *dma;
/* do not access the following fields */ /* do not access the following fields */

View File

@ -21,6 +21,7 @@
#include "qdev.h" #include "qdev.h"
#include "kvm_ppc.h" #include "kvm_ppc.h"
#include "dma.h" #include "dma.h"
#include "exec-memory.h"
#include "hw/spapr.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)); 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->liobn = liobn;
tcet->window_size = window_size; tcet->window_size = window_size;

View File

@ -930,25 +930,6 @@ static int vfio_dma_map(VFIOContainer *container, target_phys_addr_t iova,
return -errno; 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) static bool vfio_listener_skipped_section(MemoryRegionSection *section)
{ {
return !memory_region_is_ram(section->mr); return !memory_region_is_ram(section->mr);
@ -1040,18 +1021,8 @@ static void vfio_listener_region_del(MemoryListener *listener,
} }
static MemoryListener vfio_memory_listener = { static MemoryListener vfio_memory_listener = {
.begin = vfio_listener_dummy1,
.commit = vfio_listener_dummy1,
.region_add = vfio_listener_region_add, .region_add = vfio_listener_region_add,
.region_del = vfio_listener_region_del, .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) 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.listener = vfio_memory_listener;
container->iommu_data.release = vfio_listener_release; container->iommu_data.release = vfio_listener_release;
memory_listener_register(&container->iommu_data.listener, memory_listener_register(&container->iommu_data.listener, &address_space_memory);
get_system_memory());
} else { } else {
error_report("vfio: No available IOMMU models\n"); error_report("vfio: No available IOMMU models\n");
g_free(container); g_free(container);

View File

@ -434,8 +434,7 @@ static void vhost_set_memory(MemoryListener *listener,
static bool vhost_section(MemoryRegionSection *section) static bool vhost_section(MemoryRegionSection *section)
{ {
return section->address_space == get_system_memory() return memory_region_is_ram(section->mr);
&& memory_region_is_ram(section->mr);
} }
static void vhost_begin(MemoryListener *listener) 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_size = 0;
hdev->log_enabled = false; hdev->log_enabled = false;
hdev->started = false; hdev->started = false;
memory_listener_register(&hdev->memory_listener, NULL); memory_listener_register(&hdev->memory_listener, &address_space_memory);
hdev->force = force; hdev->force = force;
return 0; return 0;
fail: fail:

View File

@ -59,6 +59,7 @@
#include "xen_backend.h" #include "xen_backend.h"
#include "xen_pt.h" #include "xen_pt.h"
#include "range.h" #include "range.h"
#include "exec-memory.h"
#define XEN_PT_NR_IRQS (256) #define XEN_PT_NR_IRQS (256)
static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0}; 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) static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
{ {
XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, 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); 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) xen_pt_region_update(s, sec, false);
{
}
static void xen_pt_eventfd_fns(MemoryListener *l, MemoryRegionSection *s,
bool match_data, uint64_t data, EventNotifier *n)
{
} }
static const MemoryListener xen_pt_memory_listener = { static const MemoryListener xen_pt_memory_listener = {
.begin = xen_pt_begin,
.commit = xen_pt_commit,
.region_add = xen_pt_region_add, .region_add = xen_pt_region_add,
.region_nop = xen_pt_region_nop,
.region_del = xen_pt_region_del, .region_del = xen_pt_region_del,
.log_start = xen_pt_log_fns, .priority = 10,
.log_stop = xen_pt_log_fns, };
.log_sync = xen_pt_log_fns,
.log_global_start = xen_pt_log_global_fns, static const MemoryListener xen_pt_io_listener = {
.log_global_stop = xen_pt_log_global_fns, .region_add = xen_pt_io_region_add,
.eventfd_add = xen_pt_eventfd_fns, .region_del = xen_pt_io_region_del,
.eventfd_del = xen_pt_eventfd_fns,
.priority = 10, .priority = 10,
}; };
@ -694,6 +682,7 @@ static int xen_pt_initfn(PCIDevice *d)
} }
s->memory_listener = xen_pt_memory_listener; s->memory_listener = xen_pt_memory_listener;
s->io_listener = xen_pt_io_listener;
/* Handle real device's MMIO/PIO BARs */ /* Handle real device's MMIO/PIO BARs */
xen_pt_register_regions(s); xen_pt_register_regions(s);
@ -760,7 +749,8 @@ static int xen_pt_initfn(PCIDevice *d)
} }
out: 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", XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n",
bus, slot, func); bus, slot, func);
@ -815,6 +805,7 @@ static void xen_pt_unregister_device(PCIDevice *d)
xen_pt_unregister_regions(s); xen_pt_unregister_regions(s);
memory_listener_unregister(&s->memory_listener); memory_listener_unregister(&s->memory_listener);
memory_listener_unregister(&s->io_listener);
xen_host_pci_device_put(&s->real_device); xen_host_pci_device_put(&s->real_device);
} }

View File

@ -209,6 +209,7 @@ struct XenPCIPassthroughState {
MemoryRegion rom; MemoryRegion rom;
MemoryListener memory_listener; MemoryListener memory_listener;
MemoryListener io_listener;
}; };
int xen_pt_config_init(XenPCIPassthroughState *s); int xen_pt_config_init(XenPCIPassthroughState *s);

105
kvm-all.c
View File

@ -454,9 +454,10 @@ static int kvm_physical_sync_dirty_bitmap(MemoryRegionSection *section)
return ret; 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; KVMState *s = kvm_state;
if (s->coalesced_mmio) { 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.size = size;
zone.pad = 0; 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; KVMState *s = kvm_state;
if (s->coalesced_mmio) { 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.size = size;
zone.pad = 0; 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) 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, static void kvm_region_add(MemoryListener *listener,
MemoryRegionSection *section) MemoryRegionSection *section)
{ {
@ -723,11 +713,6 @@ static void kvm_region_del(MemoryListener *listener,
kvm_set_phys_mem(section, false); kvm_set_phys_mem(section, false);
} }
static void kvm_region_nop(MemoryListener *listener,
MemoryRegionSection *section)
{
}
static void kvm_log_sync(MemoryListener *listener, static void kvm_log_sync(MemoryListener *listener,
MemoryRegionSection *section) MemoryRegionSection *section)
{ {
@ -755,9 +740,12 @@ static void kvm_log_global_stop(struct MemoryListener *listener)
assert(r >= 0); assert(r >= 0);
} }
static void kvm_mem_ioeventfd_add(MemoryRegionSection *section, static void kvm_mem_ioeventfd_add(MemoryListener *listener,
bool match_data, uint64_t data, int fd) MemoryRegionSection *section,
bool match_data, uint64_t data,
EventNotifier *e)
{ {
int fd = event_notifier_get_fd(e);
int r; int r;
assert(match_data && section->size <= 8); 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, static void kvm_mem_ioeventfd_del(MemoryListener *listener,
bool match_data, uint64_t data, int fd) MemoryRegionSection *section,
bool match_data, uint64_t data,
EventNotifier *e)
{ {
int fd = event_notifier_get_fd(e);
int r; int r;
r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space, 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, static void kvm_io_ioeventfd_add(MemoryListener *listener,
bool match_data, uint64_t data, int fd) MemoryRegionSection *section,
bool match_data, uint64_t data,
EventNotifier *e)
{ {
int fd = event_notifier_get_fd(e);
int r; int r;
assert(match_data && section->size == 2); 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, static void kvm_io_ioeventfd_del(MemoryListener *listener,
bool match_data, uint64_t data, int fd) MemoryRegionSection *section,
bool match_data, uint64_t data,
EventNotifier *e)
{ {
int fd = event_notifier_get_fd(e);
int r; int r;
r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space, 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 = { static MemoryListener kvm_memory_listener = {
.begin = kvm_begin,
.commit = kvm_commit,
.region_add = kvm_region_add, .region_add = kvm_region_add,
.region_del = kvm_region_del, .region_del = kvm_region_del,
.region_nop = kvm_region_nop,
.log_start = kvm_log_start, .log_start = kvm_log_start,
.log_stop = kvm_log_stop, .log_stop = kvm_log_stop,
.log_sync = kvm_log_sync, .log_sync = kvm_log_sync,
.log_global_start = kvm_log_global_start, .log_global_start = kvm_log_global_start,
.log_global_stop = kvm_log_global_stop, .log_global_stop = kvm_log_global_stop,
.eventfd_add = kvm_eventfd_add, .eventfd_add = kvm_mem_ioeventfd_add,
.eventfd_del = kvm_eventfd_del, .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, .priority = 10,
}; };
@ -1401,7 +1375,8 @@ int kvm_init(void)
} }
kvm_state = s; 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(); s->many_ioeventfds = kvm_check_many_ioeventfds();

View File

@ -29,16 +29,6 @@ int kvm_init_vcpu(CPUArchState *env)
return -ENOSYS; 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) int kvm_init(void)
{ {
return -ENOSYS; return -ENOSYS;

2
kvm.h
View File

@ -129,8 +129,6 @@ void *kvm_vmalloc(ram_addr_t size);
void *kvm_arch_vmalloc(ram_addr_t size); void *kvm_arch_vmalloc(ram_addr_t size);
void kvm_setup_guest_memory(void *start, size_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); void kvm_flush_coalesced_mmio_buffer(void);
#endif #endif

View File

@ -16,16 +16,33 @@
* The functions declared here will be removed soon. * The functions declared here will be removed soon.
*/ */
#ifndef EXEC_OBSOLETE_H #ifndef MEMORY_INTERNAL_H
#define EXEC_OBSOLETE_H #define MEMORY_INTERNAL_H
#ifndef WANT_EXEC_OBSOLETE
#error Do not include exec-obsolete.h
#endif
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
#include "hw/xen.h" #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, ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
MemoryRegion *mr); MemoryRegion *mr);
ram_addr_t qemu_ram_alloc(ram_addr_t size, 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 MemoryRegion;
struct MemoryRegionSection; 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_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); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);

173
memory.c
View File

@ -20,8 +20,7 @@
#include "kvm.h" #include "kvm.h"
#include <assert.h> #include <assert.h>
#define WANT_EXEC_OBSOLETE #include "memory-internal.h"
#include "exec-obsolete.h"
unsigned memory_region_transaction_depth = 0; unsigned memory_region_transaction_depth = 0;
static bool global_dirty_log = false; static bool global_dirty_log = false;
@ -29,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;
/* /*
@ -97,13 +99,17 @@ static bool memory_listener_match(MemoryListener *listener,
switch (_direction) { \ switch (_direction) { \
case Forward: \ case Forward: \
QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \
_listener->_callback(_listener, ##_args); \ if (_listener->_callback) { \
_listener->_callback(_listener, ##_args); \
} \
} \ } \
break; \ break; \
case Reverse: \ case Reverse: \
QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \
memory_listeners, link) { \ memory_listeners, link) { \
_listener->_callback(_listener, ##_args); \ if (_listener->_callback) { \
_listener->_callback(_listener, ##_args); \
} \
} \ } \
break; \ break; \
default: \ default: \
@ -118,7 +124,8 @@ static bool memory_listener_match(MemoryListener *listener,
switch (_direction) { \ switch (_direction) { \
case Forward: \ case Forward: \
QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ 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); \ _listener->_callback(_listener, _section, ##_args); \
} \ } \
} \ } \
@ -126,7 +133,8 @@ static bool memory_listener_match(MemoryListener *listener,
case Reverse: \ case Reverse: \
QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \
memory_listeners, link) { \ memory_listeners, link) { \
if (memory_listener_match(_listener, _section)) { \ if (_listener->_callback \
&& memory_listener_match(_listener, _section)) { \
_listener->_callback(_listener, _section, ##_args); \ _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) \ #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \
MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \
.mr = (fr)->mr, \ .mr = (fr)->mr, \
.address_space = (as)->root, \ .address_space = (as), \
.offset_within_region = (fr)->offset_in_region, \ .offset_within_region = (fr)->offset_in_region, \
.size = int128_get64((fr)->addr.size), \ .size = int128_get64((fr)->addr.size), \
.offset_within_address_space = int128_get64((fr)->addr.start), \ .offset_within_address_space = int128_get64((fr)->addr.start), \
@ -217,17 +225,8 @@ struct FlatView {
unsigned nr_allocated; unsigned nr_allocated;
}; };
typedef struct AddressSpace AddressSpace;
typedef struct AddressSpaceOps AddressSpaceOps; 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) \ #define FOR_EACH_FLAT_RANGE(var, view) \
for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) 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, static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset,
unsigned width, bool write) unsigned width, bool write)
{ {
@ -455,18 +452,17 @@ const IORangeOps memory_region_iorange_ops = {
.destructor = memory_region_iorange_destructor, .destructor = memory_region_iorange_destructor,
}; };
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();
} }
@ -568,8 +564,10 @@ static FlatView generate_memory_topology(MemoryRegion *mr)
flatview_init(&view); flatview_init(&view);
render_memory_region(&view, mr, int128_zero(), if (mr) {
addrrange_make(int128_zero(), int128_2_64()), false); render_memory_region(&view, mr, int128_zero(),
addrrange_make(int128_zero(), int128_2_64()), false);
}
flatview_simplify(&view); flatview_simplify(&view);
return view; return view;
@ -597,7 +595,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
fds_new[inew]))) { fds_new[inew]))) {
fd = &fds_old[iold]; fd = &fds_old[iold];
section = (MemoryRegionSection) { section = (MemoryRegionSection) {
.address_space = as->root, .address_space = as,
.offset_within_address_space = int128_get64(fd->addr.start), .offset_within_address_space = int128_get64(fd->addr.start),
.size = int128_get64(fd->addr.size), .size = int128_get64(fd->addr.size),
}; };
@ -610,7 +608,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
fds_old[iold]))) { fds_old[iold]))) {
fd = &fds_new[inew]; fd = &fds_new[inew];
section = (MemoryRegionSection) { section = (MemoryRegionSection) {
.address_space = as->root, .address_space = as,
.offset_within_address_space = int128_get64(fd->addr.start), .offset_within_address_space = int128_get64(fd->addr.start),
.size = int128_get64(fd->addr.size), .size = int128_get64(fd->addr.size),
}; };
@ -632,7 +630,7 @@ static void address_space_update_ioeventfds(AddressSpace *as)
AddrRange tmp; AddrRange tmp;
unsigned i; 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) { for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
tmp = addrrange_shift(fr->mr->ioeventfds[i].addr, tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
int128_sub(fr->addr.start, 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) 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); 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, false);
address_space_update_topology_pass(as, old_view, new_view, true); 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); flatview_destroy(&old_view);
address_space_update_ioeventfds(as); address_space_update_ioeventfds(as);
} }
@ -739,16 +737,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);
@ -1082,12 +1079,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);
}
} }
} }
} }
@ -1130,16 +1129,24 @@ 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;
MemoryRegionSection section;
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), section = (MemoryRegionSection) {
int128_get64(fr->addr.size)); .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, &section,
int128_get64(fr->addr.start),
int128_get64(fr->addr.size));
QTAILQ_FOREACH(cmr, &mr->coalesced, link) { QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
tmp = addrrange_shift(cmr->addr, tmp = addrrange_shift(cmr->addr,
int128_sub(fr->addr.start, int128_sub(fr->addr.start,
@ -1148,13 +1155,23 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr)
continue; continue;
} }
tmp = addrrange_intersection(tmp, fr->addr); tmp = addrrange_intersection(tmp, fr->addr);
qemu_register_coalesced_mmio(int128_get64(tmp.start), MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, &section,
int128_get64(tmp.size)); 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) void memory_region_set_coalescing(MemoryRegion *mr)
{ {
memory_region_clear_coalescing(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) 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); sizeof(FlatRange), cmp_flatrange_addr);
} }
@ -1417,7 +1434,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space,
return ret; return ret;
} }
while (fr > as->current_map.ranges while (fr > as->current_map->ranges
&& addrrange_intersects(fr[-1].addr, range)) { && addrrange_intersects(fr[-1].addr, range)) {
--fr; --fr;
} }
@ -1438,7 +1455,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space)
AddressSpace *as = memory_region_to_address_space(address_space); AddressSpace *as = memory_region_to_address_space(address_space);
FlatRange *fr; 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); MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
} }
} }
@ -1461,29 +1478,35 @@ static void listener_add_address_space(MemoryListener *listener,
FlatRange *fr; FlatRange *fr;
if (listener->address_space_filter if (listener->address_space_filter
&& listener->address_space_filter != as->root) { && listener->address_space_filter != as) {
return; return;
} }
if (global_dirty_log) { 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 = { MemoryRegionSection section = {
.mr = fr->mr, .mr = fr->mr,
.address_space = as->root, .address_space = as,
.offset_within_region = fr->offset_in_region, .offset_within_region = fr->offset_in_region,
.size = int128_get64(fr->addr.size), .size = int128_get64(fr->addr.size),
.offset_within_address_space = int128_get64(fr->addr.start), .offset_within_address_space = int128_get64(fr->addr.start),
.readonly = fr->readonly, .readonly = fr->readonly,
}; };
listener->region_add(listener, &section); if (listener->region_add) {
listener->region_add(listener, &section);
}
} }
} }
void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) void memory_listener_register(MemoryListener *listener, AddressSpace *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)
@ -1498,8 +1521,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,18 +1532,28 @@ void memory_listener_unregister(MemoryListener *listener)
QTAILQ_REMOVE(&memory_listeners, listener, link); 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(); 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(); 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(); memory_region_transaction_begin();
address_space_io.root = mr; as->root = NULL;
memory_region_transaction_commit(); 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) 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; 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");

107
memory.h
View File

@ -157,6 +157,22 @@ struct MemoryRegionPortio {
#define PORTIO_END_OF_LIST() { } #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; typedef struct MemoryRegionSection MemoryRegionSection;
/** /**
@ -172,7 +188,7 @@ typedef struct MemoryRegionSection MemoryRegionSection;
*/ */
struct MemoryRegionSection { struct MemoryRegionSection {
MemoryRegion *mr; MemoryRegion *mr;
MemoryRegion *address_space; AddressSpace *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;
@ -202,9 +218,13 @@ struct MemoryListener {
bool match_data, uint64_t data, EventNotifier *e); bool match_data, uint64_t data, EventNotifier *e);
void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section, void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section,
bool match_data, uint64_t data, EventNotifier *e); 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) */ /* Lower = earlier (during add), later (during del) */
unsigned priority; unsigned priority;
MemoryRegion *address_space_filter; AddressSpace *address_space_filter;
QTAILQ_ENTRY(MemoryListener) link; QTAILQ_ENTRY(MemoryListener) link;
}; };
@ -755,7 +775,7 @@ void memory_region_transaction_commit(void);
* @listener: an object containing the callbacks to be called * @listener: an object containing the callbacks to be called
* @filter: if non-%NULL, only regions in this address space will be observed * @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() * 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); 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
#endif #endif

View File

@ -20,7 +20,6 @@
#include "cpu.h" #include "cpu.h"
#include "memory.h" #include "memory.h"
#include "cputlb.h"
#include "host-utils.h" #include "host-utils.h"
#include "helper.h" #include "helper.h"
#include <string.h> #include <string.h>
@ -81,7 +80,7 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
#endif #endif
/* basic checks */ /* 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; return -PGM_ADDRESSING;
} }
if (sccb & ~0x7ffffff8ul) { if (sccb & ~0x7ffffff8ul) {

View File

@ -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, static void xen_region_add(MemoryListener *listener,
MemoryRegionSection *section) MemoryRegionSection *section)
{ {
@ -474,11 +466,6 @@ static void xen_region_del(MemoryListener *listener,
xen_set_memory(listener, section, false); xen_set_memory(listener, section, false);
} }
static void xen_region_nop(MemoryListener *listener,
MemoryRegionSection *section)
{
}
static void xen_sync_dirty_bitmap(XenIOState *state, static void xen_sync_dirty_bitmap(XenIOState *state,
target_phys_addr_t start_addr, target_phys_addr_t start_addr,
ram_addr_t size) ram_addr_t size)
@ -565,33 +552,14 @@ static void xen_log_global_stop(MemoryListener *listener)
xen_in_migration = false; 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 = { static MemoryListener xen_memory_listener = {
.begin = xen_begin,
.commit = xen_commit,
.region_add = xen_region_add, .region_add = xen_region_add,
.region_del = xen_region_del, .region_del = xen_region_del,
.region_nop = xen_region_nop,
.log_start = xen_log_start, .log_start = xen_log_start,
.log_stop = xen_log_stop, .log_stop = xen_log_stop,
.log_sync = xen_log_sync, .log_sync = xen_log_sync,
.log_global_start = xen_log_global_start, .log_global_start = xen_log_global_start,
.log_global_stop = xen_log_global_stop, .log_global_stop = xen_log_global_stop,
.eventfd_add = xen_eventfd_add,
.eventfd_del = xen_eventfd_del,
.priority = 10, .priority = 10,
}; };
@ -1173,7 +1141,7 @@ int xen_hvm_init(void)
state->memory_listener = xen_memory_listener; state->memory_listener = xen_memory_listener;
QLIST_INIT(&state->physmap); 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; state->log_for_dirtybit = NULL;
/* Initialize backend core & drivers */ /* Initialize backend core & drivers */