diff --git a/cpu-all.h b/cpu-all.h index 9a2a548d70..06dc6d7b16 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -767,6 +767,7 @@ int page_get_flags(target_ulong address); void page_set_flags(target_ulong start, target_ulong end, int flags); int page_check_range(target_ulong start, target_ulong len, int flags); +void cpu_exec_init_all(unsigned long tb_size); CPUState *cpu_copy(CPUState *env); void cpu_dump_state(CPUState *env, FILE *f, diff --git a/darwin-user/main.c b/darwin-user/main.c index 10b7fcb9a9..20fde19687 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -873,6 +873,7 @@ int main(int argc, char **argv) #endif } + cpu_exec_init_all(0); /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(cpu_model); diff --git a/exec-all.h b/exec-all.h index d1e581b105..eaf7c40613 100644 --- a/exec-all.h +++ b/exec-all.h @@ -56,12 +56,6 @@ typedef void (GenOpFunc1)(long); typedef void (GenOpFunc2)(long, long); typedef void (GenOpFunc3)(long, long, long); -#if defined(TARGET_I386) - -void optimize_flags_init(void); - -#endif - extern FILE *logfile; extern int loglevel; @@ -105,31 +99,7 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, #define CODE_GEN_PHYS_HASH_BITS 15 #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) -/* maximum total translate dcode allocated */ - -/* NOTE: the translated code area cannot be too big because on some - archs the range of "fast" function calls is limited. Here is a - summary of the ranges: - - i386 : signed 32 bits - arm : signed 26 bits - ppc : signed 24 bits - sparc : signed 32 bits - alpha : signed 23 bits -*/ - -#if defined(__alpha__) -#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) -#elif defined(__ia64) -#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */ -#elif defined(__powerpc__) -#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) -#else -/* XXX: make it dynamic on x86 */ -#define CODE_GEN_BUFFER_SIZE (64 * 1024 * 1024) -#endif - -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) +#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) /* estimated block size for TB allocation */ /* XXX: use a per code average code fragment size and modulate it @@ -140,8 +110,6 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, #define CODE_GEN_AVG_BLOCK_SIZE 64 #endif -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) - #if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__) #define USE_DIRECT_JUMP #endif @@ -210,9 +178,8 @@ void tb_link_phys(TranslationBlock *tb, target_ulong phys_pc, target_ulong phys_page2); extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; - -extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; extern uint8_t *code_gen_ptr; +extern int code_gen_max_blocks; #if defined(USE_DIRECT_JUMP) diff --git a/exec.c b/exec.c index 0aaa8358c9..4b6f9bb443 100644 --- a/exec.c +++ b/exec.c @@ -58,9 +58,6 @@ #undef DEBUG_TB_CHECK #endif -/* threshold to flush the translated code buffer */ -#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size()) - #define SMC_BITMAP_USE_THRESHOLD 10 #define MMAP_AREA_START 0x00000000 @@ -85,13 +82,17 @@ #endif TranslationBlock *tbs; +int code_gen_max_blocks; TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; 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_prologue[1024] __attribute__((aligned (32))); -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32))); +uint8_t *code_gen_buffer; +unsigned long code_gen_buffer_size; +/* threshold to flush the translated code buffer */ +unsigned long code_gen_buffer_max_size; uint8_t *code_gen_ptr; ram_addr_t phys_ram_size; @@ -215,9 +216,6 @@ static void page_init(void) #else qemu_real_host_page_size = getpagesize(); #endif - map_exec(code_gen_buffer, sizeof(code_gen_buffer)); - map_exec(code_gen_prologue, sizeof(code_gen_prologue)); - if (qemu_host_page_size == 0) qemu_host_page_size = qemu_real_host_page_size; if (qemu_host_page_size < TARGET_PAGE_SIZE) @@ -328,18 +326,67 @@ static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr); #endif +void code_gen_alloc(unsigned long tb_size) +{ + code_gen_buffer_size = tb_size; + if (code_gen_buffer_size == 0) { + /* XXX: needs ajustments */ + code_gen_buffer_size = (int)(phys_ram_size / 4); + } + if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE) + code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE; + /* The code gen buffer location may have constraints depending on + the host cpu and OS */ +#if defined(__linux__) + { + int flags; + flags = MAP_PRIVATE | MAP_ANONYMOUS; +#if defined(__x86_64__) + flags |= MAP_32BIT; + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +#endif + code_gen_buffer = mmap(NULL, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, + flags, -1, 0); + if (code_gen_buffer == MAP_FAILED) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + } +#else + code_gen_buffer = qemu_malloc(code_gen_buffer_size); + if (!code_gen_buffer) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + map_exec(code_gen_buffer, code_gen_buffer_size); +#endif + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); + code_gen_buffer_max_size = code_gen_buffer_size - + code_gen_max_block_size(); + code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; + tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); +} + +/* Must be called before using the QEMU cpus. 'tb_size' is the size + (in bytes) allocated to the translation buffer. Zero means default + size. */ +void cpu_exec_init_all(unsigned long tb_size) +{ + page_init(); + cpu_gen_init(); + code_gen_alloc(tb_size); + code_gen_ptr = code_gen_buffer; + io_mem_init(); +} + void cpu_exec_init(CPUState *env) { CPUState **penv; int cpu_index; - if (!code_gen_ptr) { - cpu_gen_init(); - tbs = qemu_malloc(CODE_GEN_MAX_BLOCKS * sizeof(TranslationBlock)); - code_gen_ptr = code_gen_buffer; - page_init(); - io_mem_init(); - } env->next_cpu = NULL; penv = &first_cpu; cpu_index = 0; @@ -390,7 +437,7 @@ void tb_flush(CPUState *env1) nb_tbs, nb_tbs > 0 ? ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); #endif - if ((unsigned long)(code_gen_ptr - code_gen_buffer) > CODE_GEN_BUFFER_SIZE) + if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size) cpu_abort(env1, "Internal error: code buffer overflow\n"); nb_tbs = 0; @@ -960,8 +1007,8 @@ TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; - if (nb_tbs >= CODE_GEN_MAX_BLOCKS || - (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) + if (nb_tbs >= code_gen_max_blocks || + (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) return NULL; tb = &tbs[nb_tbs++]; tb->pc = pc; @@ -2990,7 +3037,10 @@ void dump_exec_info(FILE *f, } /* XXX: avoid using doubles ? */ cpu_fprintf(f, "Translation buffer state:\n"); - cpu_fprintf(f, "TB count %d\n", nb_tbs); + cpu_fprintf(f, "gen code size %ld/%ld\n", + code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); + cpu_fprintf(f, "TB count %d/%d\n", + nb_tbs, code_gen_max_blocks); cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", nb_tbs ? target_code_size / nb_tbs : 0, max_target_code_size); diff --git a/linux-user/main.c b/linux-user/main.c index d5bb1240ca..4087a11ff6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2115,6 +2115,7 @@ int main(int argc, char **argv) cpu_model = "any"; #endif } + cpu_exec_init_all(0); /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(cpu_model); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index f23a782dd6..364485e008 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -723,6 +723,8 @@ static inline int cpu_mmu_index (CPUState *env) return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; } +void optimize_flags_init(void); + typedef struct CCTable { int (*compute_all)(void); /* return all the flags */ int (*compute_c)(void); /* return the C flag */ diff --git a/vl.c b/vl.c index 5430ae6430..18ddcce1f9 100644 --- a/vl.c +++ b/vl.c @@ -7378,6 +7378,7 @@ enum { QEMU_OPTION_old_param, QEMU_OPTION_clock, QEMU_OPTION_startdate, + QEMU_OPTION_tb_size, }; typedef struct QEMUOption { @@ -7489,6 +7490,7 @@ const QEMUOption qemu_options[] = { #endif { "clock", HAS_ARG, QEMU_OPTION_clock }, { "startdate", HAS_ARG, QEMU_OPTION_startdate }, + { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, { NULL }, }; @@ -7697,6 +7699,7 @@ int main(int argc, char **argv) const char *usb_devices[MAX_USB_CMDLINE]; int usb_devices_index; int fds[2]; + int tb_size; const char *pid_file = NULL; VLANState *vlan; @@ -7768,8 +7771,9 @@ int main(int argc, char **argv) hda_index = -1; nb_nics = 0; - /* default mac address of the first network interface */ + tb_size = 0; + optind = 1; for(;;) { if (optind >= argc) @@ -8296,6 +8300,11 @@ int main(int argc, char **argv) } } break; + case QEMU_OPTION_tb_size: + tb_size = strtol(optarg, NULL, 0); + if (tb_size < 0) + tb_size = 0; + break; } } } @@ -8467,6 +8476,9 @@ int main(int argc, char **argv) exit(1); } + /* init the dynamic translator */ + cpu_exec_init_all(tb_size * 1024 * 1024); + bdrv_init(); /* we always create the cdrom drive, even if no disk is there */