| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * internal execution defines for qemu | 
 | 3 |  * | 
 | 4 |  *  Copyright (c) 2003 Fabrice Bellard | 
 | 5 |  * | 
 | 6 |  * This library is free software; you can redistribute it and/or | 
 | 7 |  * modify it under the terms of the GNU Lesser General Public | 
 | 8 |  * License as published by the Free Software Foundation; either | 
 | 9 |  * version 2 of the License, or (at your option) any later version. | 
 | 10 |  * | 
 | 11 |  * This library is distributed in the hope that it will be useful, | 
 | 12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 14 |  * Lesser General Public License for more details. | 
 | 15 |  * | 
 | 16 |  * You should have received a copy of the GNU Lesser General Public | 
| David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 17 |  * License along with this library; if not, see <http://www.gnu.org/licenses/>. | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 18 |  */ | 
 | 19 |  | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 20 | #ifndef _EXEC_ALL_H_ | 
 | 21 | #define _EXEC_ALL_H_ | 
 | 22 |  | 
 | 23 | #include "qemu-common.h" | 
 | 24 |  | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 25 | /* allow to see translation results - the slowdown should be negligible, so we leave it */ | 
 | 26 | #define DEBUG_DISAS | 
 | 27 |  | 
| David 'Digit' Turner | 280afa0 | 2011-05-11 17:37:44 +0200 | [diff] [blame] | 28 | /* Page tracking code uses ram addresses in system mode, and virtual | 
 | 29 |    addresses in userspace mode.  Define tb_page_addr_t to be an appropriate | 
 | 30 |    type.  */ | 
 | 31 | #if defined(CONFIG_USER_ONLY) | 
 | 32 | typedef abi_ulong tb_page_addr_t; | 
 | 33 | #else | 
 | 34 | typedef ram_addr_t tb_page_addr_t; | 
 | 35 | #endif | 
 | 36 |  | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 37 | /* is_jmp field values */ | 
 | 38 | #define DISAS_NEXT    0 /* next instruction can be analyzed */ | 
 | 39 | #define DISAS_JUMP    1 /* only pc was modified dynamically */ | 
 | 40 | #define DISAS_UPDATE  2 /* cpu state was modified dynamically */ | 
 | 41 | #define DISAS_TB_JUMP 3 /* only pc was modified statically */ | 
 | 42 |  | 
 | 43 | typedef struct TranslationBlock TranslationBlock; | 
 | 44 |  | 
 | 45 | /* XXX: make safe guess about sizes */ | 
| David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 46 | #define MAX_OP_PER_INSTR 96 | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 47 | /* A Call op needs up to 6 + 2N parameters (N = number of arguments).  */ | 
 | 48 | #define MAX_OPC_PARAM 10 | 
| David 'Digit' Turner | bcc6ae1 | 2009-10-06 11:18:29 -0700 | [diff] [blame] | 49 | #define OPC_BUF_SIZE 2048 | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 50 | #define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) | 
 | 51 |  | 
 | 52 | /* Maximum size a TCG op can expand to.  This is complicated because a | 
| David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 53 |    single op may require several host instructions and register reloads. | 
 | 54 |    For now take a wild guess at 192 bytes, which should allow at least | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 55 |    a couple of fixup instructions per argument.  */ | 
| David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 56 | #define TCG_MAX_OP_SIZE 192 | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 57 |  | 
 | 58 | #define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) | 
 | 59 |  | 
 | 60 | extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; | 
 | 61 | extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; | 
 | 62 | extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; | 
 | 63 | extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; | 
 | 64 | extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; | 
 | 65 | extern target_ulong gen_opc_jump_pc[2]; | 
 | 66 | extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; | 
 | 67 |  | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 68 | #include "qemu-log.h" | 
 | 69 |  | 
 | 70 | void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); | 
 | 71 | void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); | 
| David 'Digit' Turner | d3d4468 | 2011-05-10 17:49:00 +0200 | [diff] [blame] | 72 | void restore_state_to_opc(CPUState *env, struct TranslationBlock *tb, int pc_pos); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 73 |  | 
 | 74 | unsigned long code_gen_max_block_size(void); | 
 | 75 | void cpu_gen_init(void); | 
 | 76 | int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, | 
 | 77 |                  int *gen_code_size_ptr); | 
 | 78 | int cpu_restore_state(struct TranslationBlock *tb, | 
| David 'Digit' Turner | f645f7d | 2011-05-11 00:44:05 +0200 | [diff] [blame] | 79 |                       CPUState *env, unsigned long searched_pc); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 80 | void cpu_resume_from_signal(CPUState *env1, void *puc); | 
 | 81 | void cpu_io_recompile(CPUState *env, void *retaddr); | 
| Vladimir Chtchetkine | 5389aa1 | 2010-02-16 10:38:35 -0800 | [diff] [blame] | 82 | TranslationBlock *tb_gen_code(CPUState *env, | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 83 |                               target_ulong pc, target_ulong cs_base, int flags, | 
 | 84 |                               int cflags); | 
 | 85 | void cpu_exec_init(CPUState *env); | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 86 | void QEMU_NORETURN cpu_loop_exit(void); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 87 | int page_unprotect(target_ulong address, unsigned long pc, void *puc); | 
 | 88 | void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, | 
 | 89 |                                    int is_cpu_write_access); | 
 | 90 | void tb_invalidate_page_range(target_ulong start, target_ulong end); | 
 | 91 | void tlb_flush_page(CPUState *env, target_ulong addr); | 
 | 92 | void tlb_flush(CPUState *env, int flush_global); | 
 | 93 | int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | 
 | 94 |                       target_phys_addr_t paddr, int prot, | 
 | 95 |                       int mmu_idx, int is_softmmu); | 
 | 96 | static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, | 
 | 97 |                                target_phys_addr_t paddr, int prot, | 
 | 98 |                                int mmu_idx, int is_softmmu) | 
 | 99 | { | 
 | 100 |     if (prot & PAGE_READ) | 
 | 101 |         prot |= PAGE_EXEC; | 
 | 102 |     return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu); | 
 | 103 | } | 
 | 104 |  | 
 | 105 | #define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */ | 
 | 106 |  | 
 | 107 | #define CODE_GEN_PHYS_HASH_BITS     15 | 
 | 108 | #define CODE_GEN_PHYS_HASH_SIZE     (1 << CODE_GEN_PHYS_HASH_BITS) | 
 | 109 |  | 
 | 110 | #define MIN_CODE_GEN_BUFFER_SIZE     (1024 * 1024) | 
 | 111 |  | 
 | 112 | /* estimated block size for TB allocation */ | 
 | 113 | /* XXX: use a per code average code fragment size and modulate it | 
 | 114 |    according to the host CPU */ | 
 | 115 | #if defined(CONFIG_SOFTMMU) | 
 | 116 | #define CODE_GEN_AVG_BLOCK_SIZE 128 | 
 | 117 | #else | 
 | 118 | #define CODE_GEN_AVG_BLOCK_SIZE 64 | 
 | 119 | #endif | 
 | 120 |  | 
