Queued TCG patches
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZ3R4gAAoJEGTfOOivfiFf9isH+wfr6Sg4z7OeGqMUfbsB2WzQ TVrN51ee9isHvPn66Qj7OANk7toqj+cWh1BuDpjRBLQV4sx7V4N/qfazlriEvlRj doIIsl4tdG4XaoiF0AM/touBRlTs+yDQtLcwL5BaLm7JoekM1ICAiiIeX9Vfy1CH ll4gyZ4n0WVVpseBQWWZJpOqZr8cBXYNdmYWkjL+qVLytxifmmdYUlELtdiwByB2 91GMpKgu2OYWV55Ivk/Yo4KUxv5EOazOXc6dELACA1oqf+G+NlTut0zCHaumxJyN gXePbD6RQuT/2NnAyQ2FMWGtaqbepg8oPVT700cboUv4flg/0Z+KU48jLpzZBvM= =syLD -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20171010' into staging Queued TCG patches # gpg: Signature made Tue 10 Oct 2017 20:23:12 BST # gpg: using RSA key 0x64DF38E8AF7E215F # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-tcg-20171010: tcg/mips: delete commented out extern keyword. tcg: define TCG_HIGHWATER util: move qemu_real_host_page_size/mask to osdep.h tcg: take .helpers out of TCGContext tci: move tci_regs to tcg_qemu_tb_exec's stack exec-all: extract tb->tc_* into a separate struct tc_tb translate-all: define and use DEBUG_TB_CHECK_GATE translate-all: define and use DEBUG_TB_INVALIDATE_GATE exec-all: introduce TB_PAGE_ADDR_FMT translate-all: define and use DEBUG_TB_FLUSH_GATE exec-all: bring tb->invalid into tb->cflags tcg: consolidate TB lookups in tb_lookup__cpu_state tcg: remove addr argument from lookup_tb_ptr tcg/mips: constify tcg_target_callee_save_regs tcg/i386: constify tcg_target_callee_save_regs cpu-exec: rename have_tb_lock to acquired_tb_lock in tb_find translate-all: make have_tb_lock static exec-all: fix typos in TranslationBlock's documentation tcg: fix corruption of code_time profiling counter upon tb_flush cputlb: bring back tlb_flush_count under !TLB_DEBUG Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e74c0cfa57
@ -28,6 +28,7 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "exec/tb-hash.h"
|
||||
#include "exec/tb-lookup.h"
|
||||
#include "exec/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
@ -142,11 +143,11 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
uintptr_t ret;
|
||||
TranslationBlock *last_tb;
|
||||
int tb_exit;
|
||||
uint8_t *tb_ptr = itb->tc_ptr;
|
||||
uint8_t *tb_ptr = itb->tc.ptr;
|
||||
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
|
||||
"Trace %p [%d: " TARGET_FMT_lx "] %s\n",
|
||||
itb->tc_ptr, cpu->cpu_index, itb->pc,
|
||||
itb->tc.ptr, cpu->cpu_index, itb->pc,
|
||||
lookup_symbol(itb->pc));
|
||||
|
||||
#if defined(DEBUG_DISAS)
|
||||
@ -178,7 +179,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, last_tb->pc,
|
||||
"Stopped execution of TB chain before %p ["
|
||||
TARGET_FMT_lx "] %s\n",
|
||||
last_tb->tc_ptr, last_tb->pc,
|
||||
last_tb->tc.ptr, last_tb->pc,
|
||||
lookup_symbol(last_tb->pc));
|
||||
if (cc->synchronize_from_tb) {
|
||||
cc->synchronize_from_tb(cpu, last_tb);
|
||||
@ -293,7 +294,7 @@ static bool tb_cmp(const void *p, const void *d)
|
||||
tb->cs_base == desc->cs_base &&
|
||||
tb->flags == desc->flags &&
|
||||
tb->trace_vcpu_dstate == desc->trace_vcpu_dstate &&
|
||||
!atomic_read(&tb->invalid)) {
|
||||
!(atomic_read(&tb->cflags) & CF_INVALID)) {
|
||||
/* check next page if needed */
|
||||
if (tb->page_addr[1] == -1) {
|
||||
return true;
|
||||
@ -333,7 +334,7 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
|
||||
{
|
||||
if (TCG_TARGET_HAS_direct_jump) {
|
||||
uintptr_t offset = tb->jmp_target_arg[n];
|
||||
uintptr_t tc_ptr = (uintptr_t)tb->tc_ptr;
|
||||
uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
|
||||
tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
|
||||
} else {
|
||||
tb->jmp_target_arg[n] = addr;
|
||||
@ -353,11 +354,11 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc,
|
||||
"Linking TBs %p [" TARGET_FMT_lx
|
||||
"] index %d -> %p [" TARGET_FMT_lx "]\n",
|
||||
tb->tc_ptr, tb->pc, n,
|
||||
tb_next->tc_ptr, tb_next->pc);
|
||||
tb->tc.ptr, tb->pc, n,
|
||||
tb_next->tc.ptr, tb_next->pc);
|
||||
|
||||
/* patch the native jump address */
|
||||
tb_set_jmp_target(tb, n, (uintptr_t)tb_next->tc_ptr);
|
||||
tb_set_jmp_target(tb, n, (uintptr_t)tb_next->tc.ptr);
|
||||
|
||||
/* add in TB jmp circular list */
|
||||
tb->jmp_list_next[n] = tb_next->jmp_list_first;
|
||||
@ -368,43 +369,31 @@ static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
TranslationBlock *last_tb,
|
||||
int tb_exit)
|
||||
{
|
||||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
bool have_tb_lock = false;
|
||||
bool acquired_tb_lock = false;
|
||||
|
||||
/* we record a subset of the CPU state. It will
|
||||
always be the same before a given translated block
|
||||
is executed. */
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
tb = atomic_rcu_read(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]);
|
||||
if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
|
||||
tb->flags != flags ||
|
||||
tb->trace_vcpu_dstate != *cpu->trace_dstate)) {
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags);
|
||||
if (tb == NULL) {
|
||||
/* mmap_lock is needed by tb_gen_code, and mmap_lock must be
|
||||
* taken outside tb_lock. As system emulation is currently
|
||||
* single threaded the locks are NOPs.
|
||||
*/
|
||||
mmap_lock();
|
||||
tb_lock();
|
||||
acquired_tb_lock = true;
|
||||
|
||||
/* There's a chance that our desired tb has been translated while
|
||||
* taking the locks so we check again inside the lock.
|
||||
*/
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags);
|
||||
if (!tb) {
|
||||
|
||||
/* mmap_lock is needed by tb_gen_code, and mmap_lock must be
|
||||
* taken outside tb_lock. As system emulation is currently
|
||||
* single threaded the locks are NOPs.
|
||||
*/
|
||||
mmap_lock();
|
||||
tb_lock();
|
||||
have_tb_lock = true;
|
||||
|
||||
/* There's a chance that our desired tb has been translated while
|
||||
* taking the locks so we check again inside the lock.
|
||||
*/
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags);
|
||||
if (!tb) {
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, 0);
|
||||
}
|
||||
|
||||
mmap_unlock();
|
||||
if (likely(tb == NULL)) {
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, 0);
|
||||
}
|
||||
|
||||
mmap_unlock();
|
||||
/* We add the TB in the virtual pc hash table for the fast lookup */
|
||||
atomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
}
|
||||
@ -419,15 +408,15 @@ static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
#endif
|
||||
/* See if we can patch the calling TB. */
|
||||
if (last_tb && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
|
||||
if (!have_tb_lock) {
|
||||
if (!acquired_tb_lock) {
|
||||
tb_lock();
|
||||
have_tb_lock = true;
|
||||
acquired_tb_lock = true;
|
||||
}
|
||||
if (!tb->invalid) {
|
||||
if (!(tb->cflags & CF_INVALID)) {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
}
|
||||
if (have_tb_lock) {
|
||||
if (acquired_tb_lock) {
|
||||
tb_unlock();
|
||||
}
|
||||
return tb;
|
||||
|
@ -92,8 +92,18 @@ static void flush_all_helper(CPUState *src, run_on_cpu_func fn,
|
||||
}
|
||||
}
|
||||
|
||||
/* statistics */
|
||||
int tlb_flush_count;
|
||||
size_t tlb_flush_count(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
size_t count = 0;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
|
||||
count += atomic_read(&env->tlb_flush_count);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* This is OK because CPU architectures generally permit an
|
||||
* implementation to drop entries from the TLB at any time, so
|
||||
@ -112,7 +122,8 @@ static void tlb_flush_nocheck(CPUState *cpu)
|
||||
}
|
||||
|
||||
assert_cpu_is_self(cpu);
|
||||
tlb_debug("(count: %d)\n", tlb_flush_count++);
|
||||
atomic_set(&env->tlb_flush_count, env->tlb_flush_count + 1);
|
||||
tlb_debug("(count: %zu)\n", tlb_flush_count());
|
||||
|
||||
tb_lock();
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/tb-hash.h"
|
||||
#include "exec/tb-lookup.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
@ -144,34 +144,22 @@ uint64_t HELPER(ctpop_i64)(uint64_t arg)
|
||||
return ctpop64(arg);
|
||||
}
|
||||
|
||||
void *HELPER(lookup_tb_ptr)(CPUArchState *env, target_ulong addr)
|
||||
void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags, addr_hash;
|
||||
uint32_t flags;
|
||||
|
||||
addr_hash = tb_jmp_cache_hash_func(addr);
|
||||
tb = atomic_rcu_read(&cpu->tb_jmp_cache[addr_hash]);
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
if (unlikely(!(tb
|
||||
&& tb->pc == addr
|
||||
&& tb->cs_base == cs_base
|
||||
&& tb->flags == flags
|
||||
&& tb->trace_vcpu_dstate == *cpu->trace_dstate))) {
|
||||
tb = tb_htable_lookup(cpu, addr, cs_base, flags);
|
||||
if (!tb) {
|
||||
return tcg_ctx.code_gen_epilogue;
|
||||
}
|
||||
atomic_set(&cpu->tb_jmp_cache[addr_hash], tb);
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags);
|
||||
if (tb == NULL) {
|
||||
return tcg_ctx.code_gen_epilogue;
|
||||
}
|
||||
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, addr,
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, pc,
|
||||
"Chain %p [%d: " TARGET_FMT_lx "] %s\n",
|
||||
tb->tc_ptr, cpu->cpu_index, addr,
|
||||
lookup_symbol(addr));
|
||||
return tb->tc_ptr;
|
||||
tb->tc.ptr, cpu->cpu_index, pc,
|
||||
lookup_symbol(pc));
|
||||
return tb->tc.ptr;
|
||||
}
|
||||
|
||||
void HELPER(exit_atomic)(CPUArchState *env)
|
||||
|
@ -24,7 +24,7 @@ DEF_HELPER_FLAGS_1(clrsb_i64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(ctpop_i32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(ctpop_i64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_2(lookup_tb_ptr, TCG_CALL_NO_WG_SE, ptr, env, tl)
|
||||
DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, ptr, env)
|
||||
|
||||
DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
|
||||
|
||||
|
@ -65,11 +65,29 @@
|
||||
/* make various TB consistency checks */
|
||||
/* #define DEBUG_TB_CHECK */
|
||||
|
||||
#ifdef DEBUG_TB_INVALIDATE
|
||||
#define DEBUG_TB_INVALIDATE_GATE 1
|
||||
#else
|
||||
#define DEBUG_TB_INVALIDATE_GATE 0
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_TB_FLUSH
|
||||
#define DEBUG_TB_FLUSH_GATE 1
|
||||
#else
|
||||
#define DEBUG_TB_FLUSH_GATE 0
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* TB consistency checks only implemented for usermode emulation. */
|
||||
#undef DEBUG_TB_CHECK
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
#define DEBUG_TB_CHECK_GATE 1
|
||||
#else
|
||||
#define DEBUG_TB_CHECK_GATE 0
|
||||
#endif
|
||||
|
||||
/* Access to the various translations structures need to be serialised via locks
|
||||
* for consistency. This is automatic for SoftMMU based system
|
||||
* emulation due to its single threaded nature. In user-mode emulation
|
||||
@ -139,7 +157,7 @@ TCGContext tcg_ctx;
|
||||
bool parallel_cpus;
|
||||
|
||||
/* translation block context */
|
||||
__thread int have_tb_lock;
|
||||
static __thread int have_tb_lock;
|
||||
|
||||
static void page_table_config_init(void)
|
||||
{
|
||||
@ -242,7 +260,7 @@ static target_long decode_sleb128(uint8_t **pp)
|
||||
which comes from the host pc of the end of the code implementing the insn.
|
||||
|
||||
Each line of the table is encoded as sleb128 deltas from the previous
|
||||
line. The seed for the first line is { tb->pc, 0..., tb->tc_ptr }.
|
||||
line. The seed for the first line is { tb->pc, 0..., tb->tc.ptr }.
|
||||
That is, the first column is seeded with the guest pc, the last column
|
||||
with the host pc, and the middle columns with zeros. */
|
||||
|
||||
@ -252,7 +270,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
|
||||
uint8_t *p = block;
|
||||
int i, j, n;
|
||||
|
||||
tb->tc_search = block;
|
||||
tb->tc.search = block;
|
||||
|
||||
for (i = 0, n = tb->icount; i < n; ++i) {
|
||||
target_ulong prev;
|
||||
@ -287,9 +305,9 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
uintptr_t searched_pc)
|
||||
{
|
||||
target_ulong data[TARGET_INSN_START_WORDS] = { tb->pc };
|
||||
uintptr_t host_pc = (uintptr_t)tb->tc_ptr;
|
||||
uintptr_t host_pc = (uintptr_t)tb->tc.ptr;
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
uint8_t *p = tb->tc_search;
|
||||
uint8_t *p = tb->tc.search;
|
||||
int i, j, num_insns = tb->icount;
|
||||
#ifdef CONFIG_PROFILER
|
||||
int64_t ti = profile_getclock();
|
||||
@ -840,7 +858,7 @@ void tb_free(TranslationBlock *tb)
|
||||
tb == tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs - 1]) {
|
||||
size_t struct_size = ROUND_UP(sizeof(*tb), qemu_icache_linesize);
|
||||
|
||||
tcg_ctx.code_gen_ptr = tb->tc_ptr - struct_size;
|
||||
tcg_ctx.code_gen_ptr = tb->tc.ptr - struct_size;
|
||||
tcg_ctx.tb_ctx.nb_tbs--;
|
||||
}
|
||||
}
|
||||
@ -899,13 +917,13 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_TB_FLUSH)
|
||||
printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
|
||||
(unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer),
|
||||
tcg_ctx.tb_ctx.nb_tbs, tcg_ctx.tb_ctx.nb_tbs > 0 ?
|
||||
((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer)) /
|
||||
tcg_ctx.tb_ctx.nb_tbs : 0);
|
||||
#endif
|
||||
if (DEBUG_TB_FLUSH_GATE) {
|
||||
printf("qemu: flush code_size=%td nb_tbs=%d avg_tb_size=%td\n",
|
||||
tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer,
|
||||
tcg_ctx.tb_ctx.nb_tbs, tcg_ctx.tb_ctx.nb_tbs > 0 ?
|
||||
(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) /
|
||||
tcg_ctx.tb_ctx.nb_tbs : 0);
|
||||
}
|
||||
if ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer)
|
||||
> tcg_ctx.code_gen_buffer_size) {
|
||||
cpu_abort(cpu, "Internal error: code buffer overflow\n");
|
||||
@ -938,7 +956,13 @@ void tb_flush(CPUState *cpu)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
/*
|
||||
* Formerly ifdef DEBUG_TB_CHECK. These debug functions are user-mode-only,
|
||||
* so in order to prevent bit rot we compile them unconditionally in user-mode,
|
||||
* and let the optimizer get rid of them by wrapping their user-only callers
|
||||
* with if (DEBUG_TB_CHECK_GATE).
|
||||
*/
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
||||
static void
|
||||
do_tb_invalidate_check(struct qht *ht, void *p, uint32_t hash, void *userp)
|
||||
@ -982,7 +1006,7 @@ static void tb_page_check(void)
|
||||
qht_iter(&tcg_ctx.tb_ctx.htable, do_tb_page_check, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
|
||||
{
|
||||
@ -1035,7 +1059,7 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *tb, int n)
|
||||
another TB */
|
||||
static inline void tb_reset_jump(TranslationBlock *tb, int n)
|
||||
{
|
||||
uintptr_t addr = (uintptr_t)(tb->tc_ptr + tb->jmp_reset_offset[n]);
|
||||
uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]);
|
||||
tb_set_jmp_target(tb, n, addr);
|
||||
}
|
||||
|
||||
@ -1073,7 +1097,7 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
|
||||
|
||||
assert_tb_locked();
|
||||
|
||||
atomic_set(&tb->invalid, true);
|
||||
atomic_set(&tb->cflags, tb->cflags | CF_INVALID);
|
||||
|
||||
/* remove the TB from the hash list */
|
||||
phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
|
||||
@ -1186,10 +1210,9 @@ static inline void tb_alloc_page(TranslationBlock *tb,
|
||||
}
|
||||
mprotect(g2h(page_addr), qemu_host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
#ifdef DEBUG_TB_INVALIDATE
|
||||
printf("protecting code page: 0x" TARGET_FMT_lx "\n",
|
||||
page_addr);
|
||||
#endif
|
||||
if (DEBUG_TB_INVALIDATE_GATE) {
|
||||
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* if some code is already present, then the pages are already
|
||||
@ -1225,8 +1248,10 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
h = tb_hash_func(phys_pc, tb->pc, tb->flags, tb->trace_vcpu_dstate);
|
||||
qht_insert(&tcg_ctx.tb_ctx.htable, tb, h);
|
||||
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_page_check();
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (DEBUG_TB_CHECK_GATE) {
|
||||
tb_page_check();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1263,13 +1288,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
}
|
||||
|
||||
gen_code_buf = tcg_ctx.code_gen_ptr;
|
||||
tb->tc_ptr = gen_code_buf;
|
||||
tb->tc.ptr = gen_code_buf;
|
||||
tb->pc = pc;
|
||||
tb->cs_base = cs_base;
|
||||
tb->flags = flags;
|
||||
tb->cflags = cflags;
|
||||
tb->trace_vcpu_dstate = *cpu->trace_dstate;
|
||||
tb->invalid = false;
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_ctx.tb_count1++; /* includes aborted translations because of
|
||||
@ -1283,7 +1307,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
gen_intermediate_code(cpu, tb);
|
||||
tcg_ctx.cpu = NULL;
|
||||
|
||||
trace_translate_block(tb, tb->pc, tb->tc_ptr);
|
||||
trace_translate_block(tb, tb->pc, tb->tc.ptr);
|
||||
|
||||
/* generate machine code */
|
||||
tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
|
||||
@ -1300,7 +1324,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_ctx.tb_count++;
|
||||
tcg_ctx.interm_time += profile_getclock() - ti;
|
||||
tcg_ctx.code_time -= profile_getclock();
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
|
||||
/* ??? Overflow could be handled better here. In particular, we
|
||||
@ -1318,7 +1342,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
tcg_ctx.code_time += profile_getclock();
|
||||
tcg_ctx.code_time += profile_getclock() - ti;
|
||||
tcg_ctx.code_in_len += tb->size;
|
||||
tcg_ctx.code_out_len += gen_code_size;
|
||||
tcg_ctx.search_out_len += search_size;
|
||||
@ -1330,11 +1354,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
qemu_log_lock();
|
||||
qemu_log("OUT: [size=%d]\n", gen_code_size);
|
||||
if (tcg_ctx.data_gen_ptr) {
|
||||
size_t code_size = tcg_ctx.data_gen_ptr - tb->tc_ptr;
|
||||
size_t code_size = tcg_ctx.data_gen_ptr - tb->tc.ptr;
|
||||
size_t data_size = gen_code_size - code_size;
|
||||
size_t i;
|
||||
|
||||
log_disas(tb->tc_ptr, code_size);
|
||||
log_disas(tb->tc.ptr, code_size);
|
||||
|
||||
for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
|
||||
if (sizeof(tcg_target_ulong) == 8) {
|
||||
@ -1348,7 +1372,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_disas(tb->tc_ptr, gen_code_size);
|
||||
log_disas(tb->tc.ptr, gen_code_size);
|
||||
}
|
||||
qemu_log("\n");
|
||||
qemu_log_flush();
|
||||
@ -1675,7 +1699,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
|
||||
while (m_min <= m_max) {
|
||||
m = (m_min + m_max) >> 1;
|
||||
tb = tcg_ctx.tb_ctx.tbs[m];
|
||||
v = (uintptr_t)tb->tc_ptr;
|
||||
v = (uintptr_t)tb->tc.ptr;
|
||||
if (v == tc_ptr) {
|
||||
return tb;
|
||||
} else if (tc_ptr < v) {
|
||||
@ -1936,7 +1960,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
|
||||
atomic_read(&tcg_ctx.tb_ctx.tb_flush_count));
|
||||
cpu_fprintf(f, "TB invalidate count %d\n",
|
||||
tcg_ctx.tb_ctx.tb_phys_invalidate_count);
|
||||
cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
|
||||
cpu_fprintf(f, "TLB flush count %zu\n", tlb_flush_count());
|
||||
tcg_dump_info(f, cpu_fprintf);
|
||||
|
||||
tb_unlock();
|
||||
@ -2213,8 +2237,10 @@ int page_unprotect(target_ulong address, uintptr_t pc)
|
||||
/* and since the content will be modified, we must invalidate
|
||||
the corresponding translated code. */
|
||||
current_tb_invalidated |= tb_invalidate_phys_page(addr, pc);
|
||||
#ifdef DEBUG_TB_CHECK
|
||||
tb_invalidate_check(addr);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (DEBUG_TB_CHECK_GATE) {
|
||||
tb_invalidate_check(addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
mprotect((void *)g2h(host_start), qemu_host_page_size,
|
||||
|
4
exec.c
4
exec.c
@ -120,8 +120,6 @@ int use_icount;
|
||||
|
||||
uintptr_t qemu_host_page_size;
|
||||
intptr_t qemu_host_page_mask;
|
||||
uintptr_t qemu_real_host_page_size;
|
||||
intptr_t qemu_real_host_page_mask;
|
||||
|
||||
bool set_preferred_target_page_bits(int bits)
|
||||
{
|
||||
@ -3606,8 +3604,6 @@ void page_size_init(void)
|
||||
{
|
||||
/* NOTE: we can always suppose that qemu_host_page_size >=
|
||||
TARGET_PAGE_SIZE */
|
||||
qemu_real_host_page_size = getpagesize();
|
||||
qemu_real_host_page_mask = -(intptr_t)qemu_real_host_page_size;
|
||||
if (qemu_host_page_size == 0) {
|
||||
qemu_host_page_size = qemu_real_host_page_size;
|
||||
}
|
||||
|
@ -229,8 +229,6 @@ extern int target_page_bits;
|
||||
/* Using intptr_t ensures that qemu_*_page_mask is sign-extended even
|
||||
* when intptr_t is 32-bit and we are aligning a long long.
|
||||
*/
|
||||
extern uintptr_t qemu_real_host_page_size;
|
||||
extern intptr_t qemu_real_host_page_mask;
|
||||
extern uintptr_t qemu_host_page_size;
|
||||
extern intptr_t qemu_host_page_mask;
|
||||
|
||||
|
@ -137,6 +137,7 @@ typedef struct CPUIOTLBEntry {
|
||||
CPUTLBEntry tlb_v_table[NB_MMU_MODES][CPU_VTLB_SIZE]; \
|
||||
CPUIOTLBEntry iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \
|
||||
CPUIOTLBEntry iotlb_v[NB_MMU_MODES][CPU_VTLB_SIZE]; \
|
||||
size_t tlb_flush_count; \
|
||||
target_ulong tlb_flush_addr; \
|
||||
target_ulong tlb_flush_mask; \
|
||||
target_ulong vtlb_index; \
|
||||
|
@ -23,7 +23,6 @@
|
||||
/* cputlb.c */
|
||||
void tlb_protect_code(ram_addr_t ram_addr);
|
||||
void tlb_unprotect_code(ram_addr_t ram_addr);
|
||||
extern int tlb_flush_count;
|
||||
|
||||
size_t tlb_flush_count(void);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -31,8 +31,10 @@
|
||||
type. */
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
typedef abi_ulong tb_page_addr_t;
|
||||
#define TB_PAGE_ADDR_FMT TARGET_ABI_FMT_lx
|
||||
#else
|
||||
typedef ram_addr_t tb_page_addr_t;
|
||||
#define TB_PAGE_ADDR_FMT RAM_ADDR_FMT
|
||||
#endif
|
||||
|
||||
#include "qemu/log.h"
|
||||
@ -301,6 +303,14 @@ static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
|
||||
#define CODE_GEN_AVG_BLOCK_SIZE 150
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Translation Cache-related fields of a TB.
|
||||
*/
|
||||
struct tb_tc {
|
||||
void *ptr; /* pointer to the translated code */
|
||||
uint8_t *search; /* pointer to search data */
|
||||
};
|
||||
|
||||
struct TranslationBlock {
|
||||
target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */
|
||||
target_ulong cs_base; /* CS base for this block */
|
||||
@ -314,14 +324,13 @@ struct TranslationBlock {
|
||||
#define CF_NOCACHE 0x10000 /* To be freed after execution */
|
||||
#define CF_USE_ICOUNT 0x20000
|
||||
#define CF_IGNORE_ICOUNT 0x40000 /* Do not generate icount code */
|
||||
#define CF_INVALID 0x80000 /* TB is stale. Setters must acquire tb_lock */
|
||||
|
||||
/* Per-vCPU dynamic tracing state used to generate this TB */
|
||||
uint32_t trace_vcpu_dstate;
|
||||
|
||||
uint16_t invalid;
|
||||
struct tb_tc tc;
|
||||
|
||||
void *tc_ptr; /* pointer to the translated code */
|
||||
uint8_t *tc_search; /* pointer to search data */
|
||||
/* original tb when cflags has CF_NOCACHE */
|
||||
struct TranslationBlock *orig_tb;
|
||||
/* first and second physical page containing code. The lower bit
|
||||
@ -332,7 +341,7 @@ struct TranslationBlock {
|
||||
/* The following data are used to directly call another TB from
|
||||
* the code of this one. This can be done either by emitting direct or
|
||||
* indirect native jump instructions. These jumps are reset so that the TB
|
||||
* just continue its execution. The TB can be linked to another one by
|
||||
* just continues its execution. The TB can be linked to another one by
|
||||
* setting one of the jump targets (or patching the jump instruction). Only
|
||||
* two of such jumps are supported.
|
||||
*/
|
||||
@ -340,7 +349,7 @@ struct TranslationBlock {
|
||||
#define TB_JMP_RESET_OFFSET_INVALID 0xffff /* indicates no jump generated */
|
||||
uintptr_t jmp_target_arg[2]; /* target address or offset */
|
||||
|
||||
/* Each TB has an assosiated circular list of TBs jumping to this one.
|
||||
/* Each TB has an associated circular list of TBs jumping to this one.
|
||||
* jmp_list_first points to the first TB jumping to this one.
|
||||
* jmp_list_next is used to point to the next TB in a list.
|
||||
* Since each TB can have two jumps, it can participate in two lists.
|
||||
|
49
include/exec/tb-lookup.h
Normal file
49
include/exec/tb-lookup.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
|
||||
*
|
||||
* License: GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
#ifndef EXEC_TB_LOOKUP_H
|
||||
#define EXEC_TB_LOOKUP_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
#include "cpu.h"
|
||||
#else
|
||||
#include "exec/poison.h"
|
||||
#endif
|
||||
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/tb-hash.h"
|
||||
|
||||
/* Might cause an exception, so have a longjmp destination ready */
|
||||
static inline TranslationBlock *
|
||||
tb_lookup__cpu_state(CPUState *cpu, target_ulong *pc, target_ulong *cs_base,
|
||||
uint32_t *flags)
|
||||
{
|
||||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
uint32_t hash;
|
||||
|
||||
cpu_get_tb_cpu_state(env, pc, cs_base, flags);
|
||||
hash = tb_jmp_cache_hash_func(*pc);
|
||||
tb = atomic_rcu_read(&cpu->tb_jmp_cache[hash]);
|
||||
if (likely(tb &&
|
||||
tb->pc == *pc &&
|
||||
tb->cs_base == *cs_base &&
|
||||
tb->flags == *flags &&
|
||||
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
|
||||
!(atomic_read(&tb->cflags) & CF_INVALID))) {
|
||||
return tb;
|
||||
}
|
||||
tb = tb_htable_lookup(cpu, *pc, *cs_base, *flags);
|
||||
if (tb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
atomic_set(&cpu->tb_jmp_cache[hash], tb);
|
||||
return tb;
|
||||
}
|
||||
|
||||
#endif /* EXEC_TB_LOOKUP_H */
|
@ -505,6 +505,12 @@ char *qemu_get_pid_name(pid_t pid);
|
||||
*/
|
||||
pid_t qemu_fork(Error **errp);
|
||||
|
||||
/* Using intptr_t ensures that qemu_*_page_mask is sign-extended even
|
||||
* when intptr_t is 32-bit and we are aligning a long long.
|
||||
*/
|
||||
extern uintptr_t qemu_real_host_page_size;
|
||||
extern intptr_t qemu_real_host_page_mask;
|
||||
|
||||
extern int qemu_icache_linesize;
|
||||
extern int qemu_dcache_linesize;
|
||||
|
||||
|
@ -3029,7 +3029,7 @@ static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
/* FALLTHRU */
|
||||
case DISAS_PC_UPDATED:
|
||||
if (!use_exit_tb(ctx)) {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
break;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
@ -379,7 +379,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
|
||||
} else if (s->base.singlestep_enabled) {
|
||||
gen_exception_internal(EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
}
|
||||
@ -11363,7 +11363,7 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
/* fall through */
|
||||
case DISAS_JUMP:
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
break;
|
||||
case DISAS_EXIT:
|
||||
tcg_gen_exit_tb(0);
|
||||
|
@ -4173,10 +4173,7 @@ static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
|
||||
|
||||
static void gen_goto_ptr(void)
|
||||
{
|
||||
TCGv addr = tcg_temp_new();
|
||||
tcg_gen_extu_i32_tl(addr, cpu_R[15]);
|
||||
tcg_gen_lookup_and_goto_ptr(addr);
|
||||
tcg_temp_free(addr);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
|
||||
/* This will end the TB but doesn't guarantee we'll return to
|
||||
|
@ -505,7 +505,7 @@ static void gen_goto_tb(DisasContext *ctx, int which,
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_excp_1(EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1515,7 +1515,7 @@ static DisasJumpType do_ibranch(DisasContext *ctx, TCGv dest,
|
||||
if (link != 0) {
|
||||
tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
|
||||
}
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
return nullify_end(ctx, DISAS_NEXT);
|
||||
} else {
|
||||
cond_prep(&ctx->null_cond);
|
||||
@ -3873,7 +3873,7 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
||||
if (ctx->base.singlestep_enabled) {
|
||||
gen_excp_1(EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -2511,7 +2511,7 @@ static void gen_bnd_jmp(DisasContext *s)
|
||||
If RECHECK_TF, emit a rechecking helper for #DB, ignoring the state of
|
||||
S->TF. This is used by the syscall/sysret insns. */
|
||||
static void
|
||||
do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
|
||||
do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr)
|
||||
{
|
||||
gen_update_cc_op(s);
|
||||
|
||||
@ -2532,12 +2532,8 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
|
||||
tcg_gen_exit_tb(0);
|
||||
} else if (s->tf) {
|
||||
gen_helper_single_step(cpu_env);
|
||||
} else if (!TCGV_IS_UNUSED(jr)) {
|
||||
TCGv vaddr = tcg_temp_new();
|
||||
|
||||
tcg_gen_add_tl(vaddr, jr, cpu_seg_base[R_CS]);
|
||||
tcg_gen_lookup_and_goto_ptr(vaddr);
|
||||
tcg_temp_free(vaddr);
|
||||
} else if (jr) {
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
} else {
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
@ -2547,10 +2543,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
|
||||
static inline void
|
||||
gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf)
|
||||
{
|
||||
TCGv unused;
|
||||
|
||||
TCGV_UNUSED(unused);
|
||||
do_gen_eob_worker(s, inhibit, recheck_tf, unused);
|
||||
do_gen_eob_worker(s, inhibit, recheck_tf, false);
|
||||
}
|
||||
|
||||
/* End of block.
|
||||
@ -2569,7 +2562,7 @@ static void gen_eob(DisasContext *s)
|
||||
/* Jump to register */
|
||||
static void gen_jr(DisasContext *s, TCGv dest)
|
||||
{
|
||||
do_gen_eob_worker(s, false, false, dest);
|
||||
do_gen_eob_worker(s, false, false, true);
|
||||
}
|
||||
|
||||
/* generate a jump to eip. No segment change must happen before as a
|
||||
|
@ -4303,7 +4303,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
||||
save_cpu_state(ctx, 0);
|
||||
gen_helper_raise_exception_debug(cpu_env);
|
||||
}
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_PC);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -10883,7 +10883,7 @@ static void gen_branch(DisasContext *ctx, int insn_bytes)
|
||||
save_cpu_state(ctx, 0);
|
||||
gen_helper_raise_exception_debug(cpu_env);
|
||||
}
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_PC);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown branch 0x%x\n", proc_hflags);
|
||||
|
@ -5949,7 +5949,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
|
||||
} else if (use_exit_tb(&dc) || status == EXIT_PC_STALE_NOCHAIN) {
|
||||
tcg_gen_exit_tb(0);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(psw_addr);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -261,7 +261,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
||||
} else if (use_exit_tb(ctx)) {
|
||||
tcg_gen_exit_tb(0);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,7 +278,7 @@ static void gen_jump(DisasContext * ctx)
|
||||
} else if (use_exit_tb(ctx)) {
|
||||
tcg_gen_exit_tb(0);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
} else {
|
||||
gen_goto_tb(ctx, 0, ctx->delayed_pc);
|
||||
|
@ -2499,7 +2499,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tcg_target_callee_save_regs[] = {
|
||||
static const int tcg_target_callee_save_regs[] = {
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
TCG_REG_RBP,
|
||||
TCG_REG_RBX,
|
||||
|
@ -36,7 +36,7 @@
|
||||
#else
|
||||
/* To assert at compile-time that these values are never used
|
||||
for TCG_TARGET_REG_BITS == 64. */
|
||||
/* extern */ int link_error(void);
|
||||
int link_error(void);
|
||||
# define LO_OFF link_error()
|
||||
# define HI_OFF link_error()
|
||||
#endif
|
||||
@ -2341,7 +2341,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
|
||||
}
|
||||
}
|
||||
|
||||
static int tcg_target_callee_save_regs[] = {
|
||||
static const int tcg_target_callee_save_regs[] = {
|
||||
TCG_REG_S0, /* used for the global env (TCG_AREG0) */
|
||||
TCG_REG_S1,
|
||||
TCG_REG_S2,
|
||||
|
@ -2588,11 +2588,11 @@ void tcg_gen_goto_tb(unsigned idx)
|
||||
tcg_gen_op1i(INDEX_op_goto_tb, idx);
|
||||
}
|
||||
|
||||
void tcg_gen_lookup_and_goto_ptr(TCGv addr)
|
||||
void tcg_gen_lookup_and_goto_ptr(void)
|
||||
{
|
||||
if (TCG_TARGET_HAS_goto_ptr && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
|
||||
TCGv_ptr ptr = tcg_temp_new_ptr();
|
||||
gen_helper_lookup_tb_ptr(ptr, tcg_ctx.tcg_env, addr);
|
||||
gen_helper_lookup_tb_ptr(ptr, tcg_ctx.tcg_env);
|
||||
tcg_gen_op1i(INDEX_op_goto_ptr, GET_TCGV_PTR(ptr));
|
||||
tcg_temp_free_ptr(ptr);
|
||||
} else {
|
||||
|
@ -797,7 +797,7 @@ static inline void tcg_gen_exit_tb(uintptr_t val)
|
||||
void tcg_gen_goto_tb(unsigned idx);
|
||||
|
||||
/**
|
||||
* tcg_gen_lookup_and_goto_ptr() - look up a TB and jump to it if valid
|
||||
* tcg_gen_lookup_and_goto_ptr() - look up the current TB, jump to it if valid
|
||||
* @addr: Guest address of the target TB
|
||||
*
|
||||
* If the TB is not valid, jump to the epilogue.
|
||||
@ -805,7 +805,7 @@ void tcg_gen_goto_tb(unsigned idx);
|
||||
* This operation is optional. If the TCG backend does not implement goto_ptr,
|
||||
* this op is equivalent to calling tcg_gen_exit_tb() with 0 as the argument.
|
||||
*/
|
||||
void tcg_gen_lookup_and_goto_ptr(TCGv addr);
|
||||
void tcg_gen_lookup_and_goto_ptr(void);
|
||||
|
||||
#if TARGET_LONG_BITS == 32
|
||||
#define tcg_temp_new() tcg_temp_new_i32()
|
||||
|
18
tcg/tcg.c
18
tcg/tcg.c
@ -116,6 +116,8 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type,
|
||||
static bool tcg_out_ldst_finalize(TCGContext *s);
|
||||
#endif
|
||||
|
||||
#define TCG_HIGHWATER 1024
|
||||
|
||||
static TCGRegSet tcg_target_available_regs[2];
|
||||
static TCGRegSet tcg_target_call_clobber_regs;
|
||||
|
||||
@ -318,6 +320,7 @@ typedef struct TCGHelperInfo {
|
||||
static const TCGHelperInfo all_helpers[] = {
|
||||
#include "exec/helper-tcg.h"
|
||||
};
|
||||
static GHashTable *helper_table;
|
||||
|
||||
static int indirect_reg_alloc_order[ARRAY_SIZE(tcg_target_reg_alloc_order)];
|
||||
static void process_op_defs(TCGContext *s);
|
||||
@ -328,7 +331,6 @@ void tcg_context_init(TCGContext *s)
|
||||
TCGOpDef *def;
|
||||
TCGArgConstraint *args_ct;
|
||||
int *sorted_args;
|
||||
GHashTable *helper_table;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->nb_globals = 0;
|
||||
@ -356,7 +358,7 @@ void tcg_context_init(TCGContext *s)
|
||||
|
||||
/* Register helpers. */
|
||||
/* Use g_direct_hash/equal for direct pointer comparisons on func. */
|
||||
s->helpers = helper_table = g_hash_table_new(NULL, NULL);
|
||||
helper_table = g_hash_table_new(NULL, NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
|
||||
g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
|
||||
@ -430,7 +432,7 @@ void tcg_prologue_init(TCGContext *s)
|
||||
/* Compute a high-water mark, at which we voluntarily flush the buffer
|
||||
and start over. The size here is arbitrary, significantly larger
|
||||
than we expect the code generation for any one opcode to require. */
|
||||
s->code_gen_highwater = s->code_gen_buffer + (total_size - 1024);
|
||||
s->code_gen_highwater = s->code_gen_buffer + (total_size - TCG_HIGHWATER);
|
||||
|
||||
tcg_register_jit(s->code_gen_buffer, total_size);
|
||||
|
||||
@ -982,7 +984,7 @@ void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
|
||||
unsigned sizemask, flags;
|
||||
TCGHelperInfo *info;
|
||||
|
||||
info = g_hash_table_lookup(s->helpers, (gpointer)func);
|
||||
info = g_hash_table_lookup(helper_table, (gpointer)func);
|
||||
flags = info->flags;
|
||||
sizemask = info->sizemask;
|
||||
|
||||
@ -1211,8 +1213,8 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf,
|
||||
static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
if (s->helpers) {
|
||||
TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val);
|
||||
if (helper_table) {
|
||||
TCGHelperInfo *info = g_hash_table_lookup(helper_table, (gpointer)val);
|
||||
if (info) {
|
||||
ret = info->name;
|
||||
}
|
||||
@ -2836,8 +2838,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
|
||||
|
||||
tcg_reg_alloc_start(s);
|
||||
|
||||
s->code_buf = tb->tc_ptr;
|
||||
s->code_ptr = tb->tc_ptr;
|
||||
s->code_buf = tb->tc.ptr;
|
||||
s->code_ptr = tb->tc.ptr;
|
||||
|
||||
#ifdef TCG_TARGET_NEED_LDST_LABELS
|
||||
s->ldst_labels = NULL;
|
||||
|
@ -656,8 +656,6 @@ struct TCGContext {
|
||||
|
||||
tcg_insn_unit *code_ptr;
|
||||
|
||||
GHashTable *helpers;
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
/* profiling info */
|
||||
int64_t tb_count1;
|
||||
|
@ -40,6 +40,7 @@ util-obj-y += buffer.o
|
||||
util-obj-y += timed-average.o
|
||||
util-obj-y += base64.o
|
||||
util-obj-y += log.o
|
||||
util-obj-y += pagesize.o
|
||||
util-obj-y += qdist.o
|
||||
util-obj-y += qht.o
|
||||
util-obj-y += range.o
|
||||
|
18
util/pagesize.c
Normal file
18
util/pagesize.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* pagesize.c - query the host about its page size
|
||||
*
|
||||
* Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
|
||||
* License: GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
uintptr_t qemu_real_host_page_size;
|
||||
intptr_t qemu_real_host_page_mask;
|
||||
|
||||
static void __attribute__((constructor)) init_real_host_page_size(void)
|
||||
{
|
||||
qemu_real_host_page_size = getpagesize();
|
||||
qemu_real_host_page_mask = -(intptr_t)qemu_real_host_page_size;
|
||||
}
|
Loading…
Reference in New Issue
Block a user