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:
commit
d3e2efc5b5
6
cputlb.c
6
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",
|
||||
|
3
cputlb.h
3
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;
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
17
dma.h
17
dma.h
@ -11,6 +11,7 @@
|
||||
#define DMA_H
|
||||
|
||||
#include <stdio.h>
|
||||
#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 {
|
||||
|
@ -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
|
||||
|
||||
|
317
exec.c
317
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));
|
||||
|
25
hw/pci.c
25
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);
|
||||
|
2
hw/pci.h
2
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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
49
hw/xen_pt.c
49
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);
|
||||
}
|
||||
|
@ -209,6 +209,7 @@ struct XenPCIPassthroughState {
|
||||
MemoryRegion rom;
|
||||
|
||||
MemoryListener memory_listener;
|
||||
MemoryListener io_listener;
|
||||
};
|
||||
|
||||
int xen_pt_config_init(XenPCIPassthroughState *s);
|
||||
|
105
kvm-all.c
105
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();
|
||||
|
||||
|
10
kvm-stub.c
10
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;
|
||||
|
2
kvm.h
2
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
|
||||
|
||||
|
@ -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);
|
173
memory.c
173
memory.c
@ -20,8 +20,7 @@
|
||||
#include "kvm.h"
|
||||
#include <assert.h>
|
||||
|
||||
#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");
|
||||
|
107
memory.h
107
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
|
||||
|
@ -20,7 +20,6 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "memory.h"
|
||||
#include "cputlb.h"
|
||||
#include "host-utils.h"
|
||||
#include "helper.h"
|
||||
#include <string.h>
|
||||
@ -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) {
|
||||
|
34
xen-all.c
34
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user