#include "qemu-common.h"
#define NO_CPU_IO_DEFS
#include "cpu.h"
+#include "trace.h"
#include "disas/disas.h"
#include "tcg.h"
#if defined(CONFIG_USER_ONLY)
#endif
#include "exec/cputlb.h"
+#include "exec/tb-hash.h"
#include "translate-all.h"
+#include "qemu/bitmap.h"
#include "qemu/timer.h"
//#define DEBUG_TB_INVALIDATE
/* in order to optimize self modifying code, we count the number
of lookups we do to a given page to use a bitmap */
unsigned int code_write_count;
- uint8_t *code_bitmap;
+ unsigned long *code_bitmap;
#if defined(CONFIG_USER_ONLY)
unsigned long flags;
#endif
#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
uintptr_t qemu_real_host_page_size;
+uintptr_t qemu_real_host_page_mask;
uintptr_t qemu_host_page_size;
uintptr_t qemu_host_page_mask;
gen_intermediate_code(env, tb);
+ trace_translate_block(tb, tb->pc, tb->tc_ptr);
+
/* generate machine code */
gen_code_buf = tb->tc_ptr;
tb->tb_next_offset[0] = 0xffff;
gen_intermediate_code_pc(env, tb);
- if (use_icount) {
+ if (tb->cflags & CF_USE_ICOUNT) {
+ assert(use_icount);
/* Reset the cycle counter to the start of the block. */
cpu->icount_decr.u16.low += tb->icount;
/* Clear the IO flag. */
tb = tb_find_pc(retaddr);
if (tb) {
cpu_restore_state_from_tb(cpu, tb, retaddr);
+ if (tb->cflags & CF_NOCACHE) {
+ /* one-shot translation, invalidate it immediately */
+ cpu->current_tb = NULL;
+ tb_phys_invalidate(tb, -1);
+ tb_free(tb);
+ }
return true;
}
return false;
}
#ifdef _WIN32
-static inline void map_exec(void *addr, long size)
+static __attribute__((unused)) void map_exec(void *addr, long size)
{
DWORD old_protect;
VirtualProtect(addr, size,
PAGE_EXECUTE_READWRITE, &old_protect);
}
#else
-static inline void map_exec(void *addr, long size)
+static __attribute__((unused)) void map_exec(void *addr, long size)
{
unsigned long start, end, page_size;
{
/* NOTE: we can always suppose that qemu_host_page_size >=
TARGET_PAGE_SIZE */
-#ifdef _WIN32
- SYSTEM_INFO system_info;
-
- GetSystemInfo(&system_info);
- qemu_real_host_page_size = system_info.dwPageSize;
-#else
qemu_real_host_page_size = getpagesize();
-#endif
+ qemu_real_host_page_mask = ~(qemu_real_host_page_size - 1);
if (qemu_host_page_size == 0) {
qemu_host_page_size = qemu_real_host_page_size;
}
void **lp;
int i;
-#if defined(CONFIG_USER_ONLY)
- /* We can't use g_malloc because it may recurse into a locked mutex. */
-# define ALLOC(P, SIZE) \
- do { \
- P = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, \
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \
- } while (0)
-#else
-# define ALLOC(P, SIZE) \
- do { P = g_malloc0(SIZE); } while (0)
-#endif
-
/* Level 1. Always allocated. */
lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1));
if (!alloc) {
return NULL;
}
- ALLOC(p, sizeof(void *) * V_L2_SIZE);
+ p = g_new0(void *, V_L2_SIZE);
*lp = p;
}
if (!alloc) {
return NULL;
}
- ALLOC(pd, sizeof(PageDesc) * V_L2_SIZE);
+ pd = g_new0(PageDesc, V_L2_SIZE);
*lp = pd;
}
-#undef ALLOC
-
return pd + (index & (V_L2_SIZE - 1));
}
#ifdef __mips__
if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
- /* Try again, with the original still mapped, to avoid re-aquiring
+ /* Try again, with the original still mapped, to avoid re-acquiring
that 256mb crossing. This time don't specify an address. */
size_t size2, size1 = tcg_ctx.code_gen_buffer_size;
void *buf2 = mmap(NULL, size1, PROT_WRITE | PROT_READ | PROT_EXEC,
#else
static inline void *alloc_code_gen_buffer(void)
{
- void *buf = g_malloc(tcg_ctx.code_gen_buffer_size);
+ void *buf = g_try_malloc(tcg_ctx.code_gen_buffer_size);
if (buf == NULL) {
return NULL;
tcg_ctx.code_gen_ptr = tcg_ctx.code_gen_buffer;
tcg_register_jit(tcg_ctx.code_gen_buffer, tcg_ctx.code_gen_buffer_size);
page_init();
-#if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
+#if defined(CONFIG_SOFTMMU)
/* There's no guest base to take into account, so go ahead and
initialize the prologue now. */
tcg_prologue_init(&tcg_ctx);
/* flush all the translation blocks */
/* XXX: tb_flush is currently not thread safe */
-void tb_flush(CPUArchState *env1)
+void tb_flush(CPUState *cpu)
{
- CPUState *cpu = ENV_GET_CPU(env1);
-
#if defined(DEBUG_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.tb_phys_invalidate_count++;
}
-static inline void set_bits(uint8_t *tab, int start, int len)
-{
- int end, mask, end1;
-
- end = start + len;
- tab += start >> 3;
- mask = 0xff << (start & 7);
- if ((start & ~7) == (end & ~7)) {
- if (start < end) {
- mask &= ~(0xff << (end & 7));
- *tab |= mask;
- }
- } else {
- *tab++ |= mask;
- start = (start + 8) & ~7;
- end1 = end & ~7;
- while (start < end1) {
- *tab++ = 0xff;
- start += 8;
- }
- if (start < end) {
- mask = ~(0xff << (end & 7));
- *tab |= mask;
- }
- }
-}
-
static void build_page_bitmap(PageDesc *p)
{
int n, tb_start, tb_end;
TranslationBlock *tb;
- p->code_bitmap = g_malloc0(TARGET_PAGE_SIZE / 8);
+ p->code_bitmap = bitmap_new(TARGET_PAGE_SIZE);
tb = p->first_tb;
while (tb != NULL) {
tb_start = 0;
tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
}
- set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
+ bitmap_set(p->code_bitmap, tb_start, tb_end - tb_start);
tb = tb->page_next[n];
}
}
int code_gen_size;
phys_pc = get_page_addr_code(env, pc);
+ if (use_icount) {
+ cflags |= CF_USE_ICOUNT;
+ }
tb = tb_alloc(pc);
if (!tb) {
/* flush must be done */
- tb_flush(env);
+ tb_flush(cpu);
/* cannot fail at this point */
tb = tb_alloc(pc);
/* Don't forget to invalidate previous TB info. */
* access: the virtual CPU will exit the current TB if code is modified inside
* this TB.
*/
-void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
- int is_cpu_write_access)
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
{
while (start < end) {
- tb_invalidate_phys_page_range(start, end, is_cpu_write_access);
+ tb_invalidate_phys_page_range(start, end, 0);
start &= TARGET_PAGE_MASK;
start += TARGET_PAGE_SIZE;
}
if (!p) {
return;
}
- if (!p->code_bitmap &&
- ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
- is_cpu_write_access) {
- /* build code bitmap */
- build_page_bitmap(p);
- }
#if defined(TARGET_HAS_PRECISE_SMC)
if (cpu != NULL) {
env = cpu->env_ptr;
/* if no code remaining, no need to continue to use slow writes */
if (!p->first_tb) {
invalidate_page_bitmap(p);
- if (is_cpu_write_access) {
- tlb_unprotect_code_phys(cpu, start, cpu->mem_io_vaddr);
- }
+ tlb_unprotect_code(start);
}
#endif
#ifdef TARGET_HAS_PRECISE_SMC
void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
{
PageDesc *p;
- int offset, b;
#if 0
if (1) {
if (!p) {
return;
}
+ if (!p->code_bitmap &&
+ ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) {
+ /* build code bitmap */
+ build_page_bitmap(p);
+ }
if (p->code_bitmap) {
- offset = start & ~TARGET_PAGE_MASK;
- b = p->code_bitmap[offset >> 3] >> (offset & 7);
+ unsigned int nr;
+ unsigned long b;
+
+ nr = start & ~TARGET_PAGE_MASK;
+ b = p->code_bitmap[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG - 1));
if (b & ((1 << len) - 1)) {
goto do_invalidate;
}
p->first_tb = (TranslationBlock *)((uintptr_t)tb | n);
invalidate_page_bitmap(p);
-#if defined(TARGET_HAS_SMC) || 1
-
#if defined(CONFIG_USER_ONLY)
if (p->flags & PAGE_WRITE) {
target_ulong addr;
tlb_protect_code(page_addr);
}
#endif
-
-#endif /* TARGET_HAS_SMC */
}
/* add a new TB and link it to the physical page tables. phys_page2 is
return &tcg_ctx.tb_ctx.tbs[m_max];
}
-#if defined(TARGET_HAS_ICE) && !defined(CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
{
ram_addr_t ram_addr;
MemoryRegion *mr;
hwaddr l = 1;
+ rcu_read_lock();
mr = address_space_translate(as, addr, &addr, &l, false);
if (!(memory_region_is_ram(mr)
|| memory_region_is_romd(mr))) {
+ rcu_read_unlock();
return;
}
ram_addr = (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK)
+ addr;
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
+ rcu_read_unlock();
}
-#endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */
+#endif /* !defined(CONFIG_USER_ONLY) */
void tb_check_watchpoint(CPUState *cpu)
{
TranslationBlock *tb;
tb = tb_find_pc(cpu->mem_io_pc);
- if (!tb) {
- cpu_abort(cpu, "check_watchpoint: could not find TB for pc=%p",
- (void *)cpu->mem_io_pc);
+ if (tb) {
+ /* We can use retranslation to find the PC. */
+ cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
+ tb_phys_invalidate(tb, -1);
+ } else {
+ /* The exception probably happened in a helper. The CPU state should
+ have been saved before calling it. Fetch the PC from there. */
+ CPUArchState *env = cpu->env_ptr;
+ target_ulong pc, cs_base;
+ tb_page_addr_t addr;
+ int flags;
+
+ cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
+ addr = get_page_addr_code(env, pc);
+ tb_invalidate_phys_range(addr, addr + 1);
}
- cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
- tb_phys_invalidate(tb, -1);
}
#ifndef CONFIG_USER_ONLY
if (use_icount) {
cpu->icount_decr.u16.high = 0xffff;
- if (!cpu_can_do_io(cpu)
+ if (!cpu->can_do_io
&& (mask & ~old_mask) != 0) {
cpu_abort(cpu, "Raised interrupt while not in I/O function");
}
branch. */
#if defined(TARGET_MIPS)
if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
- env->active_tc.PC -= 4;
+ env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
cpu->icount_decr.u16.low++;
env->hflags &= ~MIPS_HFLAG_BMASK;
}
cs_base = tb->cs_base;
flags = tb->flags;
tb_phys_invalidate(tb, -1);
+ if (tb->cflags & CF_NOCACHE) {
+ if (tb->orig_tb) {
+ /* Invalidate original TB if this TB was generated in
+ * cpu_exec_nocache() */
+ tb_phys_invalidate(tb->orig_tb, -1);
+ }
+ tb_free(tb);
+ }
/* FIXME: In theory this could raise an exception. In practice
we have already translated the block once so it's probably ok. */
tb_gen_code(cpu, pc, cs_base, flags, cflags);
tcg_dump_info(f, cpu_fprintf);
}
+void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf)
+{
+ tcg_dump_op_count(f, cpu_fprintf);
+}
+
#else /* CONFIG_USER_ONLY */
void cpu_interrupt(CPUState *cpu, int mask)
struct walk_memory_regions_data {
walk_memory_regions_fn fn;
void *priv;
- uintptr_t start;
+ target_ulong start;
int prot;
};
static int walk_memory_regions_end(struct walk_memory_regions_data *data,
- abi_ulong end, int new_prot)
+ target_ulong end, int new_prot)
{
- if (data->start != -1ul) {
+ if (data->start != -1u) {
int rc = data->fn(data->priv, data->start, end, data->prot);
if (rc != 0) {
return rc;
}
}
- data->start = (new_prot ? end : -1ul);
+ data->start = (new_prot ? end : -1u);
data->prot = new_prot;
return 0;
}
static int walk_memory_regions_1(struct walk_memory_regions_data *data,
- abi_ulong base, int level, void **lp)
+ target_ulong base, int level, void **lp)
{
- abi_ulong pa;
+ target_ulong pa;
int i, rc;
if (*lp == NULL) {
void **pp = *lp;
for (i = 0; i < V_L2_SIZE; ++i) {
- pa = base | ((abi_ulong)i <<
+ pa = base | ((target_ulong)i <<
(TARGET_PAGE_BITS + V_L2_BITS * level));
rc = walk_memory_regions_1(data, pa, level - 1, pp + i);
if (rc != 0) {
data.fn = fn;
data.priv = priv;
- data.start = -1ul;
+ data.start = -1u;
data.prot = 0;
for (i = 0; i < V_L1_SIZE; i++) {
- int rc = walk_memory_regions_1(&data, (abi_ulong)i << V_L1_SHIFT,
+ int rc = walk_memory_regions_1(&data, (target_ulong)i << (V_L1_SHIFT + TARGET_PAGE_BITS),
V_L1_SHIFT / V_L2_BITS - 1, l1_map + i);
-
if (rc != 0) {
return rc;
}
return walk_memory_regions_end(&data, 0, 0);
}
-static int dump_region(void *priv, abi_ulong start,
- abi_ulong end, unsigned long prot)
+static int dump_region(void *priv, target_ulong start,
+ target_ulong end, unsigned long prot)
{
FILE *f = (FILE *)priv;
- (void) fprintf(f, TARGET_ABI_FMT_lx"-"TARGET_ABI_FMT_lx
- " "TARGET_ABI_FMT_lx" %c%c%c\n",
+ (void) fprintf(f, TARGET_FMT_lx"-"TARGET_FMT_lx
+ " "TARGET_FMT_lx" %c%c%c\n",
start, end, end - start,
((prot & PAGE_READ) ? 'r' : '-'),
((prot & PAGE_WRITE) ? 'w' : '-'),
/* dump memory mappings */
void page_dump(FILE *f)
{
- const int length = sizeof(abi_ulong) * 2;
+ const int length = sizeof(target_ulong) * 2;
(void) fprintf(f, "%-*s %-*s %-*s %s\n",
length, "start", length, "end", length, "size", "prot");
walk_memory_regions(f, dump_region);
guest address space. If this assert fires, it probably indicates
a missing call to h2g_valid. */
#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
- assert(end < ((abi_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
+ assert(end < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
#endif
assert(start < end);
guest address space. If this assert fires, it probably indicates
a missing call to h2g_valid. */
#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
- assert(start < ((abi_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
+ assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
#endif
if (len == 0) {