X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=exec.c;h=08914aecdea88361b17cfc6c0f635e84695e8e00;hb=9529397248a1330cf442e79e4d4bbe912fa7f6e6;hp=9c86765f708cd20ae212b026dad7610e25016f58;hpb=83fb7adf6c653a0285a89d51b746cb642d2859cf;p=qemu diff --git a/exec.c b/exec.c index 9c86765..08914ae 100644 --- a/exec.c +++ b/exec.c @@ -18,6 +18,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" +#ifdef _WIN32 +#include +#else +#include +#include +#endif #include #include #include @@ -25,9 +31,6 @@ #include #include #include -#if !defined(CONFIG_SOFTMMU) -#include -#endif #include "cpu.h" #include "exec-all.h" @@ -55,7 +58,7 @@ int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32))); uint8_t *code_gen_ptr; int phys_ram_size; @@ -77,7 +80,7 @@ typedef struct PageDesc { typedef struct PhysPageDesc { /* offset in host memory of the page + io_index in the low 12 bits */ - unsigned long phys_offset; + uint32_t phys_offset; } PhysPageDesc; typedef struct VirtPageDesc { @@ -107,7 +110,7 @@ unsigned long qemu_host_page_mask; /* XXX: for system emulation, it could just be an array */ static PageDesc *l1_map[L1_SIZE]; -static PhysPageDesc *l1_phys_map[L1_SIZE]; +PhysPageDesc **l1_phys_map; #if !defined(CONFIG_USER_ONLY) static VirtPageDesc *l1_virt_map[L1_SIZE]; @@ -125,15 +128,43 @@ char *logfilename = "/tmp/qemu.log"; FILE *logfile; int loglevel; +/* statistics */ +static int tlb_flush_count; +static int tb_flush_count; +static int tb_phys_invalidate_count; + static void page_init(void) { /* NOTE: we can always suppose that qemu_host_page_size >= TARGET_PAGE_SIZE */ #ifdef _WIN32 - qemu_real_host_page_size = 4096; + { + SYSTEM_INFO system_info; + DWORD old_protect; + + GetSystemInfo(&system_info); + qemu_real_host_page_size = system_info.dwPageSize; + + VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer), + PAGE_EXECUTE_READWRITE, &old_protect); + } #else qemu_real_host_page_size = getpagesize(); + { + unsigned long start, end; + + start = (unsigned long)code_gen_buffer; + start &= ~(qemu_real_host_page_size - 1); + + end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer); + end += qemu_real_host_page_size - 1; + end &= ~(qemu_real_host_page_size - 1); + + mprotect((void *)start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + } #endif + if (qemu_host_page_size == 0) qemu_host_page_size = qemu_real_host_page_size; if (qemu_host_page_size < TARGET_PAGE_SIZE) @@ -145,6 +176,8 @@ static void page_init(void) #if !defined(CONFIG_USER_ONLY) virt_valid_tag = 1; #endif + l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *)); + memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *)); } static inline PageDesc *page_find_alloc(unsigned int index) @@ -180,7 +213,7 @@ static inline PhysPageDesc *phys_page_find_alloc(unsigned int index) p = *lp; if (!p) { /* allocate if not found */ - p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE); + p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); *lp = p; } @@ -205,6 +238,10 @@ static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) { VirtPageDesc **lp, *p; + /* XXX: should not truncate for 64 bit addresses */ +#if TARGET_LONG_BITS > 32 + index &= (L1_SIZE - 1); +#endif lp = &l1_virt_map[index >> L2_BITS]; p = *lp; if (!p) { @@ -290,7 +327,6 @@ static void page_flush_tb(void) /* XXX: tb_flush is currently not thread safe */ void tb_flush(CPUState *env) { - int i; #if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", code_gen_ptr - code_gen_buffer, @@ -298,17 +334,16 @@ void tb_flush(CPUState *env) nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif nb_tbs = 0; - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) - tb_hash[i] = NULL; + memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); virt_page_flush(); - for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) - tb_phys_hash[i] = NULL; + memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); page_flush_tb(); code_gen_ptr = code_gen_buffer; /* XXX: flush processor icache at this point if cache flush is expensive */ + tb_flush_count++; } #ifdef DEBUG_TB_CHECK @@ -503,6 +538,7 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad } tb_invalidate(tb); + tb_phys_invalidate_count++; } static inline void set_bits(uint8_t *tab, int start, int len) @@ -574,13 +610,13 @@ static void tb_gen_code(CPUState *env, target_ulong phys_pc, phys_page2, virt_page2; int code_gen_size; - phys_pc = get_phys_addr_code(env, (unsigned long)pc); - tb = tb_alloc((unsigned long)pc); + phys_pc = get_phys_addr_code(env, pc); + tb = tb_alloc(pc); if (!tb) { /* flush must be done */ tb_flush(env); /* cannot fail at this point */ - tb = tb_alloc((unsigned long)pc); + tb = tb_alloc(pc); } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; @@ -591,9 +627,9 @@ static void tb_gen_code(CPUState *env, code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); /* check next page if needed */ - virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; + virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; phys_page2 = -1; - if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + if ((pc & TARGET_PAGE_MASK) != virt_page2) { phys_page2 = get_phys_addr_code(env, virt_page2); } tb_link_phys(tb, phys_pc, phys_page2); @@ -861,7 +897,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, /* Allocate a new translation block. Flush the translation buffer if too many translation blocks or too much generated code. */ -TranslationBlock *tb_alloc(unsigned long pc) +TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; @@ -1040,6 +1076,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } +#if defined(TARGET_HAS_ICE) static void breakpoint_invalidate(CPUState *env, target_ulong pc) { target_ulong phys_addr; @@ -1047,12 +1084,13 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) phys_addr = cpu_get_phys_page_debug(env, pc); tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0); } +#endif /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) { -#if defined(TARGET_I386) || defined(TARGET_PPC) +#if defined(TARGET_HAS_ICE) int i; for(i = 0; i < env->nb_breakpoints; i++) { @@ -1074,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) /* remove a breakpoint */ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) { -#if defined(TARGET_I386) || defined(TARGET_PPC) +#if defined(TARGET_HAS_ICE) int i; for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) @@ -1082,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) } return -1; found: - memmove(&env->breakpoints[i], &env->breakpoints[i + 1], - (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); env->nb_breakpoints--; + if (i < env->nb_breakpoints) + env->breakpoints[i] = env->breakpoints[env->nb_breakpoints]; breakpoint_invalidate(env, pc); return 0; @@ -1097,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) CPU loop after each instruction */ void cpu_single_step(CPUState *env, int enabled) { -#if defined(TARGET_I386) || defined(TARGET_PPC) +#if defined(TARGET_HAS_ICE) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ @@ -1177,8 +1215,10 @@ CPULogItem cpu_log_items[] = { { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, #endif +#ifdef DEBUG_IOPORT { CPU_LOG_IOPORT, "ioport", "show all i/o ports accesses" }, +#endif { 0, NULL, NULL }, }; @@ -1202,11 +1242,17 @@ int cpu_str_to_log_mask(const char *str) p1 = strchr(p, ','); if (!p1) p1 = p + strlen(p); + if(cmp1(p,p1-p,"all")) { + for(item = cpu_log_items; item->mask != 0; item++) { + mask |= item->mask; + } + } else { for(item = cpu_log_items; item->mask != 0; item++) { if (cmp1(p, p1 - p, item->name)) goto found; } return 0; + } found: mask |= item->mask; if (*p1 != ',') @@ -1225,7 +1271,9 @@ void cpu_abort(CPUState *env, const char *fmt, ...) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); #ifdef TARGET_I386 - cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP); + cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(env, stderr, fprintf, 0); #endif va_end(ap); abort(); @@ -1254,12 +1302,17 @@ void tlb_flush(CPUState *env, int flush_global) } virt_page_flush(); - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) - tb_hash[i] = NULL; + memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); #if !defined(CONFIG_SOFTMMU) munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); #endif +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_flush(env, flush_global); + } +#endif + tlb_flush_count++; } static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) @@ -1316,6 +1369,11 @@ void tlb_flush_page(CPUState *env, target_ulong addr) if (addr < MMAP_AREA_END) munmap((void *)addr, TARGET_PAGE_SIZE); #endif +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_flush_page(env, addr); + } +#endif } static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) @@ -1380,11 +1438,13 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, } } -void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) +void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, + int dirty_flags) { CPUState *env; unsigned long length, start1; - int i; + int i, mask, len; + uint8_t *p; start &= TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); @@ -1392,7 +1452,11 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) length = end - start; if (length == 0) return; - memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS); + mask = ~dirty_flags; + p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); + len = length >> TARGET_PAGE_BITS; + for(i = 0; i < len; i++) + p[i] &= mask; env = cpu_single_env; /* we modify the TLB cache so that the dirty bit will be set again @@ -1451,7 +1515,7 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) CPUState *env = cpu_single_env; int i; - phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff; addr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); @@ -1623,7 +1687,7 @@ int page_unprotect(unsigned long addr, unsigned long pc, void *puc) cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n", (unsigned long)addr, vp->prot); /* set the dirty bit */ - phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff; /* flush the code inside */ tb_invalidate_phys_page(vp->phys_addr, pc, puc); return 1; @@ -1840,8 +1904,8 @@ static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 1); #endif - stb_raw((uint8_t *)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; + stb_p((uint8_t *)(long)addr, val); + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; } static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -1852,8 +1916,8 @@ static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 2); #endif - stw_raw((uint8_t *)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; + stw_p((uint8_t *)(long)addr, val); + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; } static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -1864,8 +1928,8 @@ static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 4); #endif - stl_raw((uint8_t *)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; + stl_p((uint8_t *)(long)addr, val); + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; } static CPUReadMemoryFunc *code_mem_read[3] = { @@ -1882,19 +1946,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = { static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - stb_raw((uint8_t *)addr, val); + stb_p((uint8_t *)(long)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { - stw_raw((uint8_t *)addr, val); + stw_p((uint8_t *)(long)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - stl_raw((uint8_t *)addr, val); + stl_p((uint8_t *)(long)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } @@ -1913,7 +1977,7 @@ static void io_mem_init(void) io_mem_nb = 5; /* alloc dirty bits array */ - phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS); + phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); } /* mem_read and mem_write are arrays of functions containing the @@ -1946,6 +2010,16 @@ int cpu_register_io_memory(int io_index, return io_index << IO_MEM_SHIFT; } +CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index) +{ + return io_mem_write[io_index >> IO_MEM_SHIFT]; +} + +CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index) +{ + return io_mem_read[io_index >> IO_MEM_SHIFT]; +} + /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, @@ -1976,6 +2050,21 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, addr += l; } } + +/* never used */ +uint32_t ldl_phys(target_phys_addr_t addr) +{ + return 0; +} + +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ +} + +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ +} + #else void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) @@ -2004,17 +2093,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ - val = ldl_raw(buf); + val = ldl_p(buf); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ - val = lduw_raw(buf); + val = lduw_p(buf); io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); l = 2; } else { /* 8 bit access */ - val = ldub_raw(buf); + val = ldub_p(buf); io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); l = 1; } @@ -2027,7 +2116,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; } } else { if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && @@ -2037,17 +2126,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); - stl_raw(buf, val); + stl_p(buf, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); - stw_raw(buf, val); + stw_p(buf, val); l = 2; } else { /* 8 bit access */ val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); - stb_raw(buf, val); + stb_p(buf, val); l = 1; } } else { @@ -2062,6 +2151,96 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, addr += l; } } + +/* warning: addr must be aligned */ +uint32_t ldl_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint32_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldl_p(ptr); + } + return val; +} + +/* warning: addr must be aligned. The ram page is not masked as dirty + and the code inside is not invalidated. It is useful if the dirty + bits are used to track modified PTEs */ +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != 0) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + stl_p(ptr, val); + } +} + +/* warning: addr must be aligned */ +/* XXX: optimize code invalidation test */ +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != 0) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = phys_ram_base + addr1; + stl_p(ptr, val); + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + } +} + #endif /* virtual memory access for debug */ @@ -2089,11 +2268,59 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, return 0; } +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i, target_code_size, max_target_code_size; + int direct_jmp_count, direct_jmp2_count, cross_page; + TranslationBlock *tb; + + target_code_size = 0; + max_target_code_size = 0; + cross_page = 0; + direct_jmp_count = 0; + direct_jmp2_count = 0; + for(i = 0; i < nb_tbs; i++) { + tb = &tbs[i]; + target_code_size += tb->size; + if (tb->size > max_target_code_size) + max_target_code_size = tb->size; + if (tb->page_addr[1] != -1) + cross_page++; + if (tb->tb_next_offset[0] != 0xffff) { + direct_jmp_count++; + if (tb->tb_next_offset[1] != 0xffff) { + direct_jmp2_count++; + } + } + } + /* XXX: avoid using doubles ? */ + cpu_fprintf(f, "TB count %d\n", nb_tbs); + cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", + nb_tbs ? target_code_size / nb_tbs : 0, + max_target_code_size); + cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", + nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, + target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); + cpu_fprintf(f, "cross page TB count %d (%d%%)\n", + cross_page, + nb_tbs ? (cross_page * 100) / nb_tbs : 0); + cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", + direct_jmp_count, + nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, + direct_jmp2_count, + nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); + cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); + cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); + cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); +} + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _cmmu #define GETPC() NULL #define env cpu_single_env +#define SOFTMMU_CODE_ACCESS #define SHIFT 0 #include "softmmu_template.h"