| David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 121 | #if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 122 | #define USE_DIRECT_JUMP | 
 | 123 | #endif | 
 | 124 |  | 
 | 125 | struct TranslationBlock { | 
 | 126 |     target_ulong pc;   /* simulated PC corresponding to this block (EIP + CS base) */ | 
 | 127 |     target_ulong cs_base; /* CS base for this block */ | 
 | 128 |     uint64_t flags; /* flags defining in which context the code was generated */ | 
 | 129 |     uint16_t size;      /* size of target code for this block (1 <= | 
 | 130 |                            size <= TARGET_PAGE_SIZE) */ | 
 | 131 |     uint16_t cflags;    /* compile flags */ | 
 | 132 | #define CF_COUNT_MASK  0x7fff | 
 | 133 | #define CF_LAST_IO     0x8000 /* Last insn may be an IO access.  */ | 
 | 134 |  | 
 | 135 |     uint8_t *tc_ptr;    /* pointer to the translated code */ | 
 | 136 |     /* next matching tb for physical address. */ | 
 | 137 |     struct TranslationBlock *phys_hash_next; | 
 | 138 |     /* first and second physical page containing code. The lower bit | 
 | 139 |        of the pointer tells the index in page_next[] */ | 
 | 140 |     struct TranslationBlock *page_next[2]; | 
 | 141 |     target_ulong page_addr[2]; | 
 | 142 |  | 
 | 143 |     /* the following data are used to directly call another TB from | 
 | 144 |        the code of this one. */ | 
 | 145 |     uint16_t tb_next_offset[2]; /* offset of original jump target */ | 
 | 146 | #ifdef USE_DIRECT_JUMP | 
 | 147 |     uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ | 
 | 148 | #else | 
 | 149 |     unsigned long tb_next[2]; /* address of jump generated code */ | 
 | 150 | #endif | 
 | 151 |     /* list of TBs jumping to this one. This is a circular list using | 
 | 152 |        the two least significant bits of the pointers to tell what is | 
 | 153 |        the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = | 
 | 154 |        jmp_first */ | 
 | 155 |     struct TranslationBlock *jmp_next[2]; | 
 | 156 |     struct TranslationBlock *jmp_first; | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 157 | #ifdef CONFIG_TRACE | 
 | 158 |     struct BBRec *bb_rec; | 
 | 159 |     uint64_t prev_time; | 
 | 160 | #endif | 
| Vladimir Chtchetkine | 5389aa1 | 2010-02-16 10:38:35 -0800 | [diff] [blame] | 161 |  | 
 | 162 | #ifdef CONFIG_MEMCHECK | 
 | 163 |     /* Maps PCs in this translation block to corresponding PCs in guest address | 
 | 164 |      * space. The array is arranged in such way, that every even entry contains | 
 | 165 |      * PC in the translation block, followed by an odd entry that contains | 
 | 166 |      * guest PC corresponding to that PC in the translation block. This | 
 | 167 |      * arrangement is set by tcg_gen_code_common that initializes this array | 
 | 168 |      * when performing guest code translation. */ | 
 | 169 |     target_ulong*   tpc2gpc; | 
 | 170 |     /* Number of pairs (pc_tb, pc_guest) in tpc2gpc array. */ | 
 | 171 |     unsigned int    tpc2gpc_pairs; | 
 | 172 | #endif  // CONFIG_MEMCHECK | 
 | 173 |  | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 174 |     uint32_t icount; | 
 | 175 | }; | 
 | 176 |  | 
 | 177 | static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) | 
 | 178 | { | 
 | 179 |     target_ulong tmp; | 
 | 180 |     tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); | 
 | 181 |     return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK; | 
 | 182 | } | 
 | 183 |  | 
 | 184 | static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) | 
 | 185 | { | 
 | 186 |     target_ulong tmp; | 
 | 187 |     tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); | 
 | 188 |     return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK) | 
 | 189 | 	    | (tmp & TB_JMP_ADDR_MASK)); | 
 | 190 | } | 
 | 191 |  | 
 | 192 | static inline unsigned int tb_phys_hash_func(unsigned long pc) | 
 | 193 | { | 
| David 'Digit' Turner | 280afa0 | 2011-05-11 17:37:44 +0200 | [diff] [blame] | 194 |     return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 195 | } | 
 | 196 |  | 
| Vladimir Chtchetkine | 5389aa1 | 2010-02-16 10:38:35 -0800 | [diff] [blame] | 197 | #ifdef CONFIG_MEMCHECK | 
 | 198 | /* Gets translated PC for a given (translated PC, guest PC) pair. | 
 | 199 |  * Return: | 
 | 200 |  *  Translated PC, or NULL if pair index was too large. | 
 | 201 |  */ | 
 | 202 | static inline target_ulong | 
 | 203 | tb_get_tb_pc(const TranslationBlock* tb, unsigned int pair) | 
 | 204 | { | 
 | 205 |     return (tb->tpc2gpc != NULL && pair < tb->tpc2gpc_pairs) ? | 
 | 206 |                                                     tb->tpc2gpc[pair * 2] : 0; | 
 | 207 | } | 
 | 208 |  | 
 | 209 | /* Gets guest PC for a given (translated PC, guest PC) pair. | 
 | 210 |  * Return: | 
 | 211 |  *  Guest PC, or NULL if pair index was too large. | 
 | 212 |  */ | 
 | 213 | static inline target_ulong | 
 | 214 | tb_get_guest_pc(const TranslationBlock* tb, unsigned int pair) | 
 | 215 | { | 
 | 216 |     return (tb->tpc2gpc != NULL && pair < tb->tpc2gpc_pairs) ? | 
 | 217 |             tb->tpc2gpc[pair * 2 + 1] : 0; | 
 | 218 | } | 
 | 219 |  | 
 | 220 | /* Gets guest PC for a given translated PC. | 
 | 221 |  * Return: | 
 | 222 |  *  Guest PC for a given translated PC, or NULL if there was no pair, matching | 
 | 223 |  *  translated PC in tb's tpc2gpc array. | 
 | 224 |  */ | 
 | 225 | static inline target_ulong | 
 | 226 | tb_search_guest_pc_from_tb_pc(const TranslationBlock* tb, target_ulong tb_pc) | 
 | 227 | { | 
 | 228 |     if (tb->tpc2gpc != NULL && tb->tpc2gpc_pairs != 0) { | 
 | 229 |         unsigned int m_min = 0; | 
 | 230 |         unsigned int m_max = (tb->tpc2gpc_pairs - 1) << 1; | 
 | 231 |         /* Make sure that tb_pc is within TB array. */ | 
 | 232 |         if (tb_pc < tb->tpc2gpc[0]) { | 
 | 233 |             return 0; | 
 | 234 |         } | 
 | 235 |         while (m_min <= m_max) { | 
 | 236 |             const unsigned int m = ((m_min + m_max) >> 1) & ~1; | 
 | 237 |             if (tb_pc < tb->tpc2gpc[m]) { | 
 | 238 |                 m_max = m - 2; | 
 | 239 |             } else if (m == m_max || tb_pc < tb->tpc2gpc[m + 2]) { | 
 | 240 |                 return tb->tpc2gpc[m + 1]; | 
 | 241 |             } else { | 
 | 242 |                 m_min = m + 2; | 
 | 243 |             } | 
 | 244 |         } | 
 | 245 |         return tb->tpc2gpc[m_max + 1]; | 
 | 246 |     } | 
 | 247 |     return 0; | 
 | 248 | } | 
 | 249 | #endif  // CONFIG_MEMCHECK | 
 | 250 |  | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 251 | TranslationBlock *tb_alloc(target_ulong pc); | 
 | 252 | void tb_free(TranslationBlock *tb); | 
 | 253 | void tb_flush(CPUState *env); | 
 | 254 | void tb_link_phys(TranslationBlock *tb, | 
 | 255 |                   target_ulong phys_pc, target_ulong phys_page2); | 
 | 256 | void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr); | 
 | 257 |  | 
 | 258 | extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | 
 | 259 | extern uint8_t *code_gen_ptr; | 
 | 260 | extern int code_gen_max_blocks; | 
 | 261 |  | 
 | 262 | #if defined(USE_DIRECT_JUMP) | 
 | 263 |  | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 264 | #if defined(_ARCH_PPC) | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 265 | extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); | 
 | 266 | #define tb_set_jmp_target1 ppc_tb_set_jmp_target | 
 | 267 | #elif defined(__i386__) || defined(__x86_64__) | 
 | 268 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) | 
 | 269 | { | 
 | 270 |     /* patch the branch destination */ | 
 | 271 |     *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); | 
 | 272 |     /* no need to flush icache explicitly */ | 
 | 273 | } | 
 | 274 | #elif defined(__arm__) | 
 | 275 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) | 
 | 276 | { | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 277 | #if QEMU_GNUC_PREREQ(4, 1) | 
 | 278 |     void __clear_cache(char *beg, char *end); | 
 | 279 | #else | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 280 |     register unsigned long _beg __asm ("a1"); | 
 | 281 |     register unsigned long _end __asm ("a2"); | 
 | 282 |     register unsigned long _flg __asm ("a3"); | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 283 | #endif | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 284 |  | 
 | 285 |     /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ | 
| David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 286 |     *(uint32_t *)jmp_addr = | 
 | 287 |         (*(uint32_t *)jmp_addr & ~0xffffff) | 
 | 288 |         | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 289 |  | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 290 | #if QEMU_GNUC_PREREQ(4, 1) | 
 | 291 |     __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); | 
 | 292 | #else | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 293 |     /* flush icache */ | 
 | 294 |     _beg = jmp_addr; | 
 | 295 |     _end = jmp_addr + 4; | 
 | 296 |     _flg = 0; | 
 | 297 |     __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 298 | #endif | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 299 | } | 
 | 300 | #endif | 
 | 301 |  | 
 | 302 | static inline void tb_set_jmp_target(TranslationBlock *tb, | 
 | 303 |                                      int n, unsigned long addr) | 
 | 304 | { | 
 | 305 |     unsigned long offset; | 
 | 306 |  | 
 | 307 |     offset = tb->tb_jmp_offset[n]; | 
 | 308 |     tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); | 
 | 309 |     offset = tb->tb_jmp_offset[n + 2]; | 
 | 310 |     if (offset != 0xffff) | 
 | 311 |         tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); | 
 | 312 | } | 
 | 313 |  | 
 | 314 | #else | 
 | 315 |  | 
 | 316 | /* set the jump target */ | 
 | 317 | static inline void tb_set_jmp_target(TranslationBlock *tb, | 
 | 318 |                                      int n, unsigned long addr) | 
 | 319 | { | 
 | 320 |     tb->tb_next[n] = addr; | 
 | 321 | } | 
 | 322 |  | 
 | 323 | #endif | 
 | 324 |  | 
 | 325 | static inline void tb_add_jump(TranslationBlock *tb, int n, | 
 | 326 |                                TranslationBlock *tb_next) | 
 | 327 | { | 
 | 328 |     /* NOTE: this test is only needed for thread safety */ | 
 | 329 |     if (!tb->jmp_next[n]) { | 
 | 330 |         /* patch the native jump address */ | 
 | 331 |         tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); | 
 | 332 |  | 
 | 333 |         /* add in TB jmp circular list */ | 
 | 334 |         tb->jmp_next[n] = tb_next->jmp_first; | 
 | 335 |         tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); | 
 | 336 |     } | 
 | 337 | } | 
 | 338 |  | 
 | 339 | TranslationBlock *tb_find_pc(unsigned long pc_ptr); | 
 | 340 |  | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 341 | extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | 
 | 342 | extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | 
 | 343 | extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; | 
 | 344 |  | 
 | 345 | #include "qemu-lock.h" | 
 | 346 |  | 
 | 347 | extern spinlock_t tb_lock; | 
 | 348 |  | 
 | 349 | extern int tb_invalidated_flag; | 
 | 350 |  | 
 | 351 | #if !defined(CONFIG_USER_ONLY) | 
 | 352 |  | 
 | 353 | void tlb_fill(target_ulong addr, int is_write, int mmu_idx, | 
 | 354 |               void *retaddr); | 
 | 355 |  | 
 | 356 | #include "softmmu_defs.h" | 
 | 357 |  | 
 | 358 | #define ACCESS_TYPE (NB_MMU_MODES + 1) | 
 | 359 | #define MEMSUFFIX _code | 
 | 360 | #define env cpu_single_env | 
 | 361 |  | 
 | 362 | #define DATA_SIZE 1 | 
 | 363 | #include "softmmu_header.h" | 
 | 364 |  | 
 | 365 | #define DATA_SIZE 2 | 
 | 366 | #include "softmmu_header.h" | 
 | 367 |  | 
 | 368 | #define DATA_SIZE 4 | 
 | 369 | #include "softmmu_header.h" | 
 | 370 |  | 
 | 371 | #define DATA_SIZE 8 | 
 | 372 | #include "softmmu_header.h" | 
 | 373 |  | 
 | 374 | #undef ACCESS_TYPE | 
 | 375 | #undef MEMSUFFIX | 
 | 376 | #undef env | 
 | 377 |  | 
 | 378 | #endif | 
 | 379 |  | 
 | 380 | #if defined(CONFIG_USER_ONLY) | 
 | 381 | static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) | 
 | 382 | { | 
 | 383 |     return addr; | 
 | 384 | } | 
 | 385 | #else | 
 | 386 | /* NOTE: this function can trigger an exception */ | 
 | 387 | /* NOTE2: the returned address is not exactly the physical address: it | 
 | 388 |    is the offset relative to phys_ram_base */ | 
 | 389 | static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) | 
 | 390 | { | 
 | 391 |     int mmu_idx, page_index, pd; | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 392 |     void *p; | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 393 |  | 
 | 394 |     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | 
 | 395 |     mmu_idx = cpu_mmu_index(env1); | 
 | 396 |     if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != | 
 | 397 |                  (addr & TARGET_PAGE_MASK))) { | 
 | 398 |         ldub_code(addr); | 
 | 399 |     } | 
 | 400 |     pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK; | 
 | 401 |     if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { | 
 | 402 | #if defined(TARGET_SPARC) || defined(TARGET_MIPS) | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 403 |         do_unassigned_access(addr, 0, 1, 0, 4); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 404 | #else | 
 | 405 |         cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); | 
 | 406 | #endif | 
 | 407 |     } | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 408 |     p = (void *)(unsigned long)addr | 
 | 409 |         + env1->tlb_table[mmu_idx][page_index].addend; | 
| David 'Digit' Turner | 280afa0 | 2011-05-11 17:37:44 +0200 | [diff] [blame] | 410 |     return qemu_ram_addr_from_host_nofail(p); | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 411 | } | 
| The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 412 | #endif | 
| David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 413 |  | 
 | 414 | typedef void (CPUDebugExcpHandler)(CPUState *env); | 
 | 415 |  | 
 | 416 | CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler); | 
 | 417 |  | 
 | 418 | /* vl.c */ | 
 | 419 | extern int singlestep; | 
 | 420 |  | 
 | 421 | #endif |