mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20190925' into staging
Fixes for TLB_BSWAP Coversion of NOTDIRTY and ROM handling to cputlb Followup cleanups to cputlb # gpg: Signature made Wed 25 Sep 2019 19:41:17 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-tcg-20190925: cputlb: Pass retaddr to tb_check_watchpoint cputlb: Pass retaddr to tb_invalidate_phys_page_fast cputlb: Remove tb_invalidate_phys_page_range is_cpu_write_access cputlb: Remove cpu->mem_io_vaddr cputlb: Handle TLB_NOTDIRTY in probe_access cputlb: Merge and move memory_notdirty_write_{prepare,complete} cputlb: Partially inline memory_region_section_get_iotlb cputlb: Move NOTDIRTY handling from I/O path to TLB path cputlb: Move ROM handling from I/O path to TLB path exec: Adjust notdirty tracing cputlb: Introduce TLB_BSWAP cputlb: Split out load/store_memop cputlb: Use qemu_build_not_reached in load/store_helpers qemu/compiler.h: Add qemu_build_not_reached cputlb: Disable __always_inline__ without optimization exec: Use TARGET_PAGE_BITS_MIN for TLB flags Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+206
-136
File diff suppressed because it is too large
Load Diff
+24
-27
@@ -1889,7 +1889,7 @@ static void
|
||||
tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
PageDesc *p, tb_page_addr_t start,
|
||||
tb_page_addr_t end,
|
||||
int is_cpu_write_access)
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
tb_page_addr_t tb_start, tb_end;
|
||||
@@ -1897,9 +1897,9 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
#ifdef TARGET_HAS_PRECISE_SMC
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUArchState *env = NULL;
|
||||
int current_tb_not_found = is_cpu_write_access;
|
||||
bool current_tb_not_found = retaddr != 0;
|
||||
bool current_tb_modified = false;
|
||||
TranslationBlock *current_tb = NULL;
|
||||
int current_tb_modified = 0;
|
||||
target_ulong current_pc = 0;
|
||||
target_ulong current_cs_base = 0;
|
||||
uint32_t current_flags = 0;
|
||||
@@ -1931,24 +1931,21 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
if (!(tb_end <= start || tb_start >= end)) {
|
||||
#ifdef TARGET_HAS_PRECISE_SMC
|
||||
if (current_tb_not_found) {
|
||||
current_tb_not_found = 0;
|
||||
current_tb = NULL;
|
||||
if (cpu->mem_io_pc) {
|
||||
/* now we have a real cpu fault */
|
||||
current_tb = tcg_tb_lookup(cpu->mem_io_pc);
|
||||
}
|
||||
current_tb_not_found = false;
|
||||
/* now we have a real cpu fault */
|
||||
current_tb = tcg_tb_lookup(retaddr);
|
||||
}
|
||||
if (current_tb == tb &&
|
||||
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
||||
/* If we are modifying the current TB, we must stop
|
||||
its execution. We could be more precise by checking
|
||||
that the modification is after the current PC, but it
|
||||
would require a specialized function to partially
|
||||
restore the CPU state */
|
||||
|
||||
current_tb_modified = 1;
|
||||
cpu_restore_state_from_tb(cpu, current_tb,
|
||||
cpu->mem_io_pc, true);
|
||||
/*
|
||||
* If we are modifying the current TB, we must stop
|
||||
* its execution. We could be more precise by checking
|
||||
* that the modification is after the current PC, but it
|
||||
* would require a specialized function to partially
|
||||
* restore the CPU state.
|
||||
*/
|
||||
current_tb_modified = true;
|
||||
cpu_restore_state_from_tb(cpu, current_tb, retaddr, true);
|
||||
cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base,
|
||||
¤t_flags);
|
||||
}
|
||||
@@ -1983,8 +1980,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
*
|
||||
* Called with mmap_lock held for user-mode emulation
|
||||
*/
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access)
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end)
|
||||
{
|
||||
struct page_collection *pages;
|
||||
PageDesc *p;
|
||||
@@ -1996,8 +1992,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
return;
|
||||
}
|
||||
pages = page_collection_lock(start, end);
|
||||
tb_invalidate_phys_page_range__locked(pages, p, start, end,
|
||||
is_cpu_write_access);
|
||||
tb_invalidate_phys_page_range__locked(pages, p, start, end, 0);
|
||||
page_collection_unlock(pages);
|
||||
}
|
||||
|
||||
@@ -2044,7 +2039,8 @@ void tb_invalidate_phys_range(target_ulong start, target_ulong end)
|
||||
* Call with all @pages in the range [@start, @start + len[ locked.
|
||||
*/
|
||||
void tb_invalidate_phys_page_fast(struct page_collection *pages,
|
||||
tb_page_addr_t start, int len)
|
||||
tb_page_addr_t start, int len,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
PageDesc *p;
|
||||
|
||||
@@ -2071,7 +2067,8 @@ void tb_invalidate_phys_page_fast(struct page_collection *pages,
|
||||
}
|
||||
} else {
|
||||
do_invalidate:
|
||||
tb_invalidate_phys_page_range__locked(pages, p, start, start + len, 1);
|
||||
tb_invalidate_phys_page_range__locked(pages, p, start, start + len,
|
||||
retaddr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -2145,16 +2142,16 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
|
||||
#endif
|
||||
|
||||
/* user-mode: call with mmap_lock held */
|
||||
void tb_check_watchpoint(CPUState *cpu)
|
||||
void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
assert_memory_lock();
|
||||
|
||||
tb = tcg_tb_lookup(cpu->mem_io_pc);
|
||||
tb = tcg_tb_lookup(retaddr);
|
||||
if (tb) {
|
||||
/* We can use retranslation to find the PC. */
|
||||
cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc, true);
|
||||
cpu_restore_state_from_tb(cpu, tb, retaddr, true);
|
||||
tb_phys_invalidate(tb, -1);
|
||||
} else {
|
||||
/* The exception probably happened in a helper. The CPU state should
|
||||
|
||||
@@ -27,10 +27,10 @@ struct page_collection *page_collection_lock(tb_page_addr_t start,
|
||||
tb_page_addr_t end);
|
||||
void page_collection_unlock(struct page_collection *set);
|
||||
void tb_invalidate_phys_page_fast(struct page_collection *pages,
|
||||
tb_page_addr_t start, int len);
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
void tb_check_watchpoint(CPUState *cpu);
|
||||
tb_page_addr_t start, int len,
|
||||
uintptr_t retaddr);
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end);
|
||||
void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int page_unprotect(target_ulong address, uintptr_t pc);
|
||||
|
||||
@@ -88,7 +88,6 @@ static MemoryRegion *system_io;
|
||||
AddressSpace address_space_io;
|
||||
AddressSpace address_space_memory;
|
||||
|
||||
MemoryRegion io_mem_rom, io_mem_notdirty;
|
||||
static MemoryRegion io_mem_unassigned;
|
||||
#endif
|
||||
|
||||
@@ -191,8 +190,6 @@ typedef struct subpage_t {
|
||||
} subpage_t;
|
||||
|
||||
#define PHYS_SECTION_UNASSIGNED 0
|
||||
#define PHYS_SECTION_NOTDIRTY 1
|
||||
#define PHYS_SECTION_ROM 2
|
||||
|
||||
static void io_mem_init(void);
|
||||
static void memory_map_init(void);
|
||||
@@ -1015,7 +1012,7 @@ const char *parse_cpu_option(const char *cpu_option)
|
||||
void tb_invalidate_phys_addr(target_ulong addr)
|
||||
{
|
||||
mmap_lock();
|
||||
tb_invalidate_phys_page_range(addr, addr + 1, 0);
|
||||
tb_invalidate_phys_page_range(addr, addr + 1);
|
||||
mmap_unlock();
|
||||
}
|
||||
|
||||
@@ -1042,7 +1039,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
|
||||
return;
|
||||
}
|
||||
ram_addr = memory_region_get_ram_addr(mr) + addr;
|
||||
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
|
||||
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@@ -1462,31 +1459,10 @@ bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
|
||||
|
||||
/* Called from RCU critical section */
|
||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
MemoryRegionSection *section,
|
||||
target_ulong vaddr,
|
||||
hwaddr paddr, hwaddr xlat,
|
||||
int prot,
|
||||
target_ulong *address)
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
hwaddr iotlb;
|
||||
|
||||
if (memory_region_is_ram(section->mr)) {
|
||||
/* Normal RAM. */
|
||||
iotlb = memory_region_get_ram_addr(section->mr) + xlat;
|
||||
if (!section->readonly) {
|
||||
iotlb |= PHYS_SECTION_NOTDIRTY;
|
||||
} else {
|
||||
iotlb |= PHYS_SECTION_ROM;
|
||||
}
|
||||
} else {
|
||||
AddressSpaceDispatch *d;
|
||||
|
||||
d = flatview_to_dispatch(section->fv);
|
||||
iotlb = section - d->map.sections;
|
||||
iotlb += xlat;
|
||||
}
|
||||
|
||||
return iotlb;
|
||||
AddressSpaceDispatch *d = flatview_to_dispatch(section->fv);
|
||||
return section - d->map.sections;
|
||||
}
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
||||
@@ -2742,83 +2718,6 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr)
|
||||
return block->offset + offset;
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
void memory_notdirty_write_prepare(NotDirtyInfo *ndi,
|
||||
CPUState *cpu,
|
||||
vaddr mem_vaddr,
|
||||
ram_addr_t ram_addr,
|
||||
unsigned size)
|
||||
{
|
||||
ndi->cpu = cpu;
|
||||
ndi->ram_addr = ram_addr;
|
||||
ndi->mem_vaddr = mem_vaddr;
|
||||
ndi->size = size;
|
||||
ndi->pages = NULL;
|
||||
|
||||
assert(tcg_enabled());
|
||||
if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
|
||||
ndi->pages = page_collection_lock(ram_addr, ram_addr + size);
|
||||
tb_invalidate_phys_page_fast(ndi->pages, ram_addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
void memory_notdirty_write_complete(NotDirtyInfo *ndi)
|
||||
{
|
||||
if (ndi->pages) {
|
||||
assert(tcg_enabled());
|
||||
page_collection_unlock(ndi->pages);
|
||||
ndi->pages = NULL;
|
||||
}
|
||||
|
||||
/* Set both VGA and migration bits for simplicity and to remove
|
||||
* the notdirty callback faster.
|
||||
*/
|
||||
cpu_physical_memory_set_dirty_range(ndi->ram_addr, ndi->size,
|
||||
DIRTY_CLIENTS_NOCODE);
|
||||
/* we remove the notdirty callback only if the code has been
|
||||
flushed */
|
||||
if (!cpu_physical_memory_is_clean(ndi->ram_addr)) {
|
||||
tlb_set_dirty(ndi->cpu, ndi->mem_vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
NotDirtyInfo ndi;
|
||||
|
||||
memory_notdirty_write_prepare(&ndi, current_cpu, current_cpu->mem_io_vaddr,
|
||||
ram_addr, size);
|
||||
|
||||
stn_p(qemu_map_ram_ptr(NULL, ram_addr), size, val);
|
||||
memory_notdirty_write_complete(&ndi);
|
||||
}
|
||||
|
||||
static bool notdirty_mem_accepts(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
return is_write;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps notdirty_mem_ops = {
|
||||
.write = notdirty_mem_write,
|
||||
.valid.accepts = notdirty_mem_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
/* Generate a debug exception if a watchpoint has been hit. */
|
||||
void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
|
||||
MemTxAttrs attrs, int flags, uintptr_t ra)
|
||||
@@ -2859,7 +2758,7 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
|
||||
cpu->watchpoint_hit = wp;
|
||||
|
||||
mmap_lock();
|
||||
tb_check_watchpoint(cpu);
|
||||
tb_check_watchpoint(cpu, ra);
|
||||
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
mmap_unlock();
|
||||
@@ -2999,38 +2898,6 @@ static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr)
|
||||
return phys_section_add(map, §ion);
|
||||
}
|
||||
|
||||
static void readonly_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
/* Ignore any write to ROM. */
|
||||
}
|
||||
|
||||
static bool readonly_mem_accepts(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
return is_write;
|
||||
}
|
||||
|
||||
/* This will only be used for writes, because reads are special cased
|
||||
* to directly access the underlying host ram.
|
||||
*/
|
||||
static const MemoryRegionOps readonly_mem_ops = {
|
||||
.write = readonly_mem_write,
|
||||
.valid.accepts = readonly_mem_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
MemoryRegionSection *iotlb_to_section(CPUState *cpu,
|
||||
hwaddr index, MemTxAttrs attrs)
|
||||
{
|
||||
@@ -3044,17 +2911,8 @@ MemoryRegionSection *iotlb_to_section(CPUState *cpu,
|
||||
|
||||
static void io_mem_init(void)
|
||||
{
|
||||
memory_region_init_io(&io_mem_rom, NULL, &readonly_mem_ops,
|
||||
NULL, NULL, UINT64_MAX);
|
||||
memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL,
|
||||
NULL, UINT64_MAX);
|
||||
|
||||
/* io_mem_notdirty calls tb_invalidate_phys_page_fast,
|
||||
* which can be called without the iothread mutex.
|
||||
*/
|
||||
memory_region_init_io(&io_mem_notdirty, NULL, ¬dirty_mem_ops, NULL,
|
||||
NULL, UINT64_MAX);
|
||||
memory_region_clear_global_locking(&io_mem_notdirty);
|
||||
}
|
||||
|
||||
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
|
||||
@@ -3064,10 +2922,6 @@ AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
|
||||
|
||||
n = dummy_section(&d->map, fv, &io_mem_unassigned);
|
||||
assert(n == PHYS_SECTION_UNASSIGNED);
|
||||
n = dummy_section(&d->map, fv, &io_mem_notdirty);
|
||||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&d->map, fv, &io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
|
||||
|
||||
|
||||
@@ -261,7 +261,6 @@ static void cpu_common_reset(CPUState *cpu)
|
||||
cpu->interrupt_request = 0;
|
||||
cpu->halted = 0;
|
||||
cpu->mem_io_pc = 0;
|
||||
cpu->mem_io_vaddr = 0;
|
||||
cpu->icount_extra = 0;
|
||||
atomic_set(&cpu->icount_decr_ptr->u32, 0);
|
||||
cpu->can_do_io = 1;
|
||||
|
||||
+16
-7
@@ -317,26 +317,35 @@ CPUArchState *cpu_copy(CPUArchState *env);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* Flags stored in the low bits of the TLB virtual address. These are
|
||||
* defined so that fast path ram access is all zeros.
|
||||
/*
|
||||
* Flags stored in the low bits of the TLB virtual address.
|
||||
* These are defined so that fast path ram access is all zeros.
|
||||
* The flags all must be between TARGET_PAGE_BITS and
|
||||
* maximum address alignment bit.
|
||||
*
|
||||
* Use TARGET_PAGE_BITS_MIN so that these bits are constant
|
||||
* when TARGET_PAGE_BITS_VARY is in effect.
|
||||
*/
|
||||
/* Zero if TLB entry is valid. */
|
||||
#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS - 1))
|
||||
#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1))
|
||||
/* Set if TLB entry references a clean RAM page. The iotlb entry will
|
||||
contain the page physical address. */
|
||||
#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS - 2))
|
||||
#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2))
|
||||
/* Set if TLB entry is an IO callback. */
|
||||
#define TLB_MMIO (1 << (TARGET_PAGE_BITS - 3))
|
||||
#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 3))
|
||||
/* Set if TLB entry contains a watchpoint. */
|
||||
#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS - 4))
|
||||
#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS_MIN - 4))
|
||||
/* Set if TLB entry requires byte swap. */
|
||||
#define TLB_BSWAP (1 << (TARGET_PAGE_BITS_MIN - 5))
|
||||
/* Set if TLB entry writes ignored. */
|
||||
#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 6))
|
||||
|
||||
/* Use this mask to check interception with an alignment mask
|
||||
* in a TCG backend.
|
||||
*/
|
||||
#define TLB_FLAGS_MASK \
|
||||
(TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO | TLB_WATCHPOINT)
|
||||
(TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \
|
||||
| TLB_WATCHPOINT | TLB_BSWAP | TLB_DISCARD_WRITE)
|
||||
|
||||
/**
|
||||
* tlb_hit_page: return true if page aligned @addr is a hit against the
|
||||
|
||||
@@ -100,9 +100,6 @@ void qemu_flush_coalesced_mmio_buffer(void);
|
||||
|
||||
void cpu_flush_icache_range(hwaddr start, hwaddr len);
|
||||
|
||||
extern struct MemoryRegion io_mem_rom;
|
||||
extern struct MemoryRegion io_mem_notdirty;
|
||||
|
||||
typedef int (RAMBlockIterFunc)(RAMBlock *rb, void *opaque);
|
||||
|
||||
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
|
||||
|
||||
@@ -509,11 +509,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen,
|
||||
MemTxAttrs attrs, int *prot);
|
||||
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
MemoryRegionSection *section,
|
||||
target_ulong vaddr,
|
||||
hwaddr paddr, hwaddr xlat,
|
||||
int prot,
|
||||
target_ulong *address);
|
||||
MemoryRegionSection *section);
|
||||
#endif
|
||||
|
||||
/* vl.c */
|
||||
|
||||
@@ -49,70 +49,5 @@ void address_space_dispatch_free(AddressSpaceDispatch *d);
|
||||
|
||||
void mtree_print_dispatch(struct AddressSpaceDispatch *d,
|
||||
MemoryRegion *root);
|
||||
|
||||
struct page_collection;
|
||||
|
||||
/* Opaque struct for passing info from memory_notdirty_write_prepare()
|
||||
* to memory_notdirty_write_complete(). Callers should treat all fields
|
||||
* as private, with the exception of @active.
|
||||
*
|
||||
* @active is a field which is not touched by either the prepare or
|
||||
* complete functions, but which the caller can use if it wishes to
|
||||
* track whether it has called prepare for this struct and so needs
|
||||
* to later call the complete function.
|
||||
*/
|
||||
typedef struct {
|
||||
CPUState *cpu;
|
||||
struct page_collection *pages;
|
||||
ram_addr_t ram_addr;
|
||||
vaddr mem_vaddr;
|
||||
unsigned size;
|
||||
bool active;
|
||||
} NotDirtyInfo;
|
||||
|
||||
/**
|
||||
* memory_notdirty_write_prepare: call before writing to non-dirty memory
|
||||
* @ndi: pointer to opaque NotDirtyInfo struct
|
||||
* @cpu: CPU doing the write
|
||||
* @mem_vaddr: virtual address of write
|
||||
* @ram_addr: the ram address of the write
|
||||
* @size: size of write in bytes
|
||||
*
|
||||
* Any code which writes to the host memory corresponding to
|
||||
* guest RAM which has been marked as NOTDIRTY must wrap those
|
||||
* writes in calls to memory_notdirty_write_prepare() and
|
||||
* memory_notdirty_write_complete():
|
||||
*
|
||||
* NotDirtyInfo ndi;
|
||||
* memory_notdirty_write_prepare(&ndi, ....);
|
||||
* ... perform write here ...
|
||||
* memory_notdirty_write_complete(&ndi);
|
||||
*
|
||||
* These calls will ensure that we flush any TCG translated code for
|
||||
* the memory being written, update the dirty bits and (if possible)
|
||||
* remove the slowpath callback for writing to the memory.
|
||||
*
|
||||
* This must only be called if we are using TCG; it will assert otherwise.
|
||||
*
|
||||
* We may take locks in the prepare call, so callers must ensure that
|
||||
* they don't exit (via longjump or otherwise) without calling complete.
|
||||
*
|
||||
* This call must only be made inside an RCU critical section.
|
||||
* (Note that while we're executing a TCG TB we're always in an
|
||||
* RCU critical section, which is likely to be the case for callers
|
||||
* of these functions.)
|
||||
*/
|
||||
void memory_notdirty_write_prepare(NotDirtyInfo *ndi,
|
||||
CPUState *cpu,
|
||||
vaddr mem_vaddr,
|
||||
ram_addr_t ram_addr,
|
||||
unsigned size);
|
||||
/**
|
||||
* memory_notdirty_write_complete: finish write to non-dirty memory
|
||||
* @ndi: pointer to the opaque NotDirtyInfo struct which was initialized
|
||||
* by memory_not_dirty_write_prepare().
|
||||
*/
|
||||
void memory_notdirty_write_complete(NotDirtyInfo *ndi);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -338,7 +338,6 @@ struct qemu_work_item;
|
||||
* @next_cpu: Next CPU sharing TB cache.
|
||||
* @opaque: User data.
|
||||
* @mem_io_pc: Host Program Counter at which the memory was accessed.
|
||||
* @mem_io_vaddr: Target virtual address at which the memory was accessed.
|
||||
* @kvm_fd: vCPU file descriptor for KVM.
|
||||
* @work_mutex: Lock to prevent multiple access to queued_work_*.
|
||||
* @queued_work_first: First asynchronous work pending.
|
||||
@@ -413,7 +412,6 @@ struct CPUState {
|
||||
* we store some rarely used information in the CPU context.
|
||||
*/
|
||||
uintptr_t mem_io_pc;
|
||||
vaddr mem_io_vaddr;
|
||||
/*
|
||||
* This is only needed for the legacy cpu_unassigned_access() hook;
|
||||
* when all targets using it have been converted to use
|
||||
|
||||
@@ -170,6 +170,17 @@
|
||||
# define QEMU_NONSTRING
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Forced inlining may be desired to encourage constant propagation
|
||||
* of function parameters. However, it can also make debugging harder,
|
||||
* so disable it for a non-optimizing build.
|
||||
*/
|
||||
#if defined(__OPTIMIZE__)
|
||||
#define QEMU_ALWAYS_INLINE __attribute__((always_inline))
|
||||
#else
|
||||
#define QEMU_ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
/* Implement C11 _Generic via GCC builtins. Example:
|
||||
*
|
||||
* QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x)
|
||||
@@ -210,4 +221,19 @@
|
||||
#define QEMU_GENERIC9(x, a0, ...) QEMU_GENERIC_IF(x, a0, QEMU_GENERIC8(x, __VA_ARGS__))
|
||||
#define QEMU_GENERIC10(x, a0, ...) QEMU_GENERIC_IF(x, a0, QEMU_GENERIC9(x, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* qemu_build_not_reached()
|
||||
*
|
||||
* The compiler, during optimization, is expected to prove that a call
|
||||
* to this function cannot be reached and remove it. If the compiler
|
||||
* supports QEMU_ERROR, this will be reported at compile time; otherwise
|
||||
* this will be reported at link time due to the missing symbol.
|
||||
*/
|
||||
#ifdef __OPTIMIZE__
|
||||
extern void QEMU_NORETURN QEMU_ERROR("code path is reachable")
|
||||
qemu_build_not_reached(void);
|
||||
#else
|
||||
#define qemu_build_not_reached() g_assert_not_reached()
|
||||
#endif
|
||||
|
||||
#endif /* COMPILER_H */
|
||||
|
||||
@@ -434,11 +434,6 @@ static MemTxResult memory_region_read_accessor(MemoryRegion *mr,
|
||||
tmp = mr->ops->read(mr->opaque, addr, size);
|
||||
if (mr->subpage) {
|
||||
trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
|
||||
} else if (mr == &io_mem_notdirty) {
|
||||
/* Accesses to code which has previously been translated into a TB show
|
||||
* up in the MMIO path, as accesses to the io_mem_notdirty
|
||||
* MemoryRegion. */
|
||||
trace_memory_region_tb_read(get_cpu_index(), addr, tmp, size);
|
||||
} else if (TRACE_MEMORY_REGION_OPS_READ_ENABLED) {
|
||||
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
|
||||
trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
|
||||
@@ -461,11 +456,6 @@ static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
|
||||
r = mr->ops->read_with_attrs(mr->opaque, addr, &tmp, size, attrs);
|
||||
if (mr->subpage) {
|
||||
trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
|
||||
} else if (mr == &io_mem_notdirty) {
|
||||
/* Accesses to code which has previously been translated into a TB show
|
||||
* up in the MMIO path, as accesses to the io_mem_notdirty
|
||||
* MemoryRegion. */
|
||||
trace_memory_region_tb_read(get_cpu_index(), addr, tmp, size);
|
||||
} else if (TRACE_MEMORY_REGION_OPS_READ_ENABLED) {
|
||||
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
|
||||
trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
|
||||
@@ -486,11 +476,6 @@ static MemTxResult memory_region_write_accessor(MemoryRegion *mr,
|
||||
|
||||
if (mr->subpage) {
|
||||
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
|
||||
} else if (mr == &io_mem_notdirty) {
|
||||
/* Accesses to code which has previously been translated into a TB show
|
||||
* up in the MMIO path, as accesses to the io_mem_notdirty
|
||||
* MemoryRegion. */
|
||||
trace_memory_region_tb_write(get_cpu_index(), addr, tmp, size);
|
||||
} else if (TRACE_MEMORY_REGION_OPS_WRITE_ENABLED) {
|
||||
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
|
||||
trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size);
|
||||
@@ -511,11 +496,6 @@ static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr,
|
||||
|
||||
if (mr->subpage) {
|
||||
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
|
||||
} else if (mr == &io_mem_notdirty) {
|
||||
/* Accesses to code which has previously been translated into a TB show
|
||||
* up in the MMIO path, as accesses to the io_mem_notdirty
|
||||
* MemoryRegion. */
|
||||
trace_memory_region_tb_write(get_cpu_index(), addr, tmp, size);
|
||||
} else if (TRACE_MEMORY_REGION_OPS_WRITE_ENABLED) {
|
||||
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
|
||||
trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size);
|
||||
|
||||
+2
-2
@@ -52,14 +52,14 @@ dma_map_wait(void *dbs) "dbs=%p"
|
||||
find_ram_offset(uint64_t size, uint64_t offset) "size: 0x%" PRIx64 " @ 0x%" PRIx64
|
||||
find_ram_offset_loop(uint64_t size, uint64_t candidate, uint64_t offset, uint64_t next, uint64_t mingap) "trying size: 0x%" PRIx64 " @ 0x%" PRIx64 ", offset: 0x%" PRIx64" next: 0x%" PRIx64 " mingap: 0x%" PRIx64
|
||||
ram_block_discard_range(const char *rbname, void *hva, size_t length, bool need_madvise, bool need_fallocate, int ret) "%s@%p + 0x%zx: madvise: %d fallocate: %d ret: %d"
|
||||
memory_notdirty_write_access(uint64_t vaddr, uint64_t ram_addr, unsigned size) "0x%" PRIx64 " ram_addr 0x%" PRIx64 " size %u"
|
||||
memory_notdirty_set_dirty(uint64_t vaddr) "0x%" PRIx64
|
||||
|
||||
# memory.c
|
||||
memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
|
||||
flatview_new(void *view, void *root) "%p (root %p)"
|
||||
|
||||
Reference in New Issue
Block a user