| 73 |
longjmp(env->jmp_env, 1); |
longjmp(env->jmp_env, 1); |
| 74 |
} |
} |
| 75 |
|
|
| 76 |
|
|
| 77 |
|
static TranslationBlock *tb_find_slow(target_ulong pc, |
| 78 |
|
target_ulong cs_base, |
| 79 |
|
unsigned int flags) |
| 80 |
|
{ |
| 81 |
|
TranslationBlock *tb, **ptb1; |
| 82 |
|
int code_gen_size; |
| 83 |
|
unsigned int h; |
| 84 |
|
target_ulong phys_pc, phys_page1, phys_page2, virt_page2; |
| 85 |
|
uint8_t *tc_ptr; |
| 86 |
|
|
| 87 |
|
spin_lock(&tb_lock); |
| 88 |
|
|
| 89 |
|
tb_invalidated_flag = 0; |
| 90 |
|
|
| 91 |
|
regs_to_env(); /* XXX: do it just before cpu_gen_code() */ |
| 92 |
|
|
| 93 |
|
/* find translated block using physical mappings */ |
| 94 |
|
phys_pc = get_phys_addr_code(env, pc); |
| 95 |
|
phys_page1 = phys_pc & TARGET_PAGE_MASK; |
| 96 |
|
phys_page2 = -1; |
| 97 |
|
h = tb_phys_hash_func(phys_pc); |
| 98 |
|
ptb1 = &tb_phys_hash[h]; |
| 99 |
|
for(;;) { |
| 100 |
|
tb = *ptb1; |
| 101 |
|
if (!tb) |
| 102 |
|
goto not_found; |
| 103 |
|
if (tb->pc == pc && |
| 104 |
|
tb->page_addr[0] == phys_page1 && |
| 105 |
|
tb->cs_base == cs_base && |
| 106 |
|
tb->flags == flags) { |
| 107 |
|
/* check next page if needed */ |
| 108 |
|
if (tb->page_addr[1] != -1) { |
| 109 |
|
virt_page2 = (pc & TARGET_PAGE_MASK) + |
| 110 |
|
TARGET_PAGE_SIZE; |
| 111 |
|
phys_page2 = get_phys_addr_code(env, virt_page2); |
| 112 |
|
if (tb->page_addr[1] == phys_page2) |
| 113 |
|
goto found; |
| 114 |
|
} else { |
| 115 |
|
goto found; |
| 116 |
|
} |
| 117 |
|
} |
| 118 |
|
ptb1 = &tb->phys_hash_next; |
| 119 |
|
} |
| 120 |
|
not_found: |
| 121 |
|
/* if no translated code available, then translate it now */ |
| 122 |
|
tb = tb_alloc(pc); |
| 123 |
|
if (!tb) { |
| 124 |
|
/* flush must be done */ |
| 125 |
|
tb_flush(env); |
| 126 |
|
/* cannot fail at this point */ |
| 127 |
|
tb = tb_alloc(pc); |
| 128 |
|
/* don't forget to invalidate previous TB info */ |
| 129 |
|
T0 = 0; |
| 130 |
|
} |
| 131 |
|
tc_ptr = code_gen_ptr; |
| 132 |
|
tb->tc_ptr = tc_ptr; |
| 133 |
|
tb->cs_base = cs_base; |
| 134 |
|
tb->flags = flags; |
| 135 |
|
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); |
| 136 |
|
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
| 137 |
|
|
| 138 |
|
/* check next page if needed */ |
| 139 |
|
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; |
| 140 |
|
phys_page2 = -1; |
| 141 |
|
if ((pc & TARGET_PAGE_MASK) != virt_page2) { |
| 142 |
|
phys_page2 = get_phys_addr_code(env, virt_page2); |
| 143 |
|
} |
| 144 |
|
tb_link_phys(tb, phys_pc, phys_page2); |
| 145 |
|
|
| 146 |
|
found: |
| 147 |
|
if (tb_invalidated_flag) { |
| 148 |
|
/* as some TB could have been invalidated because |
| 149 |
|
of memory exceptions while generating the code, we |
| 150 |
|
must recompute the hash index here */ |
| 151 |
|
T0 = 0; |
| 152 |
|
} |
| 153 |
|
/* we add the TB in the virtual pc hash table */ |
| 154 |
|
env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; |
| 155 |
|
spin_unlock(&tb_lock); |
| 156 |
|
return tb; |
| 157 |
|
} |
| 158 |
|
|
| 159 |
|
static inline TranslationBlock *tb_find_fast(void) |
| 160 |
|
{ |
| 161 |
|
TranslationBlock *tb; |
| 162 |
|
target_ulong cs_base, pc; |
| 163 |
|
unsigned int flags; |
| 164 |
|
|
| 165 |
|
/* we record a subset of the CPU state. It will |
| 166 |
|
always be the same before a given translated block |
| 167 |
|
is executed. */ |
| 168 |
|
#if defined(TARGET_I386) |
| 169 |
|
flags = env->hflags; |
| 170 |
|
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); |
| 171 |
|
cs_base = env->segs[R_CS].base; |
| 172 |
|
pc = cs_base + env->eip; |
| 173 |
|
#elif defined(TARGET_ARM) |
| 174 |
|
flags = env->thumb | (env->vfp.vec_len << 1) |
| 175 |
|
| (env->vfp.vec_stride << 4); |
| 176 |
|
cs_base = 0; |
| 177 |
|
pc = env->regs[15]; |
| 178 |
|
#elif defined(TARGET_SPARC) |
| 179 |
|
#ifdef TARGET_SPARC64 |
| 180 |
|
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); |
| 181 |
|
#else |
| 182 |
|
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); |
| 183 |
|
#endif |
| 184 |
|
cs_base = env->npc; |
| 185 |
|
pc = env->pc; |
| 186 |
|
#elif defined(TARGET_PPC) |
| 187 |
|
flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | |
| 188 |
|
(msr_se << MSR_SE) | (msr_le << MSR_LE); |
| 189 |
|
cs_base = 0; |
| 190 |
|
pc = env->nip; |
| 191 |
|
#elif defined(TARGET_MIPS) |
| 192 |
|
flags = env->hflags & MIPS_HFLAGS_TMASK; |
| 193 |
|
cs_base = NULL; |
| 194 |
|
pc = env->PC; |
| 195 |
|
#else |
| 196 |
|
#error unsupported CPU |
| 197 |
|
#endif |
| 198 |
|
tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; |
| 199 |
|
if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base || |
| 200 |
|
tb->flags != flags, 0)) { |
| 201 |
|
tb = tb_find_slow(pc, cs_base, flags); |
| 202 |
|
} |
| 203 |
|
return tb; |
| 204 |
|
} |
| 205 |
|
|
| 206 |
|
|
| 207 |
/* main execution loop */ |
/* main execution loop */ |
| 208 |
|
|
| 209 |
int cpu_exec(CPUState *env1) |
int cpu_exec(CPUState *env1) |
| 246 |
#ifdef __sparc__ |
#ifdef __sparc__ |
| 247 |
int saved_i7, tmp_T0; |
int saved_i7, tmp_T0; |
| 248 |
#endif |
#endif |
| 249 |
int code_gen_size, ret, interrupt_request; |
int ret, interrupt_request; |
| 250 |
void (*gen_func)(void); |
void (*gen_func)(void); |
| 251 |
TranslationBlock *tb, **ptb; |
TranslationBlock *tb; |
|
target_ulong cs_base, pc; |
|
| 252 |
uint8_t *tc_ptr; |
uint8_t *tc_ptr; |
|
unsigned int flags; |
|
| 253 |
|
|
| 254 |
/* first we save global registers */ |
/* first we save global registers */ |
| 255 |
saved_env = env; |
saved_env = env; |
| 419 |
} |
} |
| 420 |
#endif |
#endif |
| 421 |
if (msr_ee != 0) { |
if (msr_ee != 0) { |
| 422 |
if ((interrupt_request & CPU_INTERRUPT_HARD)) { |
if ((interrupt_request & CPU_INTERRUPT_HARD)) { |
| 423 |
/* Raise it */ |
/* Raise it */ |
| 424 |
env->exception_index = EXCP_EXTERNAL; |
env->exception_index = EXCP_EXTERNAL; |
| 425 |
env->error_code = 0; |
env->error_code = 0; |
| 426 |
do_interrupt(env); |
do_interrupt(env); |
| 427 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 428 |
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { |
#ifdef __sparc__ |
| 429 |
/* Raise it */ |
tmp_T0 = 0; |
| 430 |
env->exception_index = EXCP_DECR; |
#else |
| 431 |
env->error_code = 0; |
T0 = 0; |
| 432 |
do_interrupt(env); |
#endif |
| 433 |
|
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { |
| 434 |
|
/* Raise it */ |
| 435 |
|
env->exception_index = EXCP_DECR; |
| 436 |
|
env->error_code = 0; |
| 437 |
|
do_interrupt(env); |
| 438 |
env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
| 439 |
} |
#ifdef __sparc__ |
| 440 |
|
tmp_T0 = 0; |
| 441 |
|
#else |
| 442 |
|
T0 = 0; |
| 443 |
|
#endif |
| 444 |
|
} |
| 445 |
} |
} |
| 446 |
#elif defined(TARGET_MIPS) |
#elif defined(TARGET_MIPS) |
| 447 |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
| 455 |
env->error_code = 0; |
env->error_code = 0; |
| 456 |
do_interrupt(env); |
do_interrupt(env); |
| 457 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 458 |
|
#ifdef __sparc__ |
| 459 |
|
tmp_T0 = 0; |
| 460 |
|
#else |
| 461 |
|
T0 = 0; |
| 462 |
|
#endif |
| 463 |
} |
} |
| 464 |
#elif defined(TARGET_SPARC) |
#elif defined(TARGET_SPARC) |
| 465 |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
| 473 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 474 |
do_interrupt(env->interrupt_index); |
do_interrupt(env->interrupt_index); |
| 475 |
env->interrupt_index = 0; |
env->interrupt_index = 0; |
| 476 |
|
#ifdef __sparc__ |
| 477 |
|
tmp_T0 = 0; |
| 478 |
|
#else |
| 479 |
|
T0 = 0; |
| 480 |
|
#endif |
| 481 |
} |
} |
| 482 |
} else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
} else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
| 483 |
//do_interrupt(0, 0, 0, 0, 0); |
//do_interrupt(0, 0, 0, 0, 0); |
| 548 |
#endif |
#endif |
| 549 |
} |
} |
| 550 |
#endif |
#endif |
| 551 |
/* we record a subset of the CPU state. It will |
tb = tb_find_fast(); |
|
always be the same before a given translated block |
|
|
is executed. */ |
|
|
#if defined(TARGET_I386) |
|
|
flags = env->hflags; |
|
|
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); |
|
|
cs_base = env->segs[R_CS].base; |
|
|
pc = cs_base + env->eip; |
|
|
#elif defined(TARGET_ARM) |
|
|
flags = env->thumb | (env->vfp.vec_len << 1) |
|
|
| (env->vfp.vec_stride << 4); |
|
|
cs_base = 0; |
|
|
pc = env->regs[15]; |
|
|
#elif defined(TARGET_SPARC) |
|
|
#ifdef TARGET_SPARC64 |
|
|
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); |
|
|
#else |
|
|
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); |
|
|
#endif |
|
|
cs_base = env->npc; |
|
|
pc = env->pc; |
|
|
#elif defined(TARGET_PPC) |
|
|
flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | |
|
|
(msr_se << MSR_SE) | (msr_le << MSR_LE); |
|
|
cs_base = 0; |
|
|
pc = env->nip; |
|
|
#elif defined(TARGET_MIPS) |
|
|
flags = env->hflags & MIPS_HFLAGS_TMASK; |
|
|
cs_base = NULL; |
|
|
pc = env->PC; |
|
|
#else |
|
|
#error unsupported CPU |
|
|
#endif |
|
|
tb = tb_find(&ptb, pc, cs_base, |
|
|
flags); |
|
|
if (!tb) { |
|
|
TranslationBlock **ptb1; |
|
|
unsigned int h; |
|
|
target_ulong phys_pc, phys_page1, phys_page2, virt_page2; |
|
|
|
|
|
|
|
|
spin_lock(&tb_lock); |
|
|
|
|
|
tb_invalidated_flag = 0; |
|
|
|
|
|
regs_to_env(); /* XXX: do it just before cpu_gen_code() */ |
|
|
|
|
|
/* find translated block using physical mappings */ |
|
|
phys_pc = get_phys_addr_code(env, pc); |
|
|
phys_page1 = phys_pc & TARGET_PAGE_MASK; |
|
|
phys_page2 = -1; |
|
|
h = tb_phys_hash_func(phys_pc); |
|
|
ptb1 = &tb_phys_hash[h]; |
|
|
for(;;) { |
|
|
tb = *ptb1; |
|
|
if (!tb) |
|
|
goto not_found; |
|
|
if (tb->pc == pc && |
|
|
tb->page_addr[0] == phys_page1 && |
|
|
tb->cs_base == cs_base && |
|
|
tb->flags == flags) { |
|
|
/* check next page if needed */ |
|
|
if (tb->page_addr[1] != -1) { |
|
|
virt_page2 = (pc & TARGET_PAGE_MASK) + |
|
|
TARGET_PAGE_SIZE; |
|
|
phys_page2 = get_phys_addr_code(env, virt_page2); |
|
|
if (tb->page_addr[1] == phys_page2) |
|
|
goto found; |
|
|
} else { |
|
|
goto found; |
|
|
} |
|
|
} |
|
|
ptb1 = &tb->phys_hash_next; |
|
|
} |
|
|
not_found: |
|
|
/* if no translated code available, then translate it now */ |
|
|
tb = tb_alloc(pc); |
|
|
if (!tb) { |
|
|
/* flush must be done */ |
|
|
tb_flush(env); |
|
|
/* cannot fail at this point */ |
|
|
tb = tb_alloc(pc); |
|
|
/* don't forget to invalidate previous TB info */ |
|
|
ptb = &tb_hash[tb_hash_func(pc)]; |
|
|
T0 = 0; |
|
|
} |
|
|
tc_ptr = code_gen_ptr; |
|
|
tb->tc_ptr = tc_ptr; |
|
|
tb->cs_base = cs_base; |
|
|
tb->flags = flags; |
|
|
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); |
|
|
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 = (pc + tb->size - 1) & TARGET_PAGE_MASK; |
|
|
phys_page2 = -1; |
|
|
if ((pc & TARGET_PAGE_MASK) != virt_page2) { |
|
|
phys_page2 = get_phys_addr_code(env, virt_page2); |
|
|
} |
|
|
tb_link_phys(tb, phys_pc, phys_page2); |
|
|
|
|
|
found: |
|
|
if (tb_invalidated_flag) { |
|
|
/* as some TB could have been invalidated because |
|
|
of memory exceptions while generating the code, we |
|
|
must recompute the hash index here */ |
|
|
ptb = &tb_hash[tb_hash_func(pc)]; |
|
|
while (*ptb != NULL) |
|
|
ptb = &(*ptb)->hash_next; |
|
|
T0 = 0; |
|
|
} |
|
|
/* we add the TB in the virtual pc hash table */ |
|
|
*ptb = tb; |
|
|
tb->hash_next = NULL; |
|
|
tb_link(tb); |
|
|
spin_unlock(&tb_lock); |
|
|
} |
|
| 552 |
#ifdef DEBUG_EXEC |
#ifdef DEBUG_EXEC |
| 553 |
if ((loglevel & CPU_LOG_EXEC)) { |
if ((loglevel & CPU_LOG_EXEC)) { |
| 554 |
fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", |
fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", |
| 559 |
#ifdef __sparc__ |
#ifdef __sparc__ |
| 560 |
T0 = tmp_T0; |
T0 = tmp_T0; |
| 561 |
#endif |
#endif |
| 562 |
/* see if we can patch the calling TB. */ |
/* see if we can patch the calling TB. When the TB |
| 563 |
|
spans two pages, we cannot safely do a direct |
| 564 |
|
jump. */ |
| 565 |
{ |
{ |
| 566 |
if (T0 != 0 |
if (T0 != 0 && |
| 567 |
|
tb->page_addr[1] == -1 |
| 568 |
#if defined(TARGET_I386) && defined(USE_CODE_COPY) |
#if defined(TARGET_I386) && defined(USE_CODE_COPY) |
| 569 |
&& (tb->cflags & CF_CODE_COPY) == |
&& (tb->cflags & CF_CODE_COPY) == |
| 570 |
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) |
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) |