more generic TLB support - began to fix unlikely interrupt issues

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@492 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2004-01-04 15:48:17 +00:00
parent f515528907
commit 0124311e00
2 changed files with 52 additions and 20 deletions

View File

@ -77,7 +77,7 @@ int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc); CPUState *env, unsigned long searched_pc);
void cpu_exec_init(void); void cpu_exec_init(void);
int page_unprotect(unsigned long address); int page_unprotect(unsigned long address);
void page_unmap(void); void tb_invalidate_page(unsigned long address);
void tlb_flush_page(CPUState *env, uint32_t addr); void tlb_flush_page(CPUState *env, uint32_t addr);
void tlb_flush_page_write(CPUState *env, uint32_t addr); void tlb_flush_page_write(CPUState *env, uint32_t addr);
void tlb_flush(CPUState *env); void tlb_flush(CPUState *env);
@ -127,7 +127,7 @@ static inline unsigned int tb_hash_func(unsigned long pc)
} }
TranslationBlock *tb_alloc(unsigned long pc); TranslationBlock *tb_alloc(unsigned long pc);
void tb_flush(void); void tb_flush(CPUState *env);
void tb_link(TranslationBlock *tb); void tb_link(TranslationBlock *tb);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];

68
exec.c
View File

@ -62,7 +62,6 @@ typedef struct PageDesc {
#define L1_SIZE (1 << L1_BITS) #define L1_SIZE (1 << L1_BITS)
#define L2_SIZE (1 << L2_BITS) #define L2_SIZE (1 << L2_BITS)
static void tb_invalidate_page(unsigned long address);
static void io_mem_init(void); static void io_mem_init(void);
unsigned long real_host_page_size; unsigned long real_host_page_size;
@ -229,15 +228,19 @@ static void page_flush_tb(void)
/* flush all the translation blocks */ /* flush all the translation blocks */
/* XXX: tb_flush is currently not thread safe */ /* XXX: tb_flush is currently not thread safe */
void tb_flush(void) void tb_flush(CPUState *env)
{ {
int i; int i;
#ifdef DEBUG_FLUSH #if defined(DEBUG_FLUSH)
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
code_gen_ptr - code_gen_buffer, code_gen_ptr - code_gen_buffer,
nb_tbs, nb_tbs,
(code_gen_ptr - code_gen_buffer) / nb_tbs); nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
#endif #endif
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
nb_tbs = 0; nb_tbs = 0;
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
tb_hash[i] = NULL; tb_hash[i] = NULL;
@ -402,7 +405,7 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity)
} }
/* invalidate all TBs which intersect with the target page starting at addr */ /* invalidate all TBs which intersect with the target page starting at addr */
static void tb_invalidate_page(unsigned long address) void tb_invalidate_page(unsigned long address)
{ {
TranslationBlock *tb_next, *tb; TranslationBlock *tb_next, *tb;
unsigned int page_index; unsigned int page_index;
@ -626,7 +629,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
/* suppress the jump to next tb in generated code */ /* suppress the jump to next tb in generated code */
tb_reset_jump(tb, n); tb_reset_jump(tb, n);
/* suppress jumps in the tb on which we could have jump */ /* suppress jumps in the tb on which we could have jumped */
tb_reset_jump_recursive(tb_next); tb_reset_jump_recursive(tb_next);
} }
} }
@ -688,7 +691,7 @@ void cpu_single_step(CPUState *env, int enabled)
if (env->singlestep_enabled != enabled) { if (env->singlestep_enabled != enabled) {
env->singlestep_enabled = enabled; env->singlestep_enabled = enabled;
/* must flush all the translated code to avoid inconsistancies */ /* must flush all the translated code to avoid inconsistancies */
tb_flush(); tb_flush(env);
} }
#endif #endif
} }
@ -712,7 +715,7 @@ void cpu_set_log_filename(const char *filename)
logfilename = strdup(filename); logfilename = strdup(filename);
} }
/* mask must never be zero */ /* mask must never be zero, except for A20 change call */
void cpu_interrupt(CPUState *env, int mask) void cpu_interrupt(CPUState *env, int mask)
{ {
TranslationBlock *tb; TranslationBlock *tb;
@ -742,9 +745,10 @@ void cpu_abort(CPUState *env, const char *fmt, ...)
abort(); abort();
} }
#ifdef TARGET_I386 #if !defined(CONFIG_USER_ONLY)
/* unmap all maped pages and flush all associated code */ /* unmap all maped pages and flush all associated code */
void page_unmap(void) static void page_unmap(CPUState *env)
{ {
PageDesc *pmap; PageDesc *pmap;
int i; int i;
@ -784,21 +788,25 @@ void page_unmap(void)
l1_map[i] = NULL; l1_map[i] = NULL;
} }
} }
tb_flush(); tb_flush(env);
} }
#endif
void tlb_flush(CPUState *env) void tlb_flush(CPUState *env)
{ {
#if !defined(CONFIG_USER_ONLY)
int i; int i;
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
for(i = 0; i < CPU_TLB_SIZE; i++) { for(i = 0; i < CPU_TLB_SIZE; i++) {
env->tlb_read[0][i].address = -1; env->tlb_read[0][i].address = -1;
env->tlb_write[0][i].address = -1; env->tlb_write[0][i].address = -1;
env->tlb_read[1][i].address = -1; env->tlb_read[1][i].address = -1;
env->tlb_write[1][i].address = -1; env->tlb_write[1][i].address = -1;
} }
#endif /* XXX: avoid flushing the TBs */
page_unmap(env);
} }
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
@ -810,8 +818,11 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
void tlb_flush_page(CPUState *env, uint32_t addr) void tlb_flush_page(CPUState *env, uint32_t addr)
{ {
#if !defined(CONFIG_USER_ONLY) int i, flags;
int i;
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
addr &= TARGET_PAGE_MASK; addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@ -819,23 +830,44 @@ void tlb_flush_page(CPUState *env, uint32_t addr)
tlb_flush_entry(&env->tlb_write[0][i], addr); tlb_flush_entry(&env->tlb_write[0][i], addr);
tlb_flush_entry(&env->tlb_read[1][i], addr); tlb_flush_entry(&env->tlb_read[1][i], addr);
tlb_flush_entry(&env->tlb_write[1][i], addr); tlb_flush_entry(&env->tlb_write[1][i], addr);
flags = page_get_flags(addr);
if (flags & PAGE_VALID) {
#if !defined(CONFIG_SOFTMMU)
munmap((void *)addr, TARGET_PAGE_SIZE);
#endif #endif
page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0);
}
} }
/* make all write to page 'addr' trigger a TLB exception to detect /* make all write to page 'addr' trigger a TLB exception to detect
self modifying code */ self modifying code */
void tlb_flush_page_write(CPUState *env, uint32_t addr) void tlb_flush_page_write(CPUState *env, uint32_t addr)
{ {
#if !defined(CONFIG_USER_ONLY)
int i; int i;
addr &= TARGET_PAGE_MASK; addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_flush_entry(&env->tlb_write[0][i], addr); tlb_flush_entry(&env->tlb_write[0][i], addr);
tlb_flush_entry(&env->tlb_write[1][i], addr); tlb_flush_entry(&env->tlb_write[1][i], addr);
#endif
} }
#else
void tlb_flush(CPUState *env)
{
}
void tlb_flush_page(CPUState *env, uint32_t addr)
{
}
void tlb_flush_page_write(CPUState *env, uint32_t addr)
{
}
#endif /* defined(CONFIG_USER_ONLY) */
static inline unsigned long *physpage_find_alloc(unsigned int page) static inline unsigned long *physpage_find_alloc(unsigned int page)
{ {
unsigned long **lp, *p; unsigned long **lp, *p;