?? exec.c
?? QEMU 0.91 source code, supports ARM processor including S3C24xx series
?? C
?? 第 1 頁 / 共 5 頁
字號:
??
} /* check end of list */ if (tb1 != tb) { printf("ERROR: jmp_list from 0x%08lx\n", (long)tb); }}#endif/* invalidate one TB */static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, int next_offset){ TranslationBlock *tb1; for(;;) { tb1 = *ptb; if (tb1 == tb) { *ptb = *(TranslationBlock **)((char *)tb1 + next_offset); break; } ptb = (TranslationBlock **)((char *)tb1 + next_offset); }}static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb){ TranslationBlock *tb1; unsigned int n1; for(;;) { tb1 = *ptb; n1 = (long)tb1 & 3; tb1 = (TranslationBlock *)((long)tb1 & ~3); if (tb1 == tb) { *ptb = tb1->page_next[n1]; break; } ptb = &tb1->page_next[n1]; }}static inline void tb_jmp_remove(TranslationBlock *tb, int n){ TranslationBlock *tb1, **ptb; unsigned int n1; ptb = &tb->jmp_next[n]; tb1 = *ptb; if (tb1) { /* find tb(n) in circular list */ for(;;) { tb1 = *ptb; n1 = (long)tb1 & 3; tb1 = (TranslationBlock *)((long)tb1 & ~3); if (n1 == n && tb1 == tb) break; if (n1 == 2) { ptb = &tb1->jmp_first; } else { ptb = &tb1->jmp_next[n1]; } } /* now we can suppress tb(n) from the list */ *ptb = tb->jmp_next[n]; tb->jmp_next[n] = NULL; }}/* reset the jump entry 'n' of a TB so that it is not chained to another TB */static inline void tb_reset_jump(TranslationBlock *tb, int n){ tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));}static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr){ CPUState *env; PageDesc *p; unsigned int h, n1; target_ulong phys_pc; TranslationBlock *tb1, *tb2; /* remove the TB from the hash list */ phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); h = tb_phys_hash_func(phys_pc); tb_remove(&tb_phys_hash[h], tb, offsetof(TranslationBlock, phys_hash_next)); /* remove the TB from the page list */ if (tb->page_addr[0] != page_addr) { p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); tb_page_remove(&p->first_tb, tb); invalidate_page_bitmap(p); } if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); tb_page_remove(&p->first_tb, tb); invalidate_page_bitmap(p); } tb_invalidated_flag = 1; /* remove the TB from the hash list */ h = tb_jmp_cache_hash_func(tb->pc); for(env = first_cpu; env != NULL; env = env->next_cpu) { if (env->tb_jmp_cache[h] == tb) env->tb_jmp_cache[h] = NULL; } /* suppress this TB from the two jump lists */ tb_jmp_remove(tb, 0); tb_jmp_remove(tb, 1); /* suppress any remaining jumps to this TB */ tb1 = tb->jmp_first; for(;;) { n1 = (long)tb1 & 3; if (n1 == 2) break; tb1 = (TranslationBlock *)((long)tb1 & ~3); tb2 = tb1->jmp_next[n1]; tb_reset_jump(tb1, n1); tb1->jmp_next[n1] = NULL; tb1 = tb2; } tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ tb_phys_invalidate_count++;}static inline void set_bits(uint8_t *tab, int start, int len){ int end, mask, end1; end = start + len; tab += start >> 3; mask = 0xff << (start & 7); if ((start & ~7) == (end & ~7)) { if (start < end) { mask &= ~(0xff << (end & 7)); *tab |= mask; } } else { *tab++ |= mask; start = (start + 8) & ~7; end1 = end & ~7; while (start < end1) { *tab++ = 0xff; start += 8; } if (start < end) { mask = ~(0xff << (end & 7)); *tab |= mask; } }}static void build_page_bitmap(PageDesc *p){ int n, tb_start, tb_end; TranslationBlock *tb; p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8); if (!p->code_bitmap) return; memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8); tb = p->first_tb; while (tb != NULL) { n = (long)tb & 3; tb = (TranslationBlock *)((long)tb & ~3); /* NOTE: this is subtle as a TB may span two physical pages */ if (n == 0) { /* NOTE: tb_end may be after the end of the page, but it is not a problem */ tb_start = tb->pc & ~TARGET_PAGE_MASK; tb_end = tb_start + tb->size; if (tb_end > TARGET_PAGE_SIZE) tb_end = TARGET_PAGE_SIZE; } else { tb_start = 0; tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); } set_bits(p->code_bitmap, tb_start, tb_end - tb_start); tb = tb->page_next[n]; }}#ifdef TARGET_HAS_PRECISE_SMCstatic void tb_gen_code(CPUState *env, target_ulong pc, target_ulong cs_base, int flags, int cflags){ TranslationBlock *tb; uint8_t *tc_ptr; target_ulong phys_pc, phys_page2, virt_page2; int code_gen_size; phys_pc = get_phys_addr_code(env, pc); tb = tb_alloc(pc); if (!tb) { /* flush must be done */ tb_flush(env); /* cannot fail at this point */ tb = tb_alloc(pc); } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; cpu_gen_code(env, tb, &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);}#endif/* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to the same physical page. 'is_cpu_write_access' should be true if called from a real cpu write access: the virtual CPU will exit the current TB if code is modified inside this TB. */void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, int is_cpu_write_access){ int n, current_tb_modified, current_tb_not_found, current_flags; CPUState *env = cpu_single_env; PageDesc *p; TranslationBlock *tb, *tb_next, *current_tb, *saved_tb; target_ulong tb_start, tb_end; target_ulong current_pc, current_cs_base; p = page_find(start >> TARGET_PAGE_BITS); if (!p) return; if (!p->code_bitmap && ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && is_cpu_write_access) { /* build code bitmap */ build_page_bitmap(p); } /* we remove all the TBs in the range [start, end[ */ /* XXX: see if in some cases it could be faster to invalidate all the code */ current_tb_not_found = is_cpu_write_access; current_tb_modified = 0; current_tb = NULL; /* avoid warning */ current_pc = 0; /* avoid warning */ current_cs_base = 0; /* avoid warning */ current_flags = 0; /* avoid warning */ tb = p->first_tb; while (tb != NULL) { n = (long)tb & 3; tb = (TranslationBlock *)((long)tb & ~3); tb_next = tb->page_next[n]; /* NOTE: this is subtle as a TB may span two physical pages */ if (n == 0) { /* NOTE: tb_end may be after the end of the page, but it is not a problem */ tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); tb_end = tb_start + tb->size; } else { tb_start = tb->page_addr[1]; tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); } if (!(tb_end <= start || tb_start >= end)) {#ifdef TARGET_HAS_PRECISE_SMC if (current_tb_not_found) { current_tb_not_found = 0; current_tb = NULL; if (env->mem_write_pc) { /* now we have a real cpu fault */ current_tb = tb_find_pc(env->mem_write_pc); } } if (current_tb == tb && !(current_tb->cflags & CF_SINGLE_INSN)) { /* If we are modifying the current TB, we must stop its execution. We could be more precise by checking that the modification is after the current PC, but it would require a specialized function to partially restore the CPU state */ current_tb_modified = 1; cpu_restore_state(current_tb, env, env->mem_write_pc, NULL);#if defined(TARGET_I386) current_flags = env->hflags; current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); current_cs_base = (target_ulong)env->segs[R_CS].base; current_pc = current_cs_base + env->eip;#else#error unsupported CPU#endif }#endif /* TARGET_HAS_PRECISE_SMC */ /* we need to do that to handle the case where a signal occurs while doing tb_phys_invalidate() */ saved_tb = NULL; if (env) { saved_tb = env->current_tb; env->current_tb = NULL; } tb_phys_invalidate(tb, -1); if (env) { env->current_tb = saved_tb; if (env->interrupt_request && env->current_tb) cpu_interrupt(env, env->interrupt_request); } } tb = tb_next; }#if !defined(CONFIG_USER_ONLY) /* if no code remaining, no need to continue to use slow writes */ if (!p->first_tb) { invalidate_page_bitmap(p); if (is_cpu_write_access) { tlb_unprotect_code_phys(env, start, env->mem_write_vaddr); } }#endif#ifdef TARGET_HAS_PRECISE_SMC if (current_tb_modified) { /* we generate a block containing just the instruction modifying the memory. It will ensure that it cannot modify itself */ env->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, CF_SINGLE_INSN); cpu_resume_from_signal(env, NULL); }#endif}/* len must be <= 8 and start must be a multiple of len */static inline void tb_invalidate_phys_page_fast(target_ulong start, int len){ PageDesc *p; int offset, b;#if 0 if (1) { if (loglevel) { fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", cpu_single_env->mem_write_vaddr, len, cpu_single_env->eip, cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); } }#endif p = page_find(start >> TARGET_PAGE_BITS); if (!p) return; if (p->code_bitmap) { offset = start & ~TARGET_PAGE_MASK; b = p->code_bitmap[offset >> 3] >> (offset & 7); if (b & ((1 << len) - 1)) goto do_invalidate; } else { do_invalidate: tb_invalidate_phys_page_range(start, start + len, 1); }}#if !defined(CONFIG_SOFTMMU)static void tb_invalidate_phys_page(target_ulong addr, unsigned long pc, void *puc){ int n, current_flags, current_tb_modified; target_ulong current_pc, current_cs_base; PageDesc *p; TranslationBlock *tb, *current_tb;#ifdef TARGET_HAS_PRECISE_SMC CPUState *env = cpu_single_env;#endif addr &= TARGET_PAGE_MASK; p = page_find(addr >> TARGET_PAGE_BITS); if (!p) return; tb = p->first_tb; current_tb_modified = 0; current_tb = NULL; current_pc = 0; /* avoid warning */ current_cs_base = 0; /* avoid warning */ current_flags = 0; /* avoid warning */#ifdef TARGET_HAS_PRECISE_SMC if (tb && pc != 0) { current_tb = tb_find_pc(pc); }#endif while (tb != NULL) { n = (long)tb & 3; tb = (TranslationBlock *)((long)tb & ~3);#ifdef TARGET_HAS_PRECISE_SMC if (current_tb == tb && !(current_tb->cflags & CF_SINGLE_INSN)) { /* If we are modifying the current TB, we must stop its execution. We could be more precise by checking that the modification is after the current PC, but it would require a specialized function to partially restore the CPU state */ current_tb_modified = 1; cpu_restore_state(current_tb, env, pc, puc);#if defined(TARGET_I386) current_flags = env->hflags; current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); current_cs_base = (target_ulong)env->segs[R_CS].base; current_pc = current_cs_base + env->eip;#else#error unsupported CPU#endif }#endif /* TARGET_HAS_PRECISE_SMC */ tb_phys_invalidate(tb, addr); tb = tb->page_next[n]; } p->first_tb = NULL;#ifdef TARGET_HAS_PRECISE_SMC if (current_tb_modified) { /* we generate a block containing just the instruction modifying the memory. It will ensure that it cannot modify
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -