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 "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",
|
||||||
|
|
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);
|
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;
|
||||||
|
|
|
@ -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
17
dma.h
|
@ -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 {
|
||||||
|
|
|
@ -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
317
exec.c
|
@ -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));
|
||||||
|
|
25
hw/pci.c
25
hw/pci.c
|
@ -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);
|
||||||
|
|
2
hw/pci.h
2
hw/pci.h
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
49
hw/xen_pt.c
49
hw/xen_pt.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
105
kvm-all.c
|
@ -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();
|
||||||
|
|
||||||
|
|
10
kvm-stub.c
10
kvm-stub.c
|
@ -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
2
kvm.h
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
173
memory.c
|
@ -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, §ion,
|
||||||
|
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, §ion,
|
||||||
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, §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;
|
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
107
memory.h
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
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,
|
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 */
|
||||||
|
|
Loading…
Reference in New Issue