diff options
Diffstat (limited to 'translate-all.c')
-rw-r--r-- | translate-all.c | 173 |
1 files changed, 83 insertions, 90 deletions
diff --git a/translate-all.c b/translate-all.c index 3b5fc7c90..5759974d4 100644 --- a/translate-all.c +++ b/translate-all.c @@ -96,12 +96,16 @@ typedef struct PageDesc { # define L1_MAP_ADDR_SPACE_BITS TARGET_VIRT_ADDR_SPACE_BITS #endif +/* Size of the L2 (and L3, etc) page tables. */ +#define V_L2_BITS 10 +#define V_L2_SIZE (1 << V_L2_BITS) + /* The bits remaining after N lower levels of page tables. */ #define V_L1_BITS_REM \ - ((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS) + ((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % V_L2_BITS) #if V_L1_BITS_REM < 4 -#define V_L1_BITS (V_L1_BITS_REM + L2_BITS) +#define V_L1_BITS (V_L1_BITS_REM + V_L2_BITS) #else #define V_L1_BITS V_L1_BITS_REM #endif @@ -193,9 +197,10 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr /* The cpu state corresponding to 'searched_pc' is restored. */ -static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env, +static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t searched_pc) { + CPUArchState *env = cpu->env_ptr; TCGContext *s = &tcg_ctx; int j; uintptr_t tc_ptr; @@ -212,9 +217,9 @@ static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env, if (use_icount) { /* Reset the cycle counter to the start of the block. */ - env->icount_decr.u16.low += tb->icount; + cpu->icount_decr.u16.low += tb->icount; /* Clear the IO flag. */ - env->can_do_io = 0; + cpu->can_do_io = 0; } /* find opc index corresponding to search_pc */ @@ -237,7 +242,7 @@ static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env, while (s->gen_opc_instr_start[j] == 0) { j--; } - env->icount_decr.u16.low -= s->gen_opc_icount[j]; + cpu->icount_decr.u16.low -= s->gen_opc_icount[j]; restore_state_to_opc(env, tb, j); @@ -248,13 +253,13 @@ static int cpu_restore_state_from_tb(TranslationBlock *tb, CPUArchState *env, return 0; } -bool cpu_restore_state(CPUArchState *env, uintptr_t retaddr) +bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr) { TranslationBlock *tb; tb = tb_find_pc(retaddr); if (tb) { - cpu_restore_state_from_tb(tb, env, retaddr); + cpu_restore_state_from_tb(cpu, tb, retaddr); return true; } return false; @@ -285,17 +290,15 @@ static inline void map_exec(void *addr, long size) } #endif -static void page_init(void) +void page_size_init(void) { /* NOTE: we can always suppose that qemu_host_page_size >= TARGET_PAGE_SIZE */ #ifdef _WIN32 - { - SYSTEM_INFO system_info; + SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - qemu_real_host_page_size = system_info.dwPageSize; - } + GetSystemInfo(&system_info); + qemu_real_host_page_size = system_info.dwPageSize; #else qemu_real_host_page_size = getpagesize(); #endif @@ -306,7 +309,11 @@ static void page_init(void) qemu_host_page_size = TARGET_PAGE_SIZE; } qemu_host_page_mask = ~(qemu_host_page_size - 1); +} +static void page_init(void) +{ + page_size_init(); #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY) { #ifdef HAVE_KINFO_GETVMMAP @@ -395,18 +402,18 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1)); /* Level 2..N-1. */ - for (i = V_L1_SHIFT / L2_BITS - 1; i > 0; i--) { + for (i = V_L1_SHIFT / V_L2_BITS - 1; i > 0; i--) { void **p = *lp; if (p == NULL) { if (!alloc) { return NULL; } - ALLOC(p, sizeof(void *) * L2_SIZE); + ALLOC(p, sizeof(void *) * V_L2_SIZE); *lp = p; } - lp = p + ((index >> (i * L2_BITS)) & (L2_SIZE - 1)); + lp = p + ((index >> (i * V_L2_BITS)) & (V_L2_SIZE - 1)); } pd = *lp; @@ -414,13 +421,13 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) if (!alloc) { return NULL; } - ALLOC(pd, sizeof(PageDesc) * L2_SIZE); + ALLOC(pd, sizeof(PageDesc) * V_L2_SIZE); *lp = pd; } #undef ALLOC - return pd + (index & (L2_SIZE - 1)); + return pd + (index & (V_L2_SIZE - 1)); } static inline PageDesc *page_find(tb_page_addr_t index) @@ -655,14 +662,14 @@ static void page_flush_tb_1(int level, void **lp) if (level == 0) { PageDesc *pd = *lp; - for (i = 0; i < L2_SIZE; ++i) { + for (i = 0; i < V_L2_SIZE; ++i) { pd[i].first_tb = NULL; invalidate_page_bitmap(pd + i); } } else { void **pp = *lp; - for (i = 0; i < L2_SIZE; ++i) { + for (i = 0; i < V_L2_SIZE; ++i) { page_flush_tb_1(level - 1, pp + i); } } @@ -673,7 +680,7 @@ static void page_flush_tb(void) int i; for (i = 0; i < V_L1_SIZE; i++) { - page_flush_tb_1(V_L1_SHIFT / L2_BITS - 1, l1_map + i); + page_flush_tb_1(V_L1_SHIFT / V_L2_BITS - 1, l1_map + i); } } @@ -681,7 +688,7 @@ static void page_flush_tb(void) /* XXX: tb_flush is currently not thread safe */ void tb_flush(CPUArchState *env1) { - 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", @@ -692,18 +699,15 @@ void tb_flush(CPUArchState *env1) #endif if ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) > tcg_ctx.code_gen_buffer_size) { - cpu_abort(env1, "Internal error: code buffer overflow\n"); + cpu_abort(cpu, "Internal error: code buffer overflow\n"); } tcg_ctx.tb_ctx.nb_tbs = 0; - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - CPUArchState *env = cpu->env_ptr; - - memset(env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *)); + CPU_FOREACH(cpu) { + memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache)); } - memset(tcg_ctx.tb_ctx.tb_phys_hash, 0, - CODE_GEN_PHYS_HASH_SIZE * sizeof(void *)); + memset(tcg_ctx.tb_ctx.tb_phys_hash, 0, sizeof(tcg_ctx.tb_ctx.tb_phys_hash)); page_flush_tb(); tcg_ctx.code_gen_ptr = tcg_ctx.code_gen_buffer; @@ -850,11 +854,9 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) /* remove the TB from the hash list */ h = tb_jmp_cache_hash_func(tb->pc); - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - CPUArchState *env = cpu->env_ptr; - - if (env->tb_jmp_cache[h] == tb) { - env->tb_jmp_cache[h] = NULL; + CPU_FOREACH(cpu) { + if (cpu->tb_jmp_cache[h] == tb) { + cpu->tb_jmp_cache[h] = NULL; } } @@ -936,10 +938,11 @@ static void build_page_bitmap(PageDesc *p) } } -TranslationBlock *tb_gen_code(CPUArchState *env, +TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, target_ulong cs_base, int flags, int cflags) { + CPUArchState *env = cpu->env_ptr; TranslationBlock *tb; uint8_t *tc_ptr; tb_page_addr_t phys_pc, phys_page2; @@ -1004,7 +1007,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, { TranslationBlock *tb, *tb_next, *saved_tb; CPUState *cpu = current_cpu; -#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY) +#if defined(TARGET_HAS_PRECISE_SMC) CPUArchState *env = NULL; #endif tb_page_addr_t tb_start, tb_end; @@ -1029,7 +1032,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, /* build code bitmap */ build_page_bitmap(p); } -#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY) +#if defined(TARGET_HAS_PRECISE_SMC) if (cpu != NULL) { env = cpu->env_ptr; } @@ -1058,9 +1061,9 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, if (current_tb_not_found) { current_tb_not_found = 0; current_tb = NULL; - if (env->mem_io_pc) { + if (cpu->mem_io_pc) { /* now we have a real cpu fault */ - current_tb = tb_find_pc(env->mem_io_pc); + current_tb = tb_find_pc(cpu->mem_io_pc); } } if (current_tb == tb && @@ -1072,7 +1075,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, restore the CPU state */ current_tb_modified = 1; - cpu_restore_state_from_tb(current_tb, env, env->mem_io_pc); + cpu_restore_state_from_tb(cpu, current_tb, cpu->mem_io_pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -1099,7 +1102,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, if (!p->first_tb) { invalidate_page_bitmap(p); if (is_cpu_write_access) { - tlb_unprotect_code_phys(env, start, env->mem_io_vaddr); + tlb_unprotect_code_phys(cpu, start, cpu->mem_io_vaddr); } } #endif @@ -1109,8 +1112,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, modifying the memory. It will ensure that it cannot modify itself */ cpu->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); - cpu_resume_from_signal(env, NULL); + tb_gen_code(cpu, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(cpu, NULL); } #endif } @@ -1191,7 +1194,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, restore the CPU state */ current_tb_modified = 1; - cpu_restore_state_from_tb(current_tb, env, pc); + cpu_restore_state_from_tb(cpu, current_tb, pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -1206,11 +1209,11 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, modifying the memory. It will ensure that it cannot modify itself */ cpu->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + tb_gen_code(cpu, current_pc, current_cs_base, current_flags, 1); if (locked) { mmap_unlock(); } - cpu_resume_from_signal(env, puc); + cpu_resume_from_signal(cpu, puc); } #endif } @@ -1318,18 +1321,6 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, mmap_unlock(); } -#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) -/* check whether the given addr is in TCG generated code buffer or not */ -bool is_tcg_gen_code(uintptr_t tc_ptr) -{ - /* This can be called during code generation, code_gen_buffer_size - is used instead of code_gen_ptr for upper boundary checking */ - return (tc_ptr >= (uintptr_t)tcg_ctx.code_gen_buffer && - tc_ptr < (uintptr_t)(tcg_ctx.code_gen_buffer + - tcg_ctx.code_gen_buffer_size)); -} -#endif - /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < tb[1].tc_ptr. Return NULL if not found */ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) @@ -1364,13 +1355,13 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) } #if defined(TARGET_HAS_ICE) && !defined(CONFIG_USER_ONLY) -void tb_invalidate_phys_addr(hwaddr addr) +void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr) { ram_addr_t ram_addr; MemoryRegion *mr; hwaddr l = 1; - mr = address_space_translate(&address_space_memory, addr, &addr, &l, false); + mr = address_space_translate(as, addr, &addr, &l, false); if (!(memory_region_is_ram(mr) || memory_region_is_romd(mr))) { return; @@ -1381,16 +1372,16 @@ void tb_invalidate_phys_addr(hwaddr addr) } #endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */ -void tb_check_watchpoint(CPUArchState *env) +void tb_check_watchpoint(CPUState *cpu) { TranslationBlock *tb; - tb = tb_find_pc(env->mem_io_pc); + tb = tb_find_pc(cpu->mem_io_pc); if (!tb) { - cpu_abort(env, "check_watchpoint: could not find TB for pc=%p", - (void *)env->mem_io_pc); + cpu_abort(cpu, "check_watchpoint: could not find TB for pc=%p", + (void *)cpu->mem_io_pc); } - cpu_restore_state_from_tb(tb, env, env->mem_io_pc); + cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc); tb_phys_invalidate(tb, -1); } @@ -1398,7 +1389,6 @@ void tb_check_watchpoint(CPUArchState *env) /* mask must never be zero, except for A20 change call */ static void tcg_handle_interrupt(CPUState *cpu, int mask) { - CPUArchState *env = cpu->env_ptr; int old_mask; old_mask = cpu->interrupt_request; @@ -1414,10 +1404,10 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) } if (use_icount) { - env->icount_decr.u16.high = 0xffff; - if (!can_do_io(env) + cpu->icount_decr.u16.high = 0xffff; + if (!cpu_can_do_io(cpu) && (mask & ~old_mask) != 0) { - cpu_abort(env, "Raised interrupt while not in I/O function"); + cpu_abort(cpu, "Raised interrupt while not in I/O function"); } } else { cpu->tcg_exit_req = 1; @@ -1428,8 +1418,11 @@ CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt; /* in deterministic execution mode, instructions doing device I/Os must be at the end of the TB */ -void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr) +void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) { +#if defined(TARGET_MIPS) || defined(TARGET_SH4) + CPUArchState *env = cpu->env_ptr; +#endif TranslationBlock *tb; uint32_t n, cflags; target_ulong pc, cs_base; @@ -1437,14 +1430,14 @@ void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr) tb = tb_find_pc(retaddr); if (!tb) { - cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p", + cpu_abort(cpu, "cpu_io_recompile: could not find TB for pc=%p", (void *)retaddr); } - n = env->icount_decr.u16.low + tb->icount; - cpu_restore_state_from_tb(tb, env, retaddr); + n = cpu->icount_decr.u16.low + tb->icount; + cpu_restore_state_from_tb(cpu, tb, retaddr); /* Calculate how many instructions had been executed before the fault occurred. */ - n = n - env->icount_decr.u16.low; + n = n - cpu->icount_decr.u16.low; /* Generate a new TB ending on the I/O insn. */ n++; /* On MIPS and SH, delay slot instructions can only be restarted if @@ -1454,20 +1447,20 @@ void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr) #if defined(TARGET_MIPS) if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { env->active_tc.PC -= 4; - env->icount_decr.u16.low++; + cpu->icount_decr.u16.low++; env->hflags &= ~MIPS_HFLAG_BMASK; } #elif defined(TARGET_SH4) if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 && n > 1) { env->pc -= 2; - env->icount_decr.u16.low++; + cpu->icount_decr.u16.low++; env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); } #endif /* This should never happen. */ if (n > CF_COUNT_MASK) { - cpu_abort(env, "TB too big during recompile"); + cpu_abort(cpu, "TB too big during recompile"); } cflags = n | CF_LAST_IO; @@ -1477,27 +1470,27 @@ void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr) tb_phys_invalidate(tb, -1); /* 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(env, pc, cs_base, flags, cflags); + tb_gen_code(cpu, pc, cs_base, flags, cflags); /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not the first in the TB) then we end up generating a whole new TB and repeating the fault, which is horribly inefficient. Better would be to execute just this insn uncached, or generate a second new TB. */ - cpu_resume_from_signal(env, NULL); + cpu_resume_from_signal(cpu, NULL); } -void tb_flush_jmp_cache(CPUArchState *env, target_ulong addr) +void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr) { unsigned int i; /* Discard jump cache entries for any tb which might potentially overlap the flushed page. */ i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); - memset(&env->tb_jmp_cache[i], 0, + memset(&cpu->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); i = tb_jmp_cache_hash_page(addr); - memset(&env->tb_jmp_cache[i], 0, + memset(&cpu->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *)); } @@ -1612,7 +1605,7 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data, if (level == 0) { PageDesc *pd = *lp; - for (i = 0; i < L2_SIZE; ++i) { + for (i = 0; i < V_L2_SIZE; ++i) { int prot = pd[i].flags; pa = base | (i << TARGET_PAGE_BITS); @@ -1626,9 +1619,9 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data, } else { void **pp = *lp; - for (i = 0; i < L2_SIZE; ++i) { + for (i = 0; i < V_L2_SIZE; ++i) { pa = base | ((abi_ulong)i << - (TARGET_PAGE_BITS + L2_BITS * level)); + (TARGET_PAGE_BITS + V_L2_BITS * level)); rc = walk_memory_regions_1(data, pa, level - 1, pp + i); if (rc != 0) { return rc; @@ -1651,7 +1644,7 @@ int walk_memory_regions(void *priv, walk_memory_regions_fn fn) for (i = 0; i < V_L1_SIZE; i++) { int rc = walk_memory_regions_1(&data, (abi_ulong)i << V_L1_SHIFT, - V_L1_SHIFT / L2_BITS - 1, l1_map + i); + V_L1_SHIFT / V_L2_BITS - 1, l1_map + i); if (rc != 0) { return rc; @@ -1679,8 +1672,9 @@ static int dump_region(void *priv, abi_ulong start, /* dump memory mappings */ void page_dump(FILE *f) { - (void) fprintf(f, "%-8s %-8s %-8s %s\n", - "start", "end", "size", "prot"); + const int length = sizeof(abi_ulong) * 2; + (void) fprintf(f, "%-*s %-*s %-*s %s\n", + length, "start", length, "end", length, "size", "prot"); walk_memory_regions(f, dump_region); } @@ -1783,7 +1777,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags) return -1; } } - return 0; } } return 0; |