qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v3 21/35] core: virtualise CPU interfaces completely


From: Peter Crosthwaite
Subject: [Qemu-devel] [PATCH v3 21/35] core: virtualise CPU interfaces completely
Date: Sat, 18 Jul 2015 02:40:31 -0700

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 <address@hidden>
---
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(-)

diff --git a/cpus.c b/cpus.c
index cd25c8c..738b96f 100644
--- a/cpus.c
+++ b/cpus.c
@@ -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
diff --git a/exec.c b/exec.c
index c37475a..4a722ce 100644
--- a/exec.c
+++ b/exec.c
@@ -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);
diff --git a/gdbstub.c b/gdbstub.c
index 92b2f81..2f280e6 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -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:
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 47d416d..d35601e 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -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);
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 8fd0540..0c70c17 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -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
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index eb12d26..9fbae16 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -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)
diff --git a/monitor.c b/monitor.c
index f283035..cb66692 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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)
-- 
1.9.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]