@@ -1116,7 +1116,7 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
void qemu_cpu_kick(CPUState *cpu)
{
qemu_cond_broadcast(cpu->halt_cond);
- if (!tcg_enabled() && !cpu->thread_kicked) {
+ if (!CPU_HOOK(cpu, tcg_enabled)() && !cpu->thread_kicked) {
qemu_cpu_kick_thread(cpu);
cpu->thread_kicked = true;
}
@@ -1310,7 +1310,7 @@ void qemu_init_vcpu(CPUState *cpu)
cpu->stopped = true;
if (kvm_enabled()) {
qemu_kvm_start_vcpu(cpu);
- } else if (tcg_enabled()) {
+ } else if (CPU_HOOK(cpu, tcg_enabled)()) {
qemu_tcg_init_vcpu(cpu);
} else {
qemu_dummy_start_vcpu(cpu);
@@ -1393,7 +1393,7 @@ static int tcg_cpu_exec(CPUState *cpu)
cpu->icount_decr.u16.low = decr;
cpu->icount_extra = count;
}
- ret = cpu_exec(cpu);
+ ret = CPU_HOOK(cpu, cpu_exec)(cpu);
#ifdef CONFIG_PROFILER
tcg_time += profile_getclock() - ti;
#endif
@@ -445,7 +445,7 @@ static int cpu_common_post_load(void *opaque, int version_id)
/* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
version_id is increased. */
cpu->interrupt_request &= ~0x01;
- tlb_flush(cpu, 1);
+ CPU_HOOK(cpu, tlb_flush)(cpu, 1);
return 0;
}
@@ -463,7 +463,7 @@ static bool cpu_common_exception_index_needed(void *opaque)
{
CPUState *cpu = opaque;
- return tcg_enabled() && cpu->exception_index != -1;
+ return CPU_HOOK(cpu, tcg_enabled)() && cpu->exception_index != -1;
}
static const VMStateDescription vmstate_cpu_common_exception_index = {
@@ -621,8 +621,8 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
hwaddr phys = cpu_get_phys_page_debug(cpu, pc);
if (phys != -1) {
- tb_invalidate_phys_addr(cpu->as,
- phys | (pc & ~TARGET_PAGE_MASK));
+ CPU_HOOK(cpu, tb_invalidate_phys_addr)(cpu->as,
+ phys | (pc & ~TARGET_PAGE_MASK));
}
}
#endif
@@ -674,7 +674,7 @@ int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
QTAILQ_INSERT_TAIL(&cpu->watchpoints, wp, entry);
}
- tlb_flush_page(cpu, addr);
+ CPU_HOOK(cpu, tlb_flush_page)(cpu, addr);
if (watchpoint)
*watchpoint = wp;
@@ -702,7 +702,7 @@ void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
{
QTAILQ_REMOVE(&cpu->watchpoints, watchpoint, entry);
- tlb_flush_page(cpu, watchpoint->vaddr);
+ CPU_HOOK(cpu, tlb_flush_page)(cpu, watchpoint->vaddr);
g_free(watchpoint);
}
@@ -814,7 +814,7 @@ void cpu_single_step(CPUState *cpu, int enabled)
} else {
/* must flush all the translated code to avoid inconsistencies */
/* XXX: only flush what is necessary */
- tb_flush(cpu);
+ CPU_HOOK(cpu,tb_flush)(cpu);
}
}
}
@@ -906,7 +906,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
assert(block == qemu_get_ram_block(end - 1));
start1 = (uintptr_t)ramblock_ptr(block, start - block->offset);
CPU_FOREACH(cpu) {
- tlb_reset_dirty(cpu, start1, length);
+ CPU_HOOK(cpu, tlb_reset_dirty)(cpu, start1, length);
}
rcu_read_unlock();
}
@@ -1876,7 +1876,7 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
uint64_t val, unsigned size)
{
if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
- tb_invalidate_phys_page_fast(ram_addr, size);
+ CPU_HOOK(current_cpu, tb_invalidate_phys_page_fast)(ram_addr, size);
}
switch (size) {
case 1:
@@ -1899,7 +1899,8 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
/* we remove the notdirty callback only if the code has been
flushed */
if (!cpu_physical_memory_is_clean(ram_addr)) {
- tlb_set_dirty(current_cpu, current_cpu->mem_io_vaddr);
+ CPU_HOOK(current_cpu, tlb_set_dirty)(current_cpu,
+ current_cpu->mem_io_vaddr);
}
}
@@ -1945,13 +1946,13 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
wp->hitattrs = attrs;
if (!cpu->watchpoint_hit) {
cpu->watchpoint_hit = wp;
- tb_check_watchpoint(cpu);
+ CPU_HOOK(cpu, tb_check_watchpoint)(cpu);
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
cpu->exception_index = EXCP_DEBUG;
cpu_loop_exit(cpu);
} else {
- cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
- tb_gen_code(cpu, pc, cs_base, cpu_flags, 1);
+ CPU_HOOK(cpu, cpu_get_tb_cpu_state)(env, &pc, &cs_base, &cpu_flags);
+ CPU_HOOK(cpu, tb_gen_code)(cpu, pc, cs_base, cpu_flags, 1);
cpu_resume_from_signal(cpu, NULL);
}
}
@@ -2344,7 +2345,7 @@ static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask);
}
if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
- tb_invalidate_phys_range(addr, addr + length);
+ CPU_HOOK(current_cpu, tb_invalidate_phys_range)(addr, addr + length);
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
}
cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
@@ -1257,7 +1257,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
cpu->watchpoint_hit = NULL;
goto send_packet;
}
- tb_flush(cpu);
+ CPU_HOOK(cpu, tb_flush)(cpu);
ret = GDB_SIGNAL_TRAP;
break;
case RUN_STATE_PAUSED:
@@ -53,9 +53,7 @@ typedef uintptr_t ram_addr_t;
# define RAM_ADDR_FMT "%" PRIxPTR
#endif
-#ifndef CONFIG_USER_ONLY
typedef ram_addr_t tb_page_addr_t;
-#endif
extern ram_addr_t ram_size;
ram_addr_t get_current_ram_size(void);
@@ -363,4 +363,9 @@ extern volatile sig_atomic_t exit_request;
#if !defined(CONFIG_USER_ONLY)
void migration_bitmap_extend(ram_addr_t old, ram_addr_t new);
#endif
+
+#ifdef NEED_CPU_H
+#include "translate-all.h"
+#endif
+
#endif
@@ -212,6 +212,8 @@ struct kvm_run;
#define TB_JMP_CACHE_BITS 12
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
+#define MAX_CPU_HOOKS 16
+
/**
* CPUState:
* @cpu_index: CPU index (informative).
@@ -320,8 +322,85 @@ struct CPUState {
(absolute value) offset as small as possible. This reduces code
size, especially for hosts without large memory offsets. */
volatile sig_atomic_t tcg_exit_req;
+
+ void (*cpu_get_tb_cpu_state)(void *env, void *pc, void *cs_base,
+ int *pflags);
+
+ union {
+ struct {
+#ifdef NEED_CPU_H
+ void (*tb_check_watchpoint)(CPUState *cpu);
+ void (*tb_flush)(CPUState *cpu);
+ struct TranslationBlock *(*tb_gen_code)(CPUState *cpu,
+ target_ulong pc,
+ target_ulong cs_base,
+ int flags, int cflags);
+#ifndef CONFIG_USER_ONLY
+ void (*tlb_flush)(CPUState *cpu, int flush_global);
+ void (*tlb_flush_page)(CPUState *cpu, target_ulong addr);
+ void (*tlb_set_dirty)(CPUState *cpu, target_ulong addr);
+ void (*tlb_reset_dirty)(CPUState *cpu, ram_addr_t start,
+ ram_addr_t length);
+
+ void (*tb_invalidate_phys_addr)(AddressSpace *as, hwaddr addr);
+ void (*tb_invalidate_phys_page_fast)(tb_page_addr_t start, int len);
+ void (*tb_invalidate_phys_range)(tb_page_addr_t start, tb_page_addr_t end);
+
+ void (*dump_exec_info)(FILE *f, fprintf_function cpu_fprintf);
+ void (*dump_opcount_info)(FILE *f, fprintf_function cpu_fprintf);
+#endif
+ int (*cpu_exec)(CPUState *cpu);
+
+ bool (*tcg_enabled)(void);
+#endif
+ void (*hooks_end_of_list)(void);
+ };
+ void (*hooks_dummy[MAX_CPU_HOOKS + 1])(void);
+ };
};
+QEMU_BUILD_BUG_ON(offsetof(CPUState, hooks_end_of_list) >
+ offsetof(CPUState, hooks_dummy[MAX_CPU_HOOKS + 1]))
+
+#ifndef CONFIG_USER_ONLY
+#define IFN_USER_ONLY(a) a
+#else
+#define IFN_USER_ONLY(a)
+#endif
+
+#define CPU_SET_QOM_HOOKS(cpu) do { \
+ cpu->cpu_get_tb_cpu_state = \
+ (void (*)(void *, void *, void *, int *))cpu_get_tb_cpu_state; \
+ \
+ cpu->tb_check_watchpoint = tb_check_watchpoint; \
+ cpu->tb_flush = tb_flush; \
+ cpu->tb_gen_code = tb_gen_code; \
+ \
+ IFN_USER_ONLY( \
+ cpu->tlb_flush = tlb_flush; \
+ cpu->tlb_flush_page = tlb_flush_page; \
+ cpu->tlb_set_dirty = tlb_set_dirty; \
+ cpu->tlb_reset_dirty = tlb_reset_dirty; \
+ \
+ cpu->tb_invalidate_phys_addr = tb_invalidate_phys_addr; \
+ cpu->tb_invalidate_phys_page_fast = tb_invalidate_phys_page_fast; \
+ cpu->tb_invalidate_phys_range = tb_invalidate_phys_range; \
+ \
+ cpu->dump_exec_info = dump_exec_info; \
+ cpu->dump_opcount_info = dump_opcount_info; \
+ ) \
+ \
+ cpu->cpu_exec = cpu_exec; \
+ \
+ cpu->tcg_enabled = tcg_enabled; \
+} while (0);
+
+#ifdef TARGET_MULTI
+#define CPU_HOOK(cpu, fn)(cpu->fn)
+#else
+#define CPU_HOOK(cpu, fn)(fn)
+#endif
+
QTAILQ_HEAD(CPUTailQ, CPUState);
extern struct CPUTailQ cpus;
#define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node)
@@ -962,13 +962,13 @@ static void hmp_info_registers(Monitor *mon, const QDict *qdict)
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
{
- dump_exec_info((FILE *)mon, monitor_fprintf);
+ CPU_HOOK(mon_get_cpu(), dump_exec_info)((FILE *)mon, monitor_fprintf);
dump_drift_info((FILE *)mon, monitor_fprintf);
}
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
{
- dump_opcount_info((FILE *)mon, monitor_fprintf);
+ CPU_HOOK(mon_get_cpu(), dump_opcount_info)((FILE *)mon, monitor_fprintf);
}
static void hmp_info_history(Monitor *mon, const QDict *qdict)
The core code interfaces to translate-all, cpu-tlb and cpu-exec are virtualised. This prepare support for multi-arch where these modules are multi-compiled for the different target backends and will need to co-exist. The names of functions are not changed. They still have their generic names and can be linked to the final build as-is. In multi-arch, the arch-obj components have all symbols localised which includes all of the function defs for these hooks (despite them still having generic names and global linkage). So it is up to the target specific sub-class to install theses hooks. Multiple targets can do this and then link together. The CPU base class will harmlessly set the hooks to NULL but in multi-arch these must be overridden. The hooks are only called in MULTI_ARCH case, which has the advantage of preserving the devirtualised behaviour of these hooks. It also guards against unconverted archs that do not set the QOM_HOOKS, i.e. an unconverted arch will not attempt to call the virtualised hooks. Signed-off-by: Peter Crosthwaite <crosthwaite.peter@gmail.com> --- Changed since RFC v2: * Major rewrite * remove tcg_ctx ptr (RTH) virtualise cpu_get_tb_cpu_state (Paolo) Don't use virtualised hooks outside of multi-arch (Paolo) Don't stub or install default hooks (woot!) Don't move header definitions Split API changes to separate patches Compile out hooks when cpu.h is unavailable Compile out hooks that dont exist in linux user mode remove tb_invalidate_phys_page_range from hooks (linux-u only) Add monitor hooks, dump_exec_info, dump_opcount_info Add tcg_enabled() as a hook --- cpus.c | 6 ++-- exec.c | 29 ++++++++--------- gdbstub.c | 2 +- include/exec/cpu-common.h | 2 -- include/exec/exec-all.h | 5 +++ include/qom/cpu.h | 79 +++++++++++++++++++++++++++++++++++++++++++++++ monitor.c | 4 +-- 7 files changed, 105 insertions(+), 22 deletions(-)