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>
master
Peter Maydell 2017-10-11 09:56:16 +01:00
commit e74c0cfa57
29 changed files with 520 additions and 433 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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)

View File

@ -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
View File

@ -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;
}

View File

@ -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;

View File

@ -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; \

View File

@ -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

View File

@ -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
View 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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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 {

View File

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

View File

@ -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;

View File

@ -656,8 +656,6 @@ struct TCGContext {
tcg_insn_unit *code_ptr;
GHashTable *helpers;
#ifdef CONFIG_PROFILER
/* profiling info */
int64_t tb_count1;

552
tcg/tci.c

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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;
}