Commit 0124311e00452fa1555968dfe794dc8feed1a67c
1 parent
f5155289
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
Showing
2 changed files
with
52 additions
and
20 deletions
exec-all.h
| @@ -77,7 +77,7 @@ int cpu_restore_state(struct TranslationBlock *tb, | @@ -77,7 +77,7 @@ int cpu_restore_state(struct TranslationBlock *tb, | ||
| 77 | CPUState *env, unsigned long searched_pc); | 77 | CPUState *env, unsigned long searched_pc); |
| 78 | void cpu_exec_init(void); | 78 | void cpu_exec_init(void); |
| 79 | int page_unprotect(unsigned long address); | 79 | int page_unprotect(unsigned long address); |
| 80 | -void page_unmap(void); | 80 | +void tb_invalidate_page(unsigned long address); |
| 81 | void tlb_flush_page(CPUState *env, uint32_t addr); | 81 | void tlb_flush_page(CPUState *env, uint32_t addr); |
| 82 | void tlb_flush_page_write(CPUState *env, uint32_t addr); | 82 | void tlb_flush_page_write(CPUState *env, uint32_t addr); |
| 83 | void tlb_flush(CPUState *env); | 83 | void tlb_flush(CPUState *env); |
| @@ -127,7 +127,7 @@ static inline unsigned int tb_hash_func(unsigned long pc) | @@ -127,7 +127,7 @@ static inline unsigned int tb_hash_func(unsigned long pc) | ||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | TranslationBlock *tb_alloc(unsigned long pc); | 129 | TranslationBlock *tb_alloc(unsigned long pc); |
| 130 | -void tb_flush(void); | 130 | +void tb_flush(CPUState *env); |
| 131 | void tb_link(TranslationBlock *tb); | 131 | void tb_link(TranslationBlock *tb); |
| 132 | 132 | ||
| 133 | extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; | 133 | extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; |
exec.c
| @@ -62,7 +62,6 @@ typedef struct PageDesc { | @@ -62,7 +62,6 @@ typedef struct PageDesc { | ||
| 62 | #define L1_SIZE (1 << L1_BITS) | 62 | #define L1_SIZE (1 << L1_BITS) |
| 63 | #define L2_SIZE (1 << L2_BITS) | 63 | #define L2_SIZE (1 << L2_BITS) |
| 64 | 64 | ||
| 65 | -static void tb_invalidate_page(unsigned long address); | ||
| 66 | static void io_mem_init(void); | 65 | static void io_mem_init(void); |
| 67 | 66 | ||
| 68 | unsigned long real_host_page_size; | 67 | unsigned long real_host_page_size; |
| @@ -229,15 +228,19 @@ static void page_flush_tb(void) | @@ -229,15 +228,19 @@ static void page_flush_tb(void) | ||
| 229 | 228 | ||
| 230 | /* flush all the translation blocks */ | 229 | /* flush all the translation blocks */ |
| 231 | /* XXX: tb_flush is currently not thread safe */ | 230 | /* XXX: tb_flush is currently not thread safe */ |
| 232 | -void tb_flush(void) | 231 | +void tb_flush(CPUState *env) |
| 233 | { | 232 | { |
| 234 | int i; | 233 | int i; |
| 235 | -#ifdef DEBUG_FLUSH | 234 | +#if defined(DEBUG_FLUSH) |
| 236 | printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", | 235 | printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", |
| 237 | code_gen_ptr - code_gen_buffer, | 236 | code_gen_ptr - code_gen_buffer, |
| 238 | nb_tbs, | 237 | nb_tbs, |
| 239 | - (code_gen_ptr - code_gen_buffer) / nb_tbs); | 238 | + nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); |
| 240 | #endif | 239 | #endif |
| 240 | + /* must reset current TB so that interrupts cannot modify the | ||
| 241 | + links while we are modifying them */ | ||
| 242 | + env->current_tb = NULL; | ||
| 243 | + | ||
| 241 | nb_tbs = 0; | 244 | nb_tbs = 0; |
| 242 | for(i = 0;i < CODE_GEN_HASH_SIZE; i++) | 245 | for(i = 0;i < CODE_GEN_HASH_SIZE; i++) |
| 243 | tb_hash[i] = NULL; | 246 | tb_hash[i] = NULL; |
| @@ -402,7 +405,7 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity) | @@ -402,7 +405,7 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity) | ||
| 402 | } | 405 | } |
| 403 | 406 | ||
| 404 | /* invalidate all TBs which intersect with the target page starting at addr */ | 407 | /* invalidate all TBs which intersect with the target page starting at addr */ |
| 405 | -static void tb_invalidate_page(unsigned long address) | 408 | +void tb_invalidate_page(unsigned long address) |
| 406 | { | 409 | { |
| 407 | TranslationBlock *tb_next, *tb; | 410 | TranslationBlock *tb_next, *tb; |
| 408 | unsigned int page_index; | 411 | unsigned int page_index; |
| @@ -626,7 +629,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) | @@ -626,7 +629,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) | ||
| 626 | /* suppress the jump to next tb in generated code */ | 629 | /* suppress the jump to next tb in generated code */ |
| 627 | tb_reset_jump(tb, n); | 630 | tb_reset_jump(tb, n); |
| 628 | 631 | ||
| 629 | - /* suppress jumps in the tb on which we could have jump */ | 632 | + /* suppress jumps in the tb on which we could have jumped */ |
| 630 | tb_reset_jump_recursive(tb_next); | 633 | tb_reset_jump_recursive(tb_next); |
| 631 | } | 634 | } |
| 632 | } | 635 | } |
| @@ -688,7 +691,7 @@ void cpu_single_step(CPUState *env, int enabled) | @@ -688,7 +691,7 @@ void cpu_single_step(CPUState *env, int enabled) | ||
| 688 | if (env->singlestep_enabled != enabled) { | 691 | if (env->singlestep_enabled != enabled) { |
| 689 | env->singlestep_enabled = enabled; | 692 | env->singlestep_enabled = enabled; |
| 690 | /* must flush all the translated code to avoid inconsistancies */ | 693 | /* must flush all the translated code to avoid inconsistancies */ |
| 691 | - tb_flush(); | 694 | + tb_flush(env); |
| 692 | } | 695 | } |
| 693 | #endif | 696 | #endif |
| 694 | } | 697 | } |
| @@ -712,7 +715,7 @@ void cpu_set_log_filename(const char *filename) | @@ -712,7 +715,7 @@ void cpu_set_log_filename(const char *filename) | ||
| 712 | logfilename = strdup(filename); | 715 | logfilename = strdup(filename); |
| 713 | } | 716 | } |
| 714 | 717 | ||
| 715 | -/* mask must never be zero */ | 718 | +/* mask must never be zero, except for A20 change call */ |
| 716 | void cpu_interrupt(CPUState *env, int mask) | 719 | void cpu_interrupt(CPUState *env, int mask) |
| 717 | { | 720 | { |
| 718 | TranslationBlock *tb; | 721 | TranslationBlock *tb; |
| @@ -742,9 +745,10 @@ void cpu_abort(CPUState *env, const char *fmt, ...) | @@ -742,9 +745,10 @@ void cpu_abort(CPUState *env, const char *fmt, ...) | ||
| 742 | abort(); | 745 | abort(); |
| 743 | } | 746 | } |
| 744 | 747 | ||
| 745 | -#ifdef TARGET_I386 | 748 | +#if !defined(CONFIG_USER_ONLY) |
| 749 | + | ||
| 746 | /* unmap all maped pages and flush all associated code */ | 750 | /* unmap all maped pages and flush all associated code */ |
| 747 | -void page_unmap(void) | 751 | +static void page_unmap(CPUState *env) |
| 748 | { | 752 | { |
| 749 | PageDesc *pmap; | 753 | PageDesc *pmap; |
| 750 | int i; | 754 | int i; |
| @@ -784,21 +788,25 @@ void page_unmap(void) | @@ -784,21 +788,25 @@ void page_unmap(void) | ||
| 784 | l1_map[i] = NULL; | 788 | l1_map[i] = NULL; |
| 785 | } | 789 | } |
| 786 | } | 790 | } |
| 787 | - tb_flush(); | 791 | + tb_flush(env); |
| 788 | } | 792 | } |
| 789 | -#endif | ||
| 790 | 793 | ||
| 791 | void tlb_flush(CPUState *env) | 794 | void tlb_flush(CPUState *env) |
| 792 | { | 795 | { |
| 793 | -#if !defined(CONFIG_USER_ONLY) | ||
| 794 | int i; | 796 | int i; |
| 797 | + | ||
| 798 | + /* must reset current TB so that interrupts cannot modify the | ||
| 799 | + links while we are modifying them */ | ||
| 800 | + env->current_tb = NULL; | ||
| 801 | + | ||
| 795 | for(i = 0; i < CPU_TLB_SIZE; i++) { | 802 | for(i = 0; i < CPU_TLB_SIZE; i++) { |
| 796 | env->tlb_read[0][i].address = -1; | 803 | env->tlb_read[0][i].address = -1; |
| 797 | env->tlb_write[0][i].address = -1; | 804 | env->tlb_write[0][i].address = -1; |
| 798 | env->tlb_read[1][i].address = -1; | 805 | env->tlb_read[1][i].address = -1; |
| 799 | env->tlb_write[1][i].address = -1; | 806 | env->tlb_write[1][i].address = -1; |
| 800 | } | 807 | } |
| 801 | -#endif | 808 | + /* XXX: avoid flushing the TBs */ |
| 809 | + page_unmap(env); | ||
| 802 | } | 810 | } |
| 803 | 811 | ||
| 804 | static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) | 812 | 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) | @@ -810,8 +818,11 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) | ||
| 810 | 818 | ||
| 811 | void tlb_flush_page(CPUState *env, uint32_t addr) | 819 | void tlb_flush_page(CPUState *env, uint32_t addr) |
| 812 | { | 820 | { |
| 813 | -#if !defined(CONFIG_USER_ONLY) | ||
| 814 | - int i; | 821 | + int i, flags; |
| 822 | + | ||
| 823 | + /* must reset current TB so that interrupts cannot modify the | ||
| 824 | + links while we are modifying them */ | ||
| 825 | + env->current_tb = NULL; | ||
| 815 | 826 | ||
| 816 | addr &= TARGET_PAGE_MASK; | 827 | addr &= TARGET_PAGE_MASK; |
| 817 | i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | 828 | i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| @@ -819,23 +830,44 @@ void tlb_flush_page(CPUState *env, uint32_t addr) | @@ -819,23 +830,44 @@ void tlb_flush_page(CPUState *env, uint32_t addr) | ||
| 819 | tlb_flush_entry(&env->tlb_write[0][i], addr); | 830 | tlb_flush_entry(&env->tlb_write[0][i], addr); |
| 820 | tlb_flush_entry(&env->tlb_read[1][i], addr); | 831 | tlb_flush_entry(&env->tlb_read[1][i], addr); |
| 821 | tlb_flush_entry(&env->tlb_write[1][i], addr); | 832 | tlb_flush_entry(&env->tlb_write[1][i], addr); |
| 833 | + | ||
| 834 | + flags = page_get_flags(addr); | ||
| 835 | + if (flags & PAGE_VALID) { | ||
| 836 | +#if !defined(CONFIG_SOFTMMU) | ||
| 837 | + munmap((void *)addr, TARGET_PAGE_SIZE); | ||
| 822 | #endif | 838 | #endif |
| 839 | + page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0); | ||
| 840 | + } | ||
| 823 | } | 841 | } |
| 824 | 842 | ||
| 825 | /* make all write to page 'addr' trigger a TLB exception to detect | 843 | /* make all write to page 'addr' trigger a TLB exception to detect |
| 826 | self modifying code */ | 844 | self modifying code */ |
| 827 | void tlb_flush_page_write(CPUState *env, uint32_t addr) | 845 | void tlb_flush_page_write(CPUState *env, uint32_t addr) |
| 828 | { | 846 | { |
| 829 | -#if !defined(CONFIG_USER_ONLY) | ||
| 830 | int i; | 847 | int i; |
| 831 | 848 | ||
| 832 | addr &= TARGET_PAGE_MASK; | 849 | addr &= TARGET_PAGE_MASK; |
| 833 | i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | 850 | i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| 834 | tlb_flush_entry(&env->tlb_write[0][i], addr); | 851 | tlb_flush_entry(&env->tlb_write[0][i], addr); |
| 835 | tlb_flush_entry(&env->tlb_write[1][i], addr); | 852 | tlb_flush_entry(&env->tlb_write[1][i], addr); |
| 836 | -#endif | ||
| 837 | } | 853 | } |
| 838 | 854 | ||
| 855 | +#else | ||
| 856 | + | ||
| 857 | +void tlb_flush(CPUState *env) | ||
| 858 | +{ | ||
| 859 | +} | ||
| 860 | + | ||
| 861 | +void tlb_flush_page(CPUState *env, uint32_t addr) | ||
| 862 | +{ | ||
| 863 | +} | ||
| 864 | + | ||
| 865 | +void tlb_flush_page_write(CPUState *env, uint32_t addr) | ||
| 866 | +{ | ||
| 867 | +} | ||
| 868 | + | ||
| 869 | +#endif /* defined(CONFIG_USER_ONLY) */ | ||
| 870 | + | ||
| 839 | static inline unsigned long *physpage_find_alloc(unsigned int page) | 871 | static inline unsigned long *physpage_find_alloc(unsigned int page) |
| 840 | { | 872 | { |
| 841 | unsigned long **lp, *p; | 873 | unsigned long **lp, *p; |