Home | History | Annotate | Download | only in qemu
      1 /*
      2  *  Host code generation
      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
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  */
     19 #include <stdarg.h>
     20 #include <stdlib.h>
     21 #include <stdio.h>
     22 #include <string.h>
     23 #include <inttypes.h>
     24 
     25 #include "config.h"
     26 
     27 #define NO_CPU_IO_DEFS
     28 #include "cpu.h"
     29 #include "exec-all.h"
     30 #include "disas.h"
     31 #include "tcg.h"
     32 
     33 /* code generation context */
     34 TCGContext tcg_ctx;
     35 
     36 uint16_t gen_opc_buf[OPC_BUF_SIZE];
     37 TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
     38 
     39 target_ulong gen_opc_pc[OPC_BUF_SIZE];
     40 uint16_t gen_opc_icount[OPC_BUF_SIZE];
     41 uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
     42 #if defined(TARGET_I386)
     43 uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
     44 #elif defined(TARGET_SPARC)
     45 target_ulong gen_opc_npc[OPC_BUF_SIZE];
     46 target_ulong gen_opc_jump_pc[2];
     47 #elif defined(TARGET_MIPS) || defined(TARGET_SH4)
     48 uint32_t gen_opc_hflags[OPC_BUF_SIZE];
     49 #endif
     50 
     51 #ifdef CONFIG_MEMCHECK
     52 /*
     53  * Memchecker code in this module copies TB PC <-> Guest PC map to the TB
     54  * descriptor after guest code has been translated in cpu_gen_init routine.
     55  */
     56 #include "memcheck/memcheck_api.h"
     57 
     58 /* Array of (tb_pc, guest_pc) pairs, big enough for all translations. This
     59  * array is used to obtain guest PC address from a translated PC address.
     60  * tcg_gen_code_common will fill it up when memchecker is enabled. */
     61 static target_ulong gen_opc_tpc2gpc[OPC_BUF_SIZE * 2];
     62 target_ulong* gen_opc_tpc2gpc_ptr = &gen_opc_tpc2gpc[0];
     63 /* Number of (tb_pc, guest_pc) pairs stored in gen_opc_tpc2gpc array. */
     64 unsigned int gen_opc_tpc2gpc_pairs;
     65 #endif  // CONFIG_MEMCHECK
     66 
     67 /* XXX: suppress that */
     68 unsigned long code_gen_max_block_size(void)
     69 {
     70     static unsigned long max;
     71 
     72     if (max == 0) {
     73         max = TCG_MAX_OP_SIZE;
     74 #define DEF(s, n, copy_size) max = copy_size > max? copy_size : max;
     75 #include "tcg-opc.h"
     76 #undef DEF
     77         max *= OPC_MAX_SIZE;
     78     }
     79 
     80     return max;
     81 }
     82 
     83 void cpu_gen_init(void)
     84 {
     85     tcg_context_init(&tcg_ctx);
     86     tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf),
     87                   CPU_TEMP_BUF_NLONGS * sizeof(long));
     88 }
     89 
     90 /* return non zero if the very first instruction is invalid so that
     91    the virtual CPU can trigger an exception.
     92 
     93    '*gen_code_size_ptr' contains the size of the generated code (host
     94    code).
     95 */
     96 int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
     97 {
     98     TCGContext *s = &tcg_ctx;
     99     uint8_t *gen_code_buf;
    100     int gen_code_size;
    101 #ifdef CONFIG_PROFILER
    102     int64_t ti;
    103 #endif
    104 
    105 #ifdef CONFIG_PROFILER
    106     s->tb_count1++; /* includes aborted translations because of
    107                        exceptions */
    108     ti = profile_getclock();
    109 #endif
    110     tcg_func_start(s);
    111 
    112     gen_intermediate_code(env, tb);
    113 
    114     /* generate machine code */
    115     gen_code_buf = tb->tc_ptr;
    116     tb->tb_next_offset[0] = 0xffff;
    117     tb->tb_next_offset[1] = 0xffff;
    118     s->tb_next_offset = tb->tb_next_offset;
    119 #ifdef USE_DIRECT_JUMP
    120     s->tb_jmp_offset = tb->tb_jmp_offset;
    121     s->tb_next = NULL;
    122     /* the following two entries are optional (only used for string ops) */
    123     /* XXX: not used ? */
    124     tb->tb_jmp_offset[2] = 0xffff;
    125     tb->tb_jmp_offset[3] = 0xffff;
    126 #else
    127     s->tb_jmp_offset = NULL;
    128     s->tb_next = tb->tb_next;
    129 #endif
    130 
    131 #ifdef CONFIG_PROFILER
    132     s->tb_count++;
    133     s->interm_time += profile_getclock() - ti;
    134     s->code_time -= profile_getclock();
    135 #endif
    136     gen_code_size = tcg_gen_code(s, gen_code_buf);
    137     *gen_code_size_ptr = gen_code_size;
    138 #ifdef CONFIG_PROFILER
    139     s->code_time += profile_getclock();
    140     s->code_in_len += tb->size;
    141     s->code_out_len += gen_code_size;
    142 #endif
    143 
    144 #ifdef CONFIG_MEMCHECK
    145     /* Save translated PC -> guest PC map into TB. */
    146     if (memcheck_enabled && gen_opc_tpc2gpc_pairs && is_cpu_user(env)) {
    147         tb->tpc2gpc =
    148                 qemu_malloc(gen_opc_tpc2gpc_pairs * 2 * sizeof(target_ulong));
    149         if (tb->tpc2gpc != NULL) {
    150             memcpy(tb->tpc2gpc, gen_opc_tpc2gpc_ptr,
    151                    gen_opc_tpc2gpc_pairs * 2 * sizeof(target_ulong));
    152             tb->tpc2gpc_pairs = gen_opc_tpc2gpc_pairs;
    153         }
    154     }
    155 #endif  // CONFIG_MEMCHECK
    156 
    157 #ifdef DEBUG_DISAS
    158     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
    159         qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);
    160         log_disas(tb->tc_ptr, *gen_code_size_ptr);
    161         qemu_log("\n");
    162         qemu_log_flush();
    163     }
    164 #endif
    165     return 0;
    166 }
    167 
    168 /* The cpu state corresponding to 'searched_pc' is restored.
    169  */
    170 int cpu_restore_state(TranslationBlock *tb,
    171                       CPUState *env, unsigned long searched_pc,
    172                       void *puc)
    173 {
    174     TCGContext *s = &tcg_ctx;
    175     int j;
    176     unsigned long tc_ptr;
    177 #ifdef CONFIG_PROFILER
    178     int64_t ti;
    179 #endif
    180 
    181 #ifdef CONFIG_PROFILER
    182     ti = profile_getclock();
    183 #endif
    184     tcg_func_start(s);
    185 
    186     gen_intermediate_code_pc(env, tb);
    187 
    188     if (use_icount) {
    189         /* Reset the cycle counter to the start of the block.  */
    190         env->icount_decr.u16.low += tb->icount;
    191         /* Clear the IO flag.  */
    192         env->can_do_io = 0;
    193     }
    194 
    195     /* find opc index corresponding to search_pc */
    196     tc_ptr = (unsigned long)tb->tc_ptr;
    197     if (searched_pc < tc_ptr)
    198         return -1;
    199 
    200     s->tb_next_offset = tb->tb_next_offset;
    201 #ifdef USE_DIRECT_JUMP
    202     s->tb_jmp_offset = tb->tb_jmp_offset;
    203     s->tb_next = NULL;
    204 #else
    205     s->tb_jmp_offset = NULL;
    206     s->tb_next = tb->tb_next;
    207 #endif
    208     j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
    209     if (j < 0)
    210         return -1;
    211     /* now find start of instruction before */
    212     while (gen_opc_instr_start[j] == 0)
    213         j--;
    214     env->icount_decr.u16.low -= gen_opc_icount[j];
    215 
    216     gen_pc_load(env, tb, searched_pc, j, puc);
    217 
    218 #ifdef CONFIG_PROFILER
    219     s->restore_time += profile_getclock() - ti;
    220     s->restore_count++;
    221 #endif
    222     return 0;
    223 }
    224