mirror of
https://github.com/qemu/qemu.git
synced 2024-12-12 13:13:51 +08:00
6375e09e79
QEMU host addresses must use uintptr_t to be portable for hosts with an unusual size of long (w64). tb_jmp_offset is an uint16_t value, therefore the local variable offset in function tb_set_jmp_target was changed from unsigned long to uint16_t. The type cast to long in function tb_add_jump now also uses uintptr_t. For the bit operation used here, the signedness of the type cast does not matter. Some remaining unsigned long values are either only used for ARM assembler code or will be fixed in a later patch for PPC. v2: Fix signature of tb_find_pc in exec.c, too (hint from Blue Swirl, thanks). There remain lots of other long / unsigned long in exec.c which must be replaced by uintptr_t. This will be done in a separate patch. Here only one of these type casts is fixed. v3: Also fix signature of page_unprotect. Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
164 lines
4.2 KiB
C
164 lines
4.2 KiB
C
/*
|
|
* Host code generation
|
|
*
|
|
* Copyright (c) 2003 Fabrice Bellard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "config.h"
|
|
|
|
#define NO_CPU_IO_DEFS
|
|
#include "cpu.h"
|
|
#include "disas.h"
|
|
#include "tcg.h"
|
|
#include "qemu-timer.h"
|
|
|
|
/* code generation context */
|
|
TCGContext tcg_ctx;
|
|
|
|
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
|
TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
|
|
|
|
target_ulong gen_opc_pc[OPC_BUF_SIZE];
|
|
uint16_t gen_opc_icount[OPC_BUF_SIZE];
|
|
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
|
|
|
void cpu_gen_init(void)
|
|
{
|
|
tcg_context_init(&tcg_ctx);
|
|
}
|
|
|
|
/* return non zero if the very first instruction is invalid so that
|
|
the virtual CPU can trigger an exception.
|
|
|
|
'*gen_code_size_ptr' contains the size of the generated code (host
|
|
code).
|
|
*/
|
|
int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr)
|
|
{
|
|
TCGContext *s = &tcg_ctx;
|
|
uint8_t *gen_code_buf;
|
|
int gen_code_size;
|
|
#ifdef CONFIG_PROFILER
|
|
int64_t ti;
|
|
#endif
|
|
|
|
#ifdef CONFIG_PROFILER
|
|
s->tb_count1++; /* includes aborted translations because of
|
|
exceptions */
|
|
ti = profile_getclock();
|
|
#endif
|
|
tcg_func_start(s);
|
|
|
|
gen_intermediate_code(env, tb);
|
|
|
|
/* generate machine code */
|
|
gen_code_buf = tb->tc_ptr;
|
|
tb->tb_next_offset[0] = 0xffff;
|
|
tb->tb_next_offset[1] = 0xffff;
|
|
s->tb_next_offset = tb->tb_next_offset;
|
|
#ifdef USE_DIRECT_JUMP
|
|
s->tb_jmp_offset = tb->tb_jmp_offset;
|
|
s->tb_next = NULL;
|
|
#else
|
|
s->tb_jmp_offset = NULL;
|
|
s->tb_next = tb->tb_next;
|
|
#endif
|
|
|
|
#ifdef CONFIG_PROFILER
|
|
s->tb_count++;
|
|
s->interm_time += profile_getclock() - ti;
|
|
s->code_time -= profile_getclock();
|
|
#endif
|
|
gen_code_size = tcg_gen_code(s, gen_code_buf);
|
|
*gen_code_size_ptr = gen_code_size;
|
|
#ifdef CONFIG_PROFILER
|
|
s->code_time += profile_getclock();
|
|
s->code_in_len += tb->size;
|
|
s->code_out_len += gen_code_size;
|
|
#endif
|
|
|
|
#ifdef DEBUG_DISAS
|
|
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
|
|
qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);
|
|
log_disas(tb->tc_ptr, *gen_code_size_ptr);
|
|
qemu_log("\n");
|
|
qemu_log_flush();
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* The cpu state corresponding to 'searched_pc' is restored.
|
|
*/
|
|
int cpu_restore_state(TranslationBlock *tb,
|
|
CPUArchState *env, uintptr_t searched_pc)
|
|
{
|
|
TCGContext *s = &tcg_ctx;
|
|
int j;
|
|
uintptr_t tc_ptr;
|
|
#ifdef CONFIG_PROFILER
|
|
int64_t ti;
|
|
#endif
|
|
|
|
#ifdef CONFIG_PROFILER
|
|
ti = profile_getclock();
|
|
#endif
|
|
tcg_func_start(s);
|
|
|
|
gen_intermediate_code_pc(env, tb);
|
|
|
|
if (use_icount) {
|
|
/* Reset the cycle counter to the start of the block. */
|
|
env->icount_decr.u16.low += tb->icount;
|
|
/* Clear the IO flag. */
|
|
env->can_do_io = 0;
|
|
}
|
|
|
|
/* find opc index corresponding to search_pc */
|
|
tc_ptr = (uintptr_t)tb->tc_ptr;
|
|
if (searched_pc < tc_ptr)
|
|
return -1;
|
|
|
|
s->tb_next_offset = tb->tb_next_offset;
|
|
#ifdef USE_DIRECT_JUMP
|
|
s->tb_jmp_offset = tb->tb_jmp_offset;
|
|
s->tb_next = NULL;
|
|
#else
|
|
s->tb_jmp_offset = NULL;
|
|
s->tb_next = tb->tb_next;
|
|
#endif
|
|
j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
|
|
if (j < 0)
|
|
return -1;
|
|
/* now find start of instruction before */
|
|
while (gen_opc_instr_start[j] == 0)
|
|
j--;
|
|
env->icount_decr.u16.low -= gen_opc_icount[j];
|
|
|
|
restore_state_to_opc(env, tb, j);
|
|
|
|
#ifdef CONFIG_PROFILER
|
|
s->restore_time += profile_getclock() - ti;
|
|
s->restore_count++;
|
|
#endif
|
|
return 0;
|
|
}
|