[1] | 1 | /*
|
---|
| 2 | * Host code generation
|
---|
[17265] | 3 | *
|
---|
[1] | 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
|
---|
[36175] | 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
---|
[1] | 18 | */
|
---|
[11982] | 19 |
|
---|
| 20 | /*
|
---|
[33656] | 21 | * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
|
---|
| 22 | * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
|
---|
[11982] | 23 | * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
|
---|
| 24 | * a choice of LGPL license versions is made available with the language indicating
|
---|
| 25 | * that LGPLv2 or any later version may be used, or where a choice of which version
|
---|
| 26 | * of the LGPL is applied is otherwise unspecified.
|
---|
| 27 | */
|
---|
[33656] | 28 |
|
---|
[1] | 29 | #include <stdarg.h>
|
---|
| 30 | #include <stdlib.h>
|
---|
| 31 | #include <stdio.h>
|
---|
| 32 | #include <string.h>
|
---|
[36140] | 33 | #include <inttypes.h>
|
---|
[1] | 34 |
|
---|
| 35 | #include "config.h"
|
---|
| 36 |
|
---|
| 37 | #define NO_CPU_IO_DEFS
|
---|
| 38 | #include "cpu.h"
|
---|
| 39 | #include "exec-all.h"
|
---|
| 40 | #include "disas.h"
|
---|
[13230] | 41 | #include "tcg.h"
|
---|
[37689] | 42 | #include "qemu-timer.h"
|
---|
[1] | 43 |
|
---|
[13230] | 44 | /* code generation context */
|
---|
| 45 | TCGContext tcg_ctx;
|
---|
[2422] | 46 |
|
---|
[1] | 47 | uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
---|
[13337] | 48 | TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
|
---|
[1] | 49 |
|
---|
| 50 | target_ulong gen_opc_pc[OPC_BUF_SIZE];
|
---|
[13337] | 51 | uint16_t gen_opc_icount[OPC_BUF_SIZE];
|
---|
[1] | 52 | uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
---|
| 53 |
|
---|
[36140] | 54 | void cpu_gen_init(void)
|
---|
[1] | 55 | {
|
---|
[13230] | 56 | tcg_context_init(&tcg_ctx);
|
---|
| 57 | tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf),
|
---|
[42601] | 58 | sizeof(((CPUState *)0)->temp_buf));
|
---|
[1] | 59 | }
|
---|
| 60 |
|
---|
| 61 | /* return non zero if the very first instruction is invalid so that
|
---|
[17265] | 62 | the virtual CPU can trigger an exception.
|
---|
[1] | 63 |
|
---|
| 64 | '*gen_code_size_ptr' contains the size of the generated code (host
|
---|
| 65 | code).
|
---|
| 66 | */
|
---|
[36140] | 67 | int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
|
---|
[1] | 68 | {
|
---|
[13230] | 69 | TCGContext *s = &tcg_ctx;
|
---|
[1] | 70 | uint8_t *gen_code_buf;
|
---|
| 71 | int gen_code_size;
|
---|
[13230] | 72 | #ifdef CONFIG_PROFILER
|
---|
| 73 | int64_t ti;
|
---|
| 74 | #endif
|
---|
[1] | 75 |
|
---|
[13230] | 76 | #ifdef CONFIG_PROFILER
|
---|
| 77 | s->tb_count1++; /* includes aborted translations because of
|
---|
| 78 | exceptions */
|
---|
| 79 | ti = profile_getclock();
|
---|
[1] | 80 | #endif
|
---|
[13230] | 81 |
|
---|
| 82 | #ifdef VBOX
|
---|
| 83 | RAWEx_ProfileStart(env, STATS_QEMU_COMPILATION);
|
---|
[36140] | 84 | #endif
|
---|
[13230] | 85 |
|
---|
| 86 | tcg_func_start(s);
|
---|
| 87 |
|
---|
[13337] | 88 | gen_intermediate_code(env, tb);
|
---|
[2422] | 89 |
|
---|
[13230] | 90 | /* generate machine code */
|
---|
| 91 | gen_code_buf = tb->tc_ptr;
|
---|
| 92 | tb->tb_next_offset[0] = 0xffff;
|
---|
| 93 | tb->tb_next_offset[1] = 0xffff;
|
---|
| 94 | s->tb_next_offset = tb->tb_next_offset;
|
---|
[1] | 95 | #ifdef USE_DIRECT_JUMP
|
---|
[13230] | 96 | s->tb_jmp_offset = tb->tb_jmp_offset;
|
---|
| 97 | s->tb_next = NULL;
|
---|
| 98 | #else
|
---|
| 99 | s->tb_jmp_offset = NULL;
|
---|
| 100 | s->tb_next = tb->tb_next;
|
---|
[1] | 101 | #endif
|
---|
[17265] | 102 |
|
---|
[13230] | 103 | #ifdef CONFIG_PROFILER
|
---|
| 104 | s->tb_count++;
|
---|
| 105 | s->interm_time += profile_getclock() - ti;
|
---|
| 106 | s->code_time -= profile_getclock();
|
---|
| 107 | #endif
|
---|
[36170] | 108 | gen_code_size = tcg_gen_code(s, gen_code_buf);
|
---|
[13230] | 109 | *gen_code_size_ptr = gen_code_size;
|
---|
| 110 | #ifdef CONFIG_PROFILER
|
---|
| 111 | s->code_time += profile_getclock();
|
---|
| 112 | s->code_in_len += tb->size;
|
---|
| 113 | s->code_out_len += gen_code_size;
|
---|
[1] | 114 | #endif
|
---|
[13230] | 115 |
|
---|
[1] | 116 | #ifdef VBOX
|
---|
[13230] | 117 | RAWEx_ProfileStop(env, STATS_QEMU_COMPILATION);
|
---|
[1] | 118 | #endif
|
---|
[17265] | 119 |
|
---|
[1] | 120 | #ifdef DEBUG_DISAS
|
---|
[36170] | 121 | if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
|
---|
| 122 | qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);
|
---|
| 123 | log_disas(tb->tc_ptr, *gen_code_size_ptr);
|
---|
| 124 | qemu_log("\n");
|
---|
| 125 | qemu_log_flush();
|
---|
[1] | 126 | }
|
---|
| 127 | #endif
|
---|
| 128 | return 0;
|
---|
| 129 | }
|
---|
| 130 |
|
---|
[17265] | 131 | /* The cpu state corresponding to 'searched_pc' is restored.
|
---|
[1] | 132 | */
|
---|
[17265] | 133 | int cpu_restore_state(TranslationBlock *tb,
|
---|
[42601] | 134 | CPUState *env, uintptr_t searched_pc,
|
---|
[1] | 135 | void *puc)
|
---|
| 136 | {
|
---|
[13230] | 137 | TCGContext *s = &tcg_ctx;
|
---|
| 138 | int j;
|
---|
[42601] | 139 | uintptr_t tc_ptr;
|
---|
[13230] | 140 | #ifdef CONFIG_PROFILER
|
---|
| 141 | int64_t ti;
|
---|
| 142 | #endif
|
---|
[1] | 143 |
|
---|
[13230] | 144 | #ifdef CONFIG_PROFILER
|
---|
| 145 | ti = profile_getclock();
|
---|
[1] | 146 | #endif
|
---|
[13230] | 147 | tcg_func_start(s);
|
---|
| 148 |
|
---|
[13337] | 149 | gen_intermediate_code_pc(env, tb);
|
---|
[13230] | 150 |
|
---|
| 151 | if (use_icount) {
|
---|
| 152 | /* Reset the cycle counter to the start of the block. */
|
---|
| 153 | env->icount_decr.u16.low += tb->icount;
|
---|
| 154 | /* Clear the IO flag. */
|
---|
| 155 | env->can_do_io = 0;
|
---|
| 156 | }
|
---|
| 157 |
|
---|
[1] | 158 | /* find opc index corresponding to search_pc */
|
---|
[42601] | 159 | tc_ptr = (uintptr_t)tb->tc_ptr;
|
---|
[1] | 160 | if (searched_pc < tc_ptr)
|
---|
| 161 | return -1;
|
---|
[17265] | 162 |
|
---|
[13230] | 163 | s->tb_next_offset = tb->tb_next_offset;
|
---|
| 164 | #ifdef USE_DIRECT_JUMP
|
---|
| 165 | s->tb_jmp_offset = tb->tb_jmp_offset;
|
---|
| 166 | s->tb_next = NULL;
|
---|
| 167 | #else
|
---|
| 168 | s->tb_jmp_offset = NULL;
|
---|
| 169 | s->tb_next = tb->tb_next;
|
---|
| 170 | #endif
|
---|
[36170] | 171 | j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
|
---|
[13230] | 172 | if (j < 0)
|
---|
| 173 | return -1;
|
---|
[1] | 174 | /* now find start of instruction before */
|
---|
| 175 | while (gen_opc_instr_start[j] == 0)
|
---|
| 176 | j--;
|
---|
[13230] | 177 | env->icount_decr.u16.low -= gen_opc_icount[j];
|
---|
| 178 |
|
---|
| 179 | gen_pc_load(env, tb, searched_pc, j, puc);
|
---|
| 180 |
|
---|
| 181 | #ifdef CONFIG_PROFILER
|
---|
| 182 | s->restore_time += profile_getclock() - ti;
|
---|
| 183 | s->restore_count++;
|
---|
[1] | 184 | #endif
|
---|
| 185 | return 0;
|
---|
| 186 | }
|
---|