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) |