27 |
#include <sys/mman.h> |
#include <sys/mman.h> |
28 |
|
|
29 |
#include "cpu-i386.h" |
#include "cpu-i386.h" |
30 |
|
#include "exec.h" |
31 |
|
|
32 |
//#define DEBUG_TB_INVALIDATE |
//#define DEBUG_TB_INVALIDATE |
33 |
#define DEBUG_FLUSH |
#define DEBUG_FLUSH |
213 |
} |
} |
214 |
|
|
215 |
/* flush all the translation blocks */ |
/* flush all the translation blocks */ |
216 |
|
/* XXX: tb_flush is currently not thread safe */ |
217 |
void tb_flush(void) |
void tb_flush(void) |
218 |
{ |
{ |
219 |
int i; |
int i; |
228 |
tb_hash[i] = NULL; |
tb_hash[i] = NULL; |
229 |
page_flush_tb(); |
page_flush_tb(); |
230 |
code_gen_ptr = code_gen_buffer; |
code_gen_ptr = code_gen_buffer; |
231 |
/* XXX: flush processor icache at this point */ |
/* XXX: flush processor icache at this point if cache flush is |
232 |
|
expensive */ |
233 |
} |
} |
234 |
|
|
235 |
#ifdef DEBUG_TB_CHECK |
#ifdef DEBUG_TB_CHECK |
268 |
} |
} |
269 |
} |
} |
270 |
|
|
271 |
|
void tb_jmp_check(TranslationBlock *tb) |
272 |
|
{ |
273 |
|
TranslationBlock *tb1; |
274 |
|
unsigned int n1; |
275 |
|
|
276 |
|
/* suppress any remaining jumps to this TB */ |
277 |
|
tb1 = tb->jmp_first; |
278 |
|
for(;;) { |
279 |
|
n1 = (long)tb1 & 3; |
280 |
|
tb1 = (TranslationBlock *)((long)tb1 & ~3); |
281 |
|
if (n1 == 2) |
282 |
|
break; |
283 |
|
tb1 = tb1->jmp_next[n1]; |
284 |
|
} |
285 |
|
/* check end of list */ |
286 |
|
if (tb1 != tb) { |
287 |
|
printf("ERROR: jmp_list from 0x%08lx\n", (long)tb); |
288 |
|
} |
289 |
|
} |
290 |
|
|
291 |
#endif |
#endif |
292 |
|
|
293 |
/* invalidate one TB */ |
/* invalidate one TB */ |
305 |
} |
} |
306 |
} |
} |
307 |
|
|
308 |
|
static inline void tb_jmp_remove(TranslationBlock *tb, int n) |
309 |
|
{ |
310 |
|
TranslationBlock *tb1, **ptb; |
311 |
|
unsigned int n1; |
312 |
|
|
313 |
|
ptb = &tb->jmp_next[n]; |
314 |
|
tb1 = *ptb; |
315 |
|
if (tb1) { |
316 |
|
/* find tb(n) in circular list */ |
317 |
|
for(;;) { |
318 |
|
tb1 = *ptb; |
319 |
|
n1 = (long)tb1 & 3; |
320 |
|
tb1 = (TranslationBlock *)((long)tb1 & ~3); |
321 |
|
if (n1 == n && tb1 == tb) |
322 |
|
break; |
323 |
|
if (n1 == 2) { |
324 |
|
ptb = &tb1->jmp_first; |
325 |
|
} else { |
326 |
|
ptb = &tb1->jmp_next[n1]; |
327 |
|
} |
328 |
|
} |
329 |
|
/* now we can suppress tb(n) from the list */ |
330 |
|
*ptb = tb->jmp_next[n]; |
331 |
|
|
332 |
|
tb->jmp_next[n] = NULL; |
333 |
|
} |
334 |
|
} |
335 |
|
|
336 |
|
/* reset the jump entry 'n' of a TB so that it is not chained to |
337 |
|
another TB */ |
338 |
|
static inline void tb_reset_jump(TranslationBlock *tb, int n) |
339 |
|
{ |
340 |
|
tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); |
341 |
|
} |
342 |
|
|
343 |
static inline void tb_invalidate(TranslationBlock *tb, int parity) |
static inline void tb_invalidate(TranslationBlock *tb, int parity) |
344 |
{ |
{ |
345 |
PageDesc *p; |
PageDesc *p; |
346 |
unsigned int page_index1, page_index2; |
unsigned int page_index1, page_index2; |
347 |
unsigned int h; |
unsigned int h, n1; |
348 |
|
TranslationBlock *tb1, *tb2; |
349 |
|
|
350 |
/* remove the TB from the hash list */ |
/* remove the TB from the hash list */ |
351 |
h = tb_hash_func(tb->pc); |
h = tb_hash_func(tb->pc); |
352 |
tb_remove(&tb_hash[h], tb, |
tb_remove(&tb_hash[h], tb, |
364 |
tb_remove(&p->first_tb, tb, |
tb_remove(&p->first_tb, tb, |
365 |
offsetof(TranslationBlock, page_next[page_index2 & 1])); |
offsetof(TranslationBlock, page_next[page_index2 & 1])); |
366 |
} |
} |
367 |
|
|
368 |
|
/* suppress this TB from the two jump lists */ |
369 |
|
tb_jmp_remove(tb, 0); |
370 |
|
tb_jmp_remove(tb, 1); |
371 |
|
|
372 |
|
/* suppress any remaining jumps to this TB */ |
373 |
|
tb1 = tb->jmp_first; |
374 |
|
for(;;) { |
375 |
|
n1 = (long)tb1 & 3; |
376 |
|
if (n1 == 2) |
377 |
|
break; |
378 |
|
tb1 = (TranslationBlock *)((long)tb1 & ~3); |
379 |
|
tb2 = tb1->jmp_next[n1]; |
380 |
|
tb_reset_jump(tb1, n1); |
381 |
|
tb1->jmp_next[n1] = NULL; |
382 |
|
tb1 = tb2; |
383 |
|
} |
384 |
|
tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ |
385 |
} |
} |
386 |
|
|
387 |
/* invalidate all TBs which intersect with the target page starting at addr */ |
/* invalidate all TBs which intersect with the target page starting at addr */ |
444 |
|
|
445 |
/* Allocate a new translation block. Flush the translation buffer if |
/* Allocate a new translation block. Flush the translation buffer if |
446 |
too many translation blocks or too much generated code. */ |
too many translation blocks or too much generated code. */ |
447 |
TranslationBlock *tb_alloc(unsigned long pc, |
TranslationBlock *tb_alloc(unsigned long pc) |
|
unsigned long size) |
|
448 |
{ |
{ |
449 |
TranslationBlock *tb; |
TranslationBlock *tb; |
|
unsigned int page_index1, page_index2; |
|
450 |
|
|
451 |
if (nb_tbs >= CODE_GEN_MAX_BLOCKS || |
if (nb_tbs >= CODE_GEN_MAX_BLOCKS || |
452 |
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) |
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) |
453 |
tb_flush(); |
return NULL; |
454 |
tb = &tbs[nb_tbs++]; |
tb = &tbs[nb_tbs++]; |
455 |
tb->pc = pc; |
tb->pc = pc; |
456 |
tb->size = size; |
return tb; |
457 |
|
} |
458 |
|
|
459 |
|
/* link the tb with the other TBs */ |
460 |
|
void tb_link(TranslationBlock *tb) |
461 |
|
{ |
462 |
|
unsigned int page_index1, page_index2; |
463 |
|
|
464 |
/* add in the page list */ |
/* add in the page list */ |
465 |
page_index1 = pc >> TARGET_PAGE_BITS; |
page_index1 = tb->pc >> TARGET_PAGE_BITS; |
466 |
tb_alloc_page(tb, page_index1); |
tb_alloc_page(tb, page_index1); |
467 |
page_index2 = (pc + size - 1) >> TARGET_PAGE_BITS; |
page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS; |
468 |
if (page_index2 != page_index1) { |
if (page_index2 != page_index1) { |
469 |
tb_alloc_page(tb, page_index2); |
tb_alloc_page(tb, page_index2); |
470 |
} |
} |
471 |
return tb; |
tb->jmp_first = (TranslationBlock *)((long)tb | 2); |
472 |
|
tb->jmp_next[0] = NULL; |
473 |
|
tb->jmp_next[1] = NULL; |
474 |
|
|
475 |
|
/* init original jump addresses */ |
476 |
|
if (tb->tb_next_offset[0] != 0xffff) |
477 |
|
tb_reset_jump(tb, 0); |
478 |
|
if (tb->tb_next_offset[1] != 0xffff) |
479 |
|
tb_reset_jump(tb, 1); |
480 |
} |
} |
481 |
|
|
482 |
/* called from signal handler: invalidate the code and unprotect the |
/* called from signal handler: invalidate the code and unprotect the |