tcg generic translate loop v15
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZsBwXAAoJEGTfOOivfiFfst4IAIkgld9yabywTZc5KUvJmMc/ Zh8BoI+1L27NqcQiRAB2m82yFho8jKdk618dFp2KadXzhmKr6CDztsD6y0BPg7YW pBWakZ4Q/HpAIwkAKiKoXZ5+go13z3OSjYZxYCDZzokl0cgxfKshoN2RYVD0L1my SGPp2DuF2YgrNy0VHU7Ki+lW77f1wYPykDv6geb7NGI4ePUvSpoCLKdcoPmCQOut sFiRijkW6W2HB70Tfq+OJFBb2UqJEZzu1uDwP156FKWGDrzGyP0tclRnnmrHuder wxdUoiscz5Ow4J4oa9/CERRAR11S1aHF45ofwjf2VpuqyeZy98d4mX9GG4oVqEc= =ItTI -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tgt-20170906' into staging tcg generic translate loop v15 # gpg: Signature made Wed 06 Sep 2017 17:02:31 BST # gpg: using RSA key 0x64DF38E8AF7E215F # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-tgt-20170906: (32 commits) target/arm: Perform per-insn cross-page check only for Thumb target/arm: Split out thumb_tr_translate_insn target/arm: Move ss check to init_disas_context target/arm: [a64] Move page and ss checks to init_disas_context target/arm: [tcg] Port to generic translation framework target/arm: [tcg,a64] Port to disas_log target/arm: [tcg] Port to disas_log target/arm: [tcg,a64] Port to tb_stop target/arm: [tcg] Port to tb_stop target/arm: [tcg,a64] Port to translate_insn target/arm: [tcg] Port to translate_insn target/arm: [tcg,a64] Port to breakpoint_check target/arm: [tcg,a64] Port to insn_start target/arm: [tcg] Port to insn_start target/arm: [tcg] Port to tb_start target/arm: [tcg,a64] Port to init_disas_context target/arm: [tcg] Port to init_disas_context target/arm: [tcg] Port to DisasContextBase target/i386: [tcg] Port to generic translation framework target/i386: [tcg] Port to disas_log ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7e375e0442
|
@ -1,3 +1,4 @@
|
|||
obj-$(CONFIG_SOFTMMU) += tcg-all.o
|
||||
obj-$(CONFIG_SOFTMMU) += cputlb.o
|
||||
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o
|
||||
obj-y += translator.o
|
||||
|
|
138
accel/tcg/translator.c
Normal file
138
accel/tcg/translator.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Generic intermediate code generation.
|
||||
*
|
||||
* Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/gen-icount.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
/* Pairs with tcg_clear_temp_count.
|
||||
To be called by #TranslatorOps.{translate_insn,tb_stop} if
|
||||
(1) the target is sufficiently clean to support reporting,
|
||||
(2) as and when all temporaries are known to be consumed.
|
||||
For most targets, (2) is at the end of translate_insn. */
|
||||
void translator_loop_temp_check(DisasContextBase *db)
|
||||
{
|
||||
if (tcg_check_temp_count()) {
|
||||
qemu_log("warning: TCG temporary leaks before "
|
||||
TARGET_FMT_lx "\n", db->pc_next);
|
||||
}
|
||||
}
|
||||
|
||||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
CPUState *cpu, TranslationBlock *tb)
|
||||
{
|
||||
int max_insns;
|
||||
|
||||
/* Initialize DisasContext */
|
||||
db->tb = tb;
|
||||
db->pc_first = tb->pc;
|
||||
db->pc_next = db->pc_first;
|
||||
db->is_jmp = DISAS_NEXT;
|
||||
db->num_insns = 0;
|
||||
db->singlestep_enabled = cpu->singlestep_enabled;
|
||||
|
||||
/* Instruction counting */
|
||||
max_insns = db->tb->cflags & CF_COUNT_MASK;
|
||||
if (max_insns == 0) {
|
||||
max_insns = CF_COUNT_MASK;
|
||||
}
|
||||
if (max_insns > TCG_MAX_INSNS) {
|
||||
max_insns = TCG_MAX_INSNS;
|
||||
}
|
||||
if (db->singlestep_enabled || singlestep) {
|
||||
max_insns = 1;
|
||||
}
|
||||
|
||||
max_insns = ops->init_disas_context(db, cpu, max_insns);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
/* Reset the temp count so that we can identify leaks */
|
||||
tcg_clear_temp_count();
|
||||
|
||||
/* Start translating. */
|
||||
gen_tb_start(db->tb);
|
||||
ops->tb_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
while (true) {
|
||||
db->num_insns++;
|
||||
ops->insn_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
/* Pass breakpoint hits to target for further processing */
|
||||
if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
|
||||
CPUBreakpoint *bp;
|
||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||
if (bp->pc == db->pc_next) {
|
||||
if (ops->breakpoint_check(db, cpu, bp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
|
||||
that only one more instruction is to be executed. Otherwise
|
||||
it should use DISAS_NORETURN when generating an exception,
|
||||
but may use a DISAS_TARGET_* value for Something Else. */
|
||||
if (db->is_jmp > DISAS_TOO_MANY) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disassemble one instruction. The translate_insn hook should
|
||||
update db->pc_next and db->is_jmp to indicate what should be
|
||||
done next -- either exiting this loop or locate the start of
|
||||
the next instruction. */
|
||||
if (db->num_insns == max_insns && (db->tb->cflags & CF_LAST_IO)) {
|
||||
/* Accept I/O on the last instruction. */
|
||||
gen_io_start();
|
||||
ops->translate_insn(db, cpu);
|
||||
gen_io_end();
|
||||
} else {
|
||||
ops->translate_insn(db, cpu);
|
||||
}
|
||||
|
||||
/* Stop translation if translate_insn so indicated. */
|
||||
if (db->is_jmp != DISAS_NEXT) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Stop translation if the output buffer is full,
|
||||
or we have executed all of the allowed instructions. */
|
||||
if (tcg_op_buf_full() || db->num_insns >= max_insns) {
|
||||
db->is_jmp = DISAS_TOO_MANY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit code to exit the TB, as indicated by db->is_jmp. */
|
||||
ops->tb_stop(db, cpu);
|
||||
gen_tb_end(db->tb, db->num_insns);
|
||||
|
||||
/* The disas_log hook may use these values rather than recompute. */
|
||||
db->tb->size = db->pc_next - db->pc_first;
|
||||
db->tb->icount = db->num_insns;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
&& qemu_log_in_addr_range(db->pc_first)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
ops->disas_log(db, cpu);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -35,35 +35,6 @@ typedef abi_ulong tb_page_addr_t;
|
|||
typedef ram_addr_t tb_page_addr_t;
|
||||
#endif
|
||||
|
||||
/* DisasContext is_jmp field values
|
||||
*
|
||||
* is_jmp starts as DISAS_NEXT. The translator will keep processing
|
||||
* instructions until an exit condition is reached. If we reach the
|
||||
* exit condition and is_jmp is still DISAS_NEXT (because of some
|
||||
* other condition) we simply "jump" to the next address.
|
||||
* The remaining exit cases are:
|
||||
*
|
||||
* DISAS_JUMP - Only the PC was modified dynamically (e.g computed)
|
||||
* DISAS_TB_JUMP - Only the PC was modified statically (e.g. branch)
|
||||
*
|
||||
* In these cases as long as the PC is updated we can chain to the
|
||||
* next TB either by exiting the loop or looking up the next TB via
|
||||
* the loookup helper.
|
||||
*
|
||||
* DISAS_UPDATE - CPU State was modified dynamically
|
||||
*
|
||||
* This covers any other CPU state which necessities us exiting the
|
||||
* TCG code to the main run-loop. Typically this includes anything
|
||||
* that might change the interrupt state.
|
||||
*
|
||||
* Individual translators may define additional exit cases to deal
|
||||
* with per-target special conditions.
|
||||
*/
|
||||
#define DISAS_NEXT 0 /* next instruction can be analyzed */
|
||||
#define DISAS_JUMP 1 /* only pc was modified dynamically */
|
||||
#define DISAS_TB_JUMP 2 /* only pc was modified statically */
|
||||
#define DISAS_UPDATE 3 /* cpu state was modified dynamically */
|
||||
|
||||
#include "qemu/log.h"
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb);
|
||||
|
|
144
include/exec/translator.h
Normal file
144
include/exec/translator.h
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Generic intermediate code generation.
|
||||
*
|
||||
* Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef EXEC__TRANSLATOR_H
|
||||
#define EXEC__TRANSLATOR_H
|
||||
|
||||
/*
|
||||
* Include this header from a target-specific file, and add a
|
||||
*
|
||||
* DisasContextBase base;
|
||||
*
|
||||
* member in your target-specific DisasContext.
|
||||
*/
|
||||
|
||||
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
|
||||
/**
|
||||
* DisasJumpType:
|
||||
* @DISAS_NEXT: Next instruction in program order.
|
||||
* @DISAS_TOO_MANY: Too many instructions translated.
|
||||
* @DISAS_NORETURN: Following code is dead.
|
||||
* @DISAS_TARGET_*: Start of target-specific conditions.
|
||||
*
|
||||
* What instruction to disassemble next.
|
||||
*/
|
||||
typedef enum DisasJumpType {
|
||||
DISAS_NEXT,
|
||||
DISAS_TOO_MANY,
|
||||
DISAS_NORETURN,
|
||||
DISAS_TARGET_0,
|
||||
DISAS_TARGET_1,
|
||||
DISAS_TARGET_2,
|
||||
DISAS_TARGET_3,
|
||||
DISAS_TARGET_4,
|
||||
DISAS_TARGET_5,
|
||||
DISAS_TARGET_6,
|
||||
DISAS_TARGET_7,
|
||||
DISAS_TARGET_8,
|
||||
DISAS_TARGET_9,
|
||||
DISAS_TARGET_10,
|
||||
DISAS_TARGET_11,
|
||||
} DisasJumpType;
|
||||
|
||||
/**
|
||||
* DisasContextBase:
|
||||
* @tb: Translation block for this disassembly.
|
||||
* @pc_first: Address of first guest instruction in this TB.
|
||||
* @pc_next: Address of next guest instruction in this TB (current during
|
||||
* disassembly).
|
||||
* @is_jmp: What instruction to disassemble next.
|
||||
* @num_insns: Number of translated instructions (including current).
|
||||
* @singlestep_enabled: "Hardware" single stepping enabled.
|
||||
*
|
||||
* Architecture-agnostic disassembly context.
|
||||
*/
|
||||
typedef struct DisasContextBase {
|
||||
TranslationBlock *tb;
|
||||
target_ulong pc_first;
|
||||
target_ulong pc_next;
|
||||
DisasJumpType is_jmp;
|
||||
unsigned int num_insns;
|
||||
bool singlestep_enabled;
|
||||
} DisasContextBase;
|
||||
|
||||
/**
|
||||
* TranslatorOps:
|
||||
* @init_disas_context:
|
||||
* Initialize the target-specific portions of DisasContext struct.
|
||||
* The generic DisasContextBase has already been initialized.
|
||||
* Return max_insns, modified as necessary by db->tb->flags.
|
||||
*
|
||||
* @tb_start:
|
||||
* Emit any code required before the start of the main loop,
|
||||
* after the generic gen_tb_start().
|
||||
*
|
||||
* @insn_start:
|
||||
* Emit the tcg_gen_insn_start opcode.
|
||||
*
|
||||
* @breakpoint_check:
|
||||
* When called, the breakpoint has already been checked to match the PC,
|
||||
* but the target may decide the breakpoint missed the address
|
||||
* (e.g., due to conditions encoded in their flags). Return true to
|
||||
* indicate that the breakpoint did hit, in which case no more breakpoints
|
||||
* are checked. If the breakpoint did hit, emit any code required to
|
||||
* signal the exception, and set db->is_jmp as necessary to terminate
|
||||
* the main loop.
|
||||
*
|
||||
* @translate_insn:
|
||||
* Disassemble one instruction and set db->pc_next for the start
|
||||
* of the following instruction. Set db->is_jmp as necessary to
|
||||
* terminate the main loop.
|
||||
*
|
||||
* @tb_stop:
|
||||
* Emit any opcodes required to exit the TB, based on db->is_jmp.
|
||||
*
|
||||
* @disas_log:
|
||||
* Print instruction disassembly to log.
|
||||
*/
|
||||
typedef struct TranslatorOps {
|
||||
int (*init_disas_context)(DisasContextBase *db, CPUState *cpu,
|
||||
int max_insns);
|
||||
void (*tb_start)(DisasContextBase *db, CPUState *cpu);
|
||||
void (*insn_start)(DisasContextBase *db, CPUState *cpu);
|
||||
bool (*breakpoint_check)(DisasContextBase *db, CPUState *cpu,
|
||||
const CPUBreakpoint *bp);
|
||||
void (*translate_insn)(DisasContextBase *db, CPUState *cpu);
|
||||
void (*tb_stop)(DisasContextBase *db, CPUState *cpu);
|
||||
void (*disas_log)(const DisasContextBase *db, CPUState *cpu);
|
||||
} TranslatorOps;
|
||||
|
||||
/**
|
||||
* translator_loop:
|
||||
* @ops: Target-specific operations.
|
||||
* @db: Disassembly context.
|
||||
* @cpu: Target vCPU.
|
||||
* @tb: Translation block.
|
||||
*
|
||||
* Generic translator loop.
|
||||
*
|
||||
* Translation will stop in the following cases (in order):
|
||||
* - When is_jmp set by #TranslatorOps::breakpoint_check.
|
||||
* - set to DISAS_TOO_MANY exits after translating one more insn
|
||||
* - set to any other value than DISAS_NEXT exits immediately.
|
||||
* - When is_jmp set by #TranslatorOps::translate_insn.
|
||||
* - set to any value other than DISAS_NEXT exits immediately.
|
||||
* - When the TCG operation buffer is full.
|
||||
* - When single-stepping is enabled (system-wide or on the current vCPU).
|
||||
* - When too many instructions have been translated.
|
||||
*/
|
||||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
CPUState *cpu, TranslationBlock *tb);
|
||||
|
||||
void translator_loop_temp_check(DisasContextBase *db);
|
||||
|
||||
#endif /* EXEC__TRANSLATOR_H */
|
|
@ -304,7 +304,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
|
|||
{
|
||||
gen_a64_set_pc_im(s->pc - offset);
|
||||
gen_exception_internal(excp);
|
||||
s->is_jmp = DISAS_EXC;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_exception_insn(DisasContext *s, int offset, int excp,
|
||||
|
@ -312,7 +312,7 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
|
|||
{
|
||||
gen_a64_set_pc_im(s->pc - offset);
|
||||
gen_exception(excp, syndrome, target_el);
|
||||
s->is_jmp = DISAS_EXC;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_ss_advance(DisasContext *s)
|
||||
|
@ -340,7 +340,7 @@ static void gen_step_complete_exception(DisasContext *s)
|
|||
gen_ss_advance(s);
|
||||
gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
|
||||
default_exception_el(s));
|
||||
s->is_jmp = DISAS_EXC;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
|
||||
|
@ -348,13 +348,13 @@ static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
|
|||
/* No direct tb linking with singlestep (either QEMU's or the ARM
|
||||
* debug architecture kind) or deterministic io
|
||||
*/
|
||||
if (s->singlestep_enabled || s->ss_active || (s->tb->cflags & CF_LAST_IO)) {
|
||||
if (s->base.singlestep_enabled || s->ss_active || (s->base.tb->cflags & CF_LAST_IO)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Only link tbs from inside the same guest page */
|
||||
if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
|
||||
if ((s->base.tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -366,21 +366,21 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
|
|||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
tb = s->tb;
|
||||
tb = s->base.tb;
|
||||
if (use_goto_tb(s, n, dest)) {
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_a64_set_pc_im(dest);
|
||||
tcg_gen_exit_tb((intptr_t)tb + n);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
gen_a64_set_pc_im(dest);
|
||||
if (s->ss_active) {
|
||||
gen_step_complete_exception(s);
|
||||
} else if (s->singlestep_enabled) {
|
||||
} else if (s->base.singlestep_enabled) {
|
||||
gen_exception_internal(EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1331,16 +1331,16 @@ static void handle_hint(DisasContext *s, uint32_t insn,
|
|||
case 0: /* NOP */
|
||||
return;
|
||||
case 3: /* WFI */
|
||||
s->is_jmp = DISAS_WFI;
|
||||
s->base.is_jmp = DISAS_WFI;
|
||||
return;
|
||||
case 1: /* YIELD */
|
||||
if (!parallel_cpus) {
|
||||
s->is_jmp = DISAS_YIELD;
|
||||
s->base.is_jmp = DISAS_YIELD;
|
||||
}
|
||||
return;
|
||||
case 2: /* WFE */
|
||||
if (!parallel_cpus) {
|
||||
s->is_jmp = DISAS_WFE;
|
||||
s->base.is_jmp = DISAS_WFE;
|
||||
}
|
||||
return;
|
||||
case 4: /* SEV */
|
||||
|
@ -1424,7 +1424,7 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
|
|||
tcg_temp_free_i32(tcg_op);
|
||||
/* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
|
||||
gen_a64_set_pc_im(s->pc);
|
||||
s->is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
|
||||
s->base.is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -1559,7 +1559,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||
break;
|
||||
}
|
||||
|
||||
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
gen_io_start();
|
||||
}
|
||||
|
||||
|
@ -1590,16 +1590,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
|||
}
|
||||
}
|
||||
|
||||
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
/* I/O operations must end the TB here (whether read or write) */
|
||||
gen_io_end();
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
} else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
|
||||
/* We default to ending the TB on a coprocessor register write,
|
||||
* but allow this to be suppressed by the register definition
|
||||
* (usually only necessary to work around guest bugs).
|
||||
*/
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1789,7 +1789,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
gen_helper_exception_return(cpu_env);
|
||||
/* Must exit loop to check un-masked IRQs */
|
||||
s->is_jmp = DISAS_EXIT;
|
||||
s->base.is_jmp = DISAS_EXIT;
|
||||
return;
|
||||
case 5: /* DRPS */
|
||||
if (rn != 0x1f) {
|
||||
|
@ -1803,7 +1803,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
|||
return;
|
||||
}
|
||||
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* C3.2 Branches, exception generating and system instructions */
|
||||
|
@ -11200,23 +11200,15 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
|||
free_tmp_a64(s);
|
||||
}
|
||||
|
||||
void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
|
||||
static int aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
CPUState *cpu, int max_insns)
|
||||
{
|
||||
CPUARMState *env = cs->env_ptr;
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
target_ulong pc_start;
|
||||
target_ulong next_page_start;
|
||||
int num_insns;
|
||||
int max_insns;
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
ARMCPU *arm_cpu = arm_env_get_cpu(env);
|
||||
int bound;
|
||||
|
||||
pc_start = tb->pc;
|
||||
|
||||
dc->tb = tb;
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->pc = pc_start;
|
||||
dc->singlestep_enabled = cs->singlestep_enabled;
|
||||
dc->pc = dc->base.pc_first;
|
||||
dc->condjmp = 0;
|
||||
|
||||
dc->aarch64 = 1;
|
||||
|
@ -11227,20 +11219,20 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
|
|||
!arm_el_is_aa64(env, 3);
|
||||
dc->thumb = 0;
|
||||
dc->sctlr_b = 0;
|
||||
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
|
||||
dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = 0;
|
||||
dc->condexec_cond = 0;
|
||||
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
|
||||
dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags);
|
||||
dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags);
|
||||
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
|
||||
dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
|
||||
dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
|
||||
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
dc->user = (dc->current_el == 0);
|
||||
#endif
|
||||
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
|
||||
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
|
||||
dc->vec_len = 0;
|
||||
dc->vec_stride = 0;
|
||||
dc->cp_regs = cpu->cp_regs;
|
||||
dc->cp_regs = arm_cpu->cp_regs;
|
||||
dc->features = env->features;
|
||||
|
||||
/* Single step state. The code-generation logic here is:
|
||||
|
@ -11258,127 +11250,131 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
|
|||
* emit code to generate a software step exception
|
||||
* end the TB
|
||||
*/
|
||||
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
|
||||
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
|
||||
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
|
||||
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
|
||||
dc->is_ldex = false;
|
||||
dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
|
||||
|
||||
/* Bound the number of insns to execute to those left on the page. */
|
||||
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
|
||||
|
||||
/* If architectural single step active, limit to 1. */
|
||||
if (dc->ss_active) {
|
||||
bound = 1;
|
||||
}
|
||||
max_insns = MIN(max_insns, bound);
|
||||
|
||||
init_tmp_a64_array(dc);
|
||||
|
||||
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
num_insns = 0;
|
||||
max_insns = tb->cflags & CF_COUNT_MASK;
|
||||
if (max_insns == 0) {
|
||||
max_insns = CF_COUNT_MASK;
|
||||
}
|
||||
if (max_insns > TCG_MAX_INSNS) {
|
||||
max_insns = TCG_MAX_INSNS;
|
||||
}
|
||||
|
||||
gen_tb_start(tb);
|
||||
return max_insns;
|
||||
}
|
||||
|
||||
static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
tcg_clear_temp_count();
|
||||
}
|
||||
|
||||
do {
|
||||
dc->insn_start_idx = tcg_op_buf_count();
|
||||
tcg_gen_insn_start(dc->pc, 0, 0);
|
||||
num_insns++;
|
||||
static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
|
||||
CPUBreakpoint *bp;
|
||||
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
|
||||
if (bp->pc == dc->pc) {
|
||||
if (bp->flags & BP_CPU) {
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
gen_helper_check_breakpoints(cpu_env);
|
||||
/* End the TB early; it likely won't be executed */
|
||||
dc->is_jmp = DISAS_UPDATE;
|
||||
} else {
|
||||
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
|
||||
/* The address covered by the breakpoint must be
|
||||
included in [tb->pc, tb->pc + tb->size) in order
|
||||
to for it to be properly cleared -- thus we
|
||||
increment the PC here so that the logic setting
|
||||
tb->size below does the right thing. */
|
||||
dc->pc += 4;
|
||||
goto done_generating;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dc->insn_start_idx = tcg_op_buf_count();
|
||||
tcg_gen_insn_start(dc->pc, 0, 0);
|
||||
}
|
||||
|
||||
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
|
||||
gen_io_start();
|
||||
}
|
||||
static bool aarch64_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
|
||||
const CPUBreakpoint *bp)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (dc->ss_active && !dc->pstate_ss) {
|
||||
/* Singlestep state is Active-pending.
|
||||
* If we're in this state at the start of a TB then either
|
||||
* a) we just took an exception to an EL which is being debugged
|
||||
* and this is the first insn in the exception handler
|
||||
* b) debug exceptions were masked and we just unmasked them
|
||||
* without changing EL (eg by clearing PSTATE.D)
|
||||
* In either case we're going to take a swstep exception in the
|
||||
* "did not step an insn" case, and so the syndrome ISV and EX
|
||||
* bits should be zero.
|
||||
*/
|
||||
assert(num_insns == 1);
|
||||
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
|
||||
default_exception_el(dc));
|
||||
dc->is_jmp = DISAS_EXC;
|
||||
break;
|
||||
}
|
||||
|
||||
disas_a64_insn(env, dc);
|
||||
|
||||
if (tcg_check_temp_count()) {
|
||||
fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
|
||||
dc->pc);
|
||||
}
|
||||
|
||||
/* Translation stops when a conditional branch is encountered.
|
||||
* Otherwise the subsequent code could get translated several times.
|
||||
* Also stop translation when a page boundary is reached. This
|
||||
* ensures prefetch aborts occur at the right place.
|
||||
*/
|
||||
} while (!dc->is_jmp && !tcg_op_buf_full() &&
|
||||
!cs->singlestep_enabled &&
|
||||
!singlestep &&
|
||||
!dc->ss_active &&
|
||||
dc->pc < next_page_start &&
|
||||
num_insns < max_insns);
|
||||
|
||||
if (tb->cflags & CF_LAST_IO) {
|
||||
gen_io_end();
|
||||
if (bp->flags & BP_CPU) {
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
gen_helper_check_breakpoints(cpu_env);
|
||||
/* End the TB early; it likely won't be executed */
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
} else {
|
||||
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
|
||||
/* The address covered by the breakpoint must be
|
||||
included in [tb->pc, tb->pc + tb->size) in order
|
||||
to for it to be properly cleared -- thus we
|
||||
increment the PC here so that the logic setting
|
||||
tb->size below does the right thing. */
|
||||
dc->pc += 4;
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
if (unlikely(cs->singlestep_enabled || dc->ss_active)
|
||||
&& dc->is_jmp != DISAS_EXC) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
|
||||
if (dc->ss_active && !dc->pstate_ss) {
|
||||
/* Singlestep state is Active-pending.
|
||||
* If we're in this state at the start of a TB then either
|
||||
* a) we just took an exception to an EL which is being debugged
|
||||
* and this is the first insn in the exception handler
|
||||
* b) debug exceptions were masked and we just unmasked them
|
||||
* without changing EL (eg by clearing PSTATE.D)
|
||||
* In either case we're going to take a swstep exception in the
|
||||
* "did not step an insn" case, and so the syndrome ISV and EX
|
||||
* bits should be zero.
|
||||
*/
|
||||
assert(dc->base.num_insns == 1);
|
||||
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
|
||||
default_exception_el(dc));
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
disas_a64_insn(env, dc);
|
||||
}
|
||||
|
||||
dc->base.pc_next = dc->pc;
|
||||
translator_loop_temp_check(&dc->base);
|
||||
}
|
||||
|
||||
static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (unlikely(dc->base.singlestep_enabled || dc->ss_active)) {
|
||||
/* Note that this means single stepping WFI doesn't halt the CPU.
|
||||
* For conditional branch insns this is harmless unreachable code as
|
||||
* gen_goto_tb() has already handled emitting the debug exception
|
||||
* (and thus a tb-jump is not possible when singlestepping).
|
||||
*/
|
||||
assert(dc->is_jmp != DISAS_TB_JUMP);
|
||||
if (dc->is_jmp != DISAS_JUMP) {
|
||||
switch (dc->base.is_jmp) {
|
||||
default:
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
}
|
||||
if (cs->singlestep_enabled) {
|
||||
gen_exception_internal(EXCP_DEBUG);
|
||||
} else {
|
||||
gen_step_complete_exception(dc);
|
||||
/* fall through */
|
||||
case DISAS_JUMP:
|
||||
if (dc->base.singlestep_enabled) {
|
||||
gen_exception_internal(EXCP_DEBUG);
|
||||
} else {
|
||||
gen_step_complete_exception(dc);
|
||||
}
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (dc->is_jmp) {
|
||||
switch (dc->base.is_jmp) {
|
||||
case DISAS_NEXT:
|
||||
case DISAS_TOO_MANY:
|
||||
gen_goto_tb(dc, 1, dc->pc);
|
||||
break;
|
||||
default:
|
||||
case DISAS_UPDATE:
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
/* fall through */
|
||||
case DISAS_JUMP:
|
||||
tcg_gen_lookup_and_goto_ptr(cpu_pc);
|
||||
break;
|
||||
case DISAS_TB_JUMP:
|
||||
case DISAS_EXC:
|
||||
case DISAS_EXIT:
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
case DISAS_SWI:
|
||||
break;
|
||||
case DISAS_WFE:
|
||||
|
@ -11400,31 +11396,29 @@ void gen_intermediate_code_a64(CPUState *cs, TranslationBlock *tb)
|
|||
*/
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case DISAS_UPDATE:
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
/* fall through */
|
||||
case DISAS_EXIT:
|
||||
default:
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done_generating:
|
||||
gen_tb_end(tb, num_insns);
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
|
||||
qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start,
|
||||
4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif
|
||||
tb->size = dc->pc - pc_start;
|
||||
tb->icount = num_insns;
|
||||
/* Functions above can change dc->pc, so re-align db->pc_next */
|
||||
dc->base.pc_next = dc->pc;
|
||||
}
|
||||
|
||||
static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size,
|
||||
4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
|
||||
}
|
||||
|
||||
const TranslatorOps aarch64_translator_ops = {
|
||||
.init_disas_context = aarch64_tr_init_disas_context,
|
||||
.tb_start = aarch64_tr_tb_start,
|
||||
.insn_start = aarch64_tr_insn_start,
|
||||
.breakpoint_check = aarch64_tr_breakpoint_check,
|
||||
.translate_insn = aarch64_tr_translate_insn,
|
||||
.tb_stop = aarch64_tr_tb_stop,
|
||||
.disas_log = aarch64_tr_disas_log,
|
||||
};
|
||||
|
|
|
@ -224,7 +224,7 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
|
|||
* We choose to ignore [1:0] in ARM mode for all architecture versions.
|
||||
*/
|
||||
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
}
|
||||
tcg_gen_mov_i32(cpu_R[reg], var);
|
||||
tcg_temp_free_i32(var);
|
||||
|
@ -297,7 +297,7 @@ static void gen_step_complete_exception(DisasContext *s)
|
|||
gen_ss_advance(s);
|
||||
gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
|
||||
default_exception_el(s));
|
||||
s->is_jmp = DISAS_EXC;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_singlestep_exception(DisasContext *s)
|
||||
|
@ -321,7 +321,7 @@ static inline bool is_singlestepping(DisasContext *s)
|
|||
* misnamed as it only means "one instruction per TB" and doesn't
|
||||
* affect the code we generate.
|
||||
*/
|
||||
return s->singlestep_enabled || s->ss_active;
|
||||
return s->base.singlestep_enabled || s->ss_active;
|
||||
}
|
||||
|
||||
static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
|
||||
|
@ -930,7 +930,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
|
|||
{
|
||||
TCGv_i32 tmp;
|
||||
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
if (s->thumb != (addr & 1)) {
|
||||
tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, addr & 1);
|
||||
|
@ -943,7 +943,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
|
|||
/* Set PC and Thumb state from var. var is marked as dead. */
|
||||
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
|
||||
{
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
tcg_gen_andi_i32(cpu_R[15], var, ~1);
|
||||
tcg_gen_andi_i32(var, var, 1);
|
||||
store_cpu_field(var, thumb);
|
||||
|
@ -957,11 +957,11 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
|
|||
static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
|
||||
{
|
||||
/* Generate the same code here as for a simple bx, but flag via
|
||||
* s->is_jmp that we need to do the rest of the work later.
|
||||
* s->base.is_jmp that we need to do the rest of the work later.
|
||||
*/
|
||||
gen_bx(s, var);
|
||||
if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) {
|
||||
s->is_jmp = DISAS_BX_EXCRET;
|
||||
s->base.is_jmp = DISAS_BX_EXCRET;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,7 +1161,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
|
|||
*/
|
||||
s->svc_imm = imm16;
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_HVC;
|
||||
s->base.is_jmp = DISAS_HVC;
|
||||
}
|
||||
|
||||
static inline void gen_smc(DisasContext *s)
|
||||
|
@ -1176,7 +1176,7 @@ static inline void gen_smc(DisasContext *s)
|
|||
gen_helper_pre_smc(cpu_env, tmp);
|
||||
tcg_temp_free_i32(tmp);
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_SMC;
|
||||
s->base.is_jmp = DISAS_SMC;
|
||||
}
|
||||
|
||||
static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
|
||||
|
@ -1184,7 +1184,7 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
|
|||
gen_set_condexec(s);
|
||||
gen_set_pc_im(s, s->pc - offset);
|
||||
gen_exception_internal(excp);
|
||||
s->is_jmp = DISAS_EXC;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_exception_insn(DisasContext *s, int offset, int excp,
|
||||
|
@ -1193,14 +1193,14 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
|
|||
gen_set_condexec(s);
|
||||
gen_set_pc_im(s, s->pc - offset);
|
||||
gen_exception(excp, syn, target_el);
|
||||
s->is_jmp = DISAS_EXC;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
/* Force a TB lookup after an instruction that changes the CPU state. */
|
||||
static inline void gen_lookup_tb(DisasContext *s)
|
||||
{
|
||||
tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
|
||||
s->is_jmp = DISAS_EXIT;
|
||||
s->base.is_jmp = DISAS_EXIT;
|
||||
}
|
||||
|
||||
static inline void gen_hlt(DisasContext *s, int imm)
|
||||
|
@ -4145,7 +4145,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
|
|||
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
|
||||
return (s->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
|
||||
((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
|
||||
#else
|
||||
return true;
|
||||
|
@ -4169,12 +4169,12 @@ static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
|
|||
if (use_goto_tb(s, dest)) {
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_set_pc_im(s, dest);
|
||||
tcg_gen_exit_tb((uintptr_t)s->tb + n);
|
||||
tcg_gen_exit_tb((uintptr_t)s->base.tb + n);
|
||||
} else {
|
||||
gen_set_pc_im(s, dest);
|
||||
gen_goto_ptr();
|
||||
}
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static inline void gen_jmp (DisasContext *s, uint32_t dest)
|
||||
|
@ -4436,7 +4436,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
|
|||
tcg_temp_free_i32(tcg_tgtmode);
|
||||
tcg_temp_free_i32(tcg_regno);
|
||||
tcg_temp_free_i32(tcg_reg);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
|
||||
static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
|
||||
|
@ -4458,7 +4458,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
|
|||
tcg_temp_free_i32(tcg_tgtmode);
|
||||
tcg_temp_free_i32(tcg_regno);
|
||||
store_reg(s, rn, tcg_reg);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
|
||||
/* Store value to PC as for an exception return (ie don't
|
||||
|
@ -4482,7 +4482,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
|
|||
gen_helper_cpsr_write_eret(cpu_env, cpsr);
|
||||
tcg_temp_free_i32(cpsr);
|
||||
/* Must exit loop to check un-masked IRQs */
|
||||
s->is_jmp = DISAS_EXIT;
|
||||
s->base.is_jmp = DISAS_EXIT;
|
||||
}
|
||||
|
||||
/* Generate an old-style exception return. Marks pc as dead. */
|
||||
|
@ -4505,17 +4505,17 @@ static void gen_nop_hint(DisasContext *s, int val)
|
|||
case 1: /* yield */
|
||||
if (!parallel_cpus) {
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_YIELD;
|
||||
s->base.is_jmp = DISAS_YIELD;
|
||||
}
|
||||
break;
|
||||
case 3: /* wfi */
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_WFI;
|
||||
s->base.is_jmp = DISAS_WFI;
|
||||
break;
|
||||
case 2: /* wfe */
|
||||
if (!parallel_cpus) {
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_WFE;
|
||||
s->base.is_jmp = DISAS_WFE;
|
||||
}
|
||||
break;
|
||||
case 4: /* sev */
|
||||
|
@ -7654,13 +7654,13 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
return 1;
|
||||
}
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->is_jmp = DISAS_WFI;
|
||||
s->base.is_jmp = DISAS_WFI;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
gen_io_start();
|
||||
}
|
||||
|
||||
|
@ -7751,7 +7751,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
}
|
||||
|
||||
if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||
/* I/O operations must end the TB here (whether read or write) */
|
||||
gen_io_end();
|
||||
gen_lookup_tb(s);
|
||||
|
@ -8065,7 +8065,7 @@ static void gen_srs(DisasContext *s,
|
|||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_temp_free_i32(addr);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
|
||||
static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
|
@ -8153,7 +8153,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
/* setend */
|
||||
if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
|
||||
gen_helper_setend(cpu_env);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
return;
|
||||
} else if ((insn & 0x0fffff00) == 0x057ff000) {
|
||||
|
@ -9527,7 +9527,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
gen_helper_cpsr_write_eret(cpu_env, tmp);
|
||||
tcg_temp_free_i32(tmp);
|
||||
/* Must exit loop to check un-masked IRQs */
|
||||
s->is_jmp = DISAS_EXIT;
|
||||
s->base.is_jmp = DISAS_EXIT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -9565,7 +9565,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
/* swi */
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->svc_imm = extract32(insn, 0, 24);
|
||||
s->is_jmp = DISAS_SWI;
|
||||
s->base.is_jmp = DISAS_SWI;
|
||||
break;
|
||||
default:
|
||||
illegal_op:
|
||||
|
@ -11657,7 +11657,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
|||
ARCH(6);
|
||||
if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
|
||||
gen_helper_setend(cpu_env);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
s->base.is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
|
@ -11751,7 +11751,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
|||
/* swi */
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->svc_imm = extract32(insn, 0, 8);
|
||||
s->is_jmp = DISAS_SWI;
|
||||
s->base.is_jmp = DISAS_SWI;
|
||||
break;
|
||||
}
|
||||
/* generate a conditional jump to next instruction */
|
||||
|
@ -11824,35 +11824,14 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
||||
static int arm_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
CPUState *cs, int max_insns)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cs->env_ptr;
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
target_ulong pc_start;
|
||||
target_ulong next_page_start;
|
||||
int num_insns;
|
||||
int max_insns;
|
||||
bool end_of_page;
|
||||
|
||||
/* generate intermediate code */
|
||||
|
||||
/* The A64 decoder has its own top level loop, because it doesn't need
|
||||
* the A32/T32 complexity to do with conditional execution/IT blocks/etc.
|
||||
*/
|
||||
if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
|
||||
gen_intermediate_code_a64(cs, tb);
|
||||
return;
|
||||
}
|
||||
|
||||
pc_start = tb->pc;
|
||||
|
||||
dc->tb = tb;
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->pc = pc_start;
|
||||
dc->singlestep_enabled = cs->singlestep_enabled;
|
||||
dc->pc = dc->base.pc_first;
|
||||
dc->condjmp = 0;
|
||||
|
||||
dc->aarch64 = 0;
|
||||
|
@ -11861,23 +11840,23 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
*/
|
||||
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
!arm_el_is_aa64(env, 3);
|
||||
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
|
||||
dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
|
||||
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
|
||||
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
|
||||
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
|
||||
dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags);
|
||||
dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags);
|
||||
dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1;
|
||||
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4;
|
||||
dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
|
||||
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
dc->user = (dc->current_el == 0);
|
||||
#endif
|
||||
dc->ns = ARM_TBFLAG_NS(tb->flags);
|
||||
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
|
||||
dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
|
||||
dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
|
||||
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
|
||||
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
|
||||
dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(tb->flags);
|
||||
dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags);
|
||||
dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
|
||||
dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags);
|
||||
dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags);
|
||||
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
|
||||
dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
|
||||
dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
|
||||
dc->cp_regs = cpu->cp_regs;
|
||||
dc->features = env->features;
|
||||
|
||||
|
@ -11896,11 +11875,26 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
* emit code to generate a software step exception
|
||||
* end the TB
|
||||
*/
|
||||
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
|
||||
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
|
||||
dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
|
||||
dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
|
||||
dc->is_ldex = false;
|
||||
dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
|
||||
|
||||
dc->next_page_start =
|
||||
(dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
|
||||
/* If architectural single step active, limit to 1. */
|
||||
if (is_singlestepping(dc)) {
|
||||
max_insns = 1;
|
||||
}
|
||||
|
||||
/* ARM is a fixed-length ISA. Bound the number of insns to execute
|
||||
to those left on the page. */
|
||||
if (!dc->thumb) {
|
||||
int bound = (dc->next_page_start - dc->base.pc_first) / 4;
|
||||
max_insns = MIN(max_insns, bound);
|
||||
}
|
||||
|
||||
cpu_F0s = tcg_temp_new_i32();
|
||||
cpu_F1s = tcg_temp_new_i32();
|
||||
cpu_F0d = tcg_temp_new_i64();
|
||||
|
@ -11909,19 +11903,13 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
cpu_V1 = cpu_F1d;
|
||||
/* FIXME: cpu_M0 can probably be the same as cpu_V0. */
|
||||
cpu_M0 = tcg_temp_new_i64();
|
||||
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
num_insns = 0;
|
||||
max_insns = tb->cflags & CF_COUNT_MASK;
|
||||
if (max_insns == 0) {
|
||||
max_insns = CF_COUNT_MASK;
|
||||
}
|
||||
if (max_insns > TCG_MAX_INSNS) {
|
||||
max_insns = TCG_MAX_INSNS;
|
||||
}
|
||||
|
||||
gen_tb_start(tb);
|
||||
return max_insns;
|
||||
}
|
||||
|
||||
tcg_clear_temp_count();
|
||||
static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
/* A note on handling of the condexec (IT) bits:
|
||||
*
|
||||
|
@ -11955,141 +11943,173 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
|
||||
/* Reset the conditional execution bits immediately. This avoids
|
||||
complications trying to do it at the end of the block. */
|
||||
if (dc->condexec_mask || dc->condexec_cond)
|
||||
{
|
||||
if (dc->condexec_mask || dc->condexec_cond) {
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, 0);
|
||||
store_cpu_field(tmp, condexec_bits);
|
||||
}
|
||||
do {
|
||||
dc->insn_start_idx = tcg_op_buf_count();
|
||||
tcg_gen_insn_start(dc->pc,
|
||||
(dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
|
||||
0);
|
||||
num_insns++;
|
||||
}
|
||||
tcg_clear_temp_count();
|
||||
}
|
||||
|
||||
static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
dc->insn_start_idx = tcg_op_buf_count();
|
||||
tcg_gen_insn_start(dc->pc,
|
||||
(dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
|
||||
0);
|
||||
}
|
||||
|
||||
static bool arm_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
|
||||
const CPUBreakpoint *bp)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (bp->flags & BP_CPU) {
|
||||
gen_set_condexec(dc);
|
||||
gen_set_pc_im(dc, dc->pc);
|
||||
gen_helper_check_breakpoints(cpu_env);
|
||||
/* End the TB early; it's likely not going to be executed */
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
} else {
|
||||
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
|
||||
/* The address covered by the breakpoint must be
|
||||
included in [tb->pc, tb->pc + tb->size) in order
|
||||
to for it to be properly cleared -- thus we
|
||||
increment the PC here so that the logic setting
|
||||
tb->size below does the right thing. */
|
||||
/* TODO: Advance PC by correct instruction length to
|
||||
* avoid disassembler error messages */
|
||||
dc->pc += 2;
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool arm_pre_translate_insn(DisasContext *dc)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* Intercept jump to the magic kernel page. */
|
||||
if (dc->pc >= 0xffff0000) {
|
||||
/* We always get here via a jump, so know we are not in a
|
||||
conditional execution block. */
|
||||
gen_exception_internal(EXCP_KERNEL_TRAP);
|
||||
dc->is_jmp = DISAS_EXC;
|
||||
break;
|
||||
}
|
||||
/* Intercept jump to the magic kernel page. */
|
||||
if (dc->pc >= 0xffff0000) {
|
||||
/* We always get here via a jump, so know we are not in a
|
||||
conditional execution block. */
|
||||
gen_exception_internal(EXCP_KERNEL_TRAP);
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
|
||||
CPUBreakpoint *bp;
|
||||
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
|
||||
if (bp->pc == dc->pc) {
|
||||
if (bp->flags & BP_CPU) {
|
||||
gen_set_condexec(dc);
|
||||
gen_set_pc_im(dc, dc->pc);
|
||||
gen_helper_check_breakpoints(cpu_env);
|
||||
/* End the TB early; it's likely not going to be executed */
|
||||
dc->is_jmp = DISAS_UPDATE;
|
||||
} else {
|
||||
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
|
||||
/* The address covered by the breakpoint must be
|
||||
included in [tb->pc, tb->pc + tb->size) in order
|
||||
to for it to be properly cleared -- thus we
|
||||
increment the PC here so that the logic setting
|
||||
tb->size below does the right thing. */
|
||||
/* TODO: Advance PC by correct instruction length to
|
||||
* avoid disassembler error messages */
|
||||
dc->pc += 2;
|
||||
goto done_generating;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
|
||||
gen_io_start();
|
||||
}
|
||||
|
||||
if (dc->ss_active && !dc->pstate_ss) {
|
||||
/* Singlestep state is Active-pending.
|
||||
* If we're in this state at the start of a TB then either
|
||||
* a) we just took an exception to an EL which is being debugged
|
||||
* and this is the first insn in the exception handler
|
||||
* b) debug exceptions were masked and we just unmasked them
|
||||
* without changing EL (eg by clearing PSTATE.D)
|
||||
* In either case we're going to take a swstep exception in the
|
||||
* "did not step an insn" case, and so the syndrome ISV and EX
|
||||
* bits should be zero.
|
||||
*/
|
||||
assert(num_insns == 1);
|
||||
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
|
||||
default_exception_el(dc));
|
||||
goto done_generating;
|
||||
}
|
||||
|
||||
if (dc->thumb) {
|
||||
disas_thumb_insn(env, dc);
|
||||
if (dc->condexec_mask) {
|
||||
dc->condexec_cond = (dc->condexec_cond & 0xe)
|
||||
| ((dc->condexec_mask >> 4) & 1);
|
||||
dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
|
||||
if (dc->condexec_mask == 0) {
|
||||
dc->condexec_cond = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
|
||||
dc->pc += 4;
|
||||
disas_arm_insn(dc, insn);
|
||||
}
|
||||
|
||||
if (dc->condjmp && !dc->is_jmp) {
|
||||
gen_set_label(dc->condlabel);
|
||||
dc->condjmp = 0;
|
||||
}
|
||||
|
||||
if (tcg_check_temp_count()) {
|
||||
fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
|
||||
dc->pc);
|
||||
}
|
||||
|
||||
/* Translation stops when a conditional branch is encountered.
|
||||
* Otherwise the subsequent code could get translated several times.
|
||||
* Also stop translation when a page boundary is reached. This
|
||||
* ensures prefetch aborts occur at the right place. */
|
||||
|
||||
/* We want to stop the TB if the next insn starts in a new page,
|
||||
* or if it spans between this page and the next. This means that
|
||||
* if we're looking at the last halfword in the page we need to
|
||||
* see if it's a 16-bit Thumb insn (which will fit in this TB)
|
||||
* or a 32-bit Thumb insn (which won't).
|
||||
* This is to avoid generating a silly TB with a single 16-bit insn
|
||||
* in it at the end of this page (which would execute correctly
|
||||
* but isn't very efficient).
|
||||
if (dc->ss_active && !dc->pstate_ss) {
|
||||
/* Singlestep state is Active-pending.
|
||||
* If we're in this state at the start of a TB then either
|
||||
* a) we just took an exception to an EL which is being debugged
|
||||
* and this is the first insn in the exception handler
|
||||
* b) debug exceptions were masked and we just unmasked them
|
||||
* without changing EL (eg by clearing PSTATE.D)
|
||||
* In either case we're going to take a swstep exception in the
|
||||
* "did not step an insn" case, and so the syndrome ISV and EX
|
||||
* bits should be zero.
|
||||
*/
|
||||
end_of_page = (dc->pc >= next_page_start) ||
|
||||
((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));
|
||||
assert(dc->base.num_insns == 1);
|
||||
gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
|
||||
default_exception_el(dc));
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
} while (!dc->is_jmp && !tcg_op_buf_full() &&
|
||||
!is_singlestepping(dc) &&
|
||||
!singlestep &&
|
||||
!end_of_page &&
|
||||
num_insns < max_insns);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tb->cflags & CF_LAST_IO) {
|
||||
if (dc->condjmp) {
|
||||
/* FIXME: This can theoretically happen with self-modifying
|
||||
code. */
|
||||
cpu_abort(cs, "IO on conditional branch instruction");
|
||||
static void arm_post_translate_insn(DisasContext *dc)
|
||||
{
|
||||
if (dc->condjmp && !dc->base.is_jmp) {
|
||||
gen_set_label(dc->condlabel);
|
||||
dc->condjmp = 0;
|
||||
}
|
||||
dc->base.pc_next = dc->pc;
|
||||
translator_loop_temp_check(&dc->base);
|
||||
}
|
||||
|
||||
static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
unsigned int insn;
|
||||
|
||||
if (arm_pre_translate_insn(dc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
|
||||
dc->pc += 4;
|
||||
disas_arm_insn(dc, insn);
|
||||
|
||||
arm_post_translate_insn(dc);
|
||||
|
||||
/* ARM is a fixed-length ISA. We performed the cross-page check
|
||||
in init_disas_context by adjusting max_insns. */
|
||||
}
|
||||
|
||||
static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
|
||||
if (arm_pre_translate_insn(dc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
disas_thumb_insn(env, dc);
|
||||
|
||||
/* Advance the Thumb condexec condition. */
|
||||
if (dc->condexec_mask) {
|
||||
dc->condexec_cond = ((dc->condexec_cond & 0xe) |
|
||||
((dc->condexec_mask >> 4) & 1));
|
||||
dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
|
||||
if (dc->condexec_mask == 0) {
|
||||
dc->condexec_cond = 0;
|
||||
}
|
||||
gen_io_end();
|
||||
}
|
||||
|
||||
arm_post_translate_insn(dc);
|
||||
|
||||
/* Thumb is a variable-length ISA. Stop translation when the next insn
|
||||
* will touch a new page. This ensures that prefetch aborts occur at
|
||||
* the right place.
|
||||
*
|
||||
* We want to stop the TB if the next insn starts in a new page,
|
||||
* or if it spans between this page and the next. This means that
|
||||
* if we're looking at the last halfword in the page we need to
|
||||
* see if it's a 16-bit Thumb insn (which will fit in this TB)
|
||||
* or a 32-bit Thumb insn (which won't).
|
||||
* This is to avoid generating a silly TB with a single 16-bit insn
|
||||
* in it at the end of this page (which would execute correctly
|
||||
* but isn't very efficient).
|
||||
*/
|
||||
if (dc->base.is_jmp == DISAS_NEXT
|
||||
&& (dc->pc >= dc->next_page_start
|
||||
|| (dc->pc >= dc->next_page_start - 3
|
||||
&& insn_crosses_page(env, dc)))) {
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (dc->base.tb->cflags & CF_LAST_IO && dc->condjmp) {
|
||||
/* FIXME: This can theoretically happen with self-modifying code. */
|
||||
cpu_abort(cpu, "IO on conditional branch instruction");
|
||||
}
|
||||
|
||||
/* At this stage dc->condjmp will only be set when the skipped
|
||||
instruction was a conditional branch or trap, and the PC has
|
||||
already been written. */
|
||||
gen_set_condexec(dc);
|
||||
if (dc->is_jmp == DISAS_BX_EXCRET) {
|
||||
if (dc->base.is_jmp == DISAS_BX_EXCRET) {
|
||||
/* Exception return branches need some special case code at the
|
||||
* end of the TB, which is complex enough that it has to
|
||||
* handle the single-step vs not and the condition-failed
|
||||
|
@ -12098,7 +12118,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
gen_bx_excret_final_code(dc);
|
||||
} else if (unlikely(is_singlestepping(dc))) {
|
||||
/* Unconditional and "condition passed" instruction codepath. */
|
||||
switch (dc->is_jmp) {
|
||||
switch (dc->base.is_jmp) {
|
||||
case DISAS_SWI:
|
||||
gen_ss_advance(dc);
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
|
||||
|
@ -12113,12 +12133,16 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
|
||||
break;
|
||||
case DISAS_NEXT:
|
||||
case DISAS_TOO_MANY:
|
||||
case DISAS_UPDATE:
|
||||
gen_set_pc_im(dc, dc->pc);
|
||||
/* fall through */
|
||||
default:
|
||||
/* FIXME: Single stepping a WFI insn will not halt the CPU. */
|
||||
gen_singlestep_exception(dc);
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* While branches must always occur at the end of an IT block,
|
||||
|
@ -12129,8 +12153,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
- Hardware watchpoints.
|
||||
Hardware breakpoints have already been handled and skip this code.
|
||||
*/
|
||||
switch(dc->is_jmp) {
|
||||
switch(dc->base.is_jmp) {
|
||||
case DISAS_NEXT:
|
||||
case DISAS_TOO_MANY:
|
||||
gen_goto_tb(dc, 1, dc->pc);
|
||||
break;
|
||||
case DISAS_JUMP:
|
||||
|
@ -12143,8 +12168,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
/* indicate that the hash table must be used to find the next TB */
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case DISAS_TB_JUMP:
|
||||
case DISAS_EXC:
|
||||
case DISAS_NORETURN:
|
||||
/* nothing more to generate */
|
||||
break;
|
||||
case DISAS_WFI:
|
||||
|
@ -12185,23 +12209,55 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
}
|
||||
}
|
||||
|
||||
done_generating:
|
||||
gen_tb_end(tb, num_insns);
|
||||
/* Functions above can change dc->pc, so re-align db->pc_next */
|
||||
dc->base.pc_next = dc->pc;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
|
||||
qemu_log_in_addr_range(pc_start)) {
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start,
|
||||
dc->thumb | (dc->sctlr_b << 1));
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
static void arm_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size,
|
||||
dc->thumb | (dc->sctlr_b << 1));
|
||||
}
|
||||
|
||||
static const TranslatorOps arm_translator_ops = {
|
||||
.init_disas_context = arm_tr_init_disas_context,
|
||||
.tb_start = arm_tr_tb_start,
|
||||
.insn_start = arm_tr_insn_start,
|
||||
.breakpoint_check = arm_tr_breakpoint_check,
|
||||
.translate_insn = arm_tr_translate_insn,
|
||||
.tb_stop = arm_tr_tb_stop,
|
||||
.disas_log = arm_tr_disas_log,
|
||||
};
|
||||
|
||||
static const TranslatorOps thumb_translator_ops = {
|
||||
.init_disas_context = arm_tr_init_disas_context,
|
||||
.tb_start = arm_tr_tb_start,
|
||||
.insn_start = arm_tr_insn_start,
|
||||
.breakpoint_check = arm_tr_breakpoint_check,
|
||||
.translate_insn = thumb_tr_translate_insn,
|
||||
.tb_stop = arm_tr_tb_stop,
|
||||
.disas_log = arm_tr_disas_log,
|
||||
};
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
|
||||
{
|
||||
DisasContext dc;
|
||||
const TranslatorOps *ops = &arm_translator_ops;
|
||||
|
||||
if (ARM_TBFLAG_THUMB(tb->flags)) {
|
||||
ops = &thumb_translator_ops;
|
||||
}
|
||||
#ifdef TARGET_AARCH64
|
||||
if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
|
||||
ops = &aarch64_translator_ops;
|
||||
}
|
||||
#endif
|
||||
tb->size = dc->pc - pc_start;
|
||||
tb->icount = num_insns;
|
||||
|
||||
translator_loop(ops, &dc.base, cpu, tb);
|
||||
}
|
||||
|
||||
static const char *cpu_mode_names[16] = {
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
#ifndef TARGET_ARM_TRANSLATE_H
|
||||
#define TARGET_ARM_TRANSLATE_H
|
||||
|
||||
#include "exec/translator.h"
|
||||
|
||||
|
||||
/* internal defines */
|
||||
typedef struct DisasContext {
|
||||
DisasContextBase base;
|
||||
|
||||
target_ulong pc;
|
||||
target_ulong next_page_start;
|
||||
uint32_t insn;
|
||||
int is_jmp;
|
||||
/* Nonzero if this instruction has been conditionally skipped. */
|
||||
int condjmp;
|
||||
/* The label that will be jumped to when the instruction is skipped. */
|
||||
|
@ -13,8 +18,6 @@ typedef struct DisasContext {
|
|||
/* Thumb-2 conditional execution bits. */
|
||||
int condexec_mask;
|
||||
int condexec_cond;
|
||||
struct TranslationBlock *tb;
|
||||
int singlestep_enabled;
|
||||
int thumb;
|
||||
int sctlr_b;
|
||||
TCGMemOp be_data;
|
||||
|
@ -119,49 +122,43 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
|
|||
s->insn_start_idx = 0;
|
||||
}
|
||||
|
||||
/* target-specific extra values for is_jmp */
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
/* These instructions trap after executing, so the A32/T32 decoder must
|
||||
* defer them until after the conditional execution state has been updated.
|
||||
* WFI also needs special handling when single-stepping.
|
||||
*/
|
||||
#define DISAS_WFI 4
|
||||
#define DISAS_SWI 5
|
||||
/* For instructions which unconditionally cause an exception we can skip
|
||||
* emitting unreachable code at the end of the TB in the A64 decoder
|
||||
*/
|
||||
#define DISAS_EXC 6
|
||||
#define DISAS_WFI DISAS_TARGET_2
|
||||
#define DISAS_SWI DISAS_TARGET_3
|
||||
/* WFE */
|
||||
#define DISAS_WFE 7
|
||||
#define DISAS_HVC 8
|
||||
#define DISAS_SMC 9
|
||||
#define DISAS_YIELD 10
|
||||
#define DISAS_WFE DISAS_TARGET_4
|
||||
#define DISAS_HVC DISAS_TARGET_5
|
||||
#define DISAS_SMC DISAS_TARGET_6
|
||||
#define DISAS_YIELD DISAS_TARGET_7
|
||||
/* M profile branch which might be an exception return (and so needs
|
||||
* custom end-of-TB code)
|
||||
*/
|
||||
#define DISAS_BX_EXCRET 11
|
||||
#define DISAS_BX_EXCRET DISAS_TARGET_8
|
||||
/* For instructions which want an immediate exit to the main loop,
|
||||
* as opposed to attempting to use lookup_and_goto_ptr. Unlike
|
||||
* DISAS_UPDATE this doesn't write the PC on exiting the translation
|
||||
* loop so you need to ensure something (gen_a64_set_pc_im or runtime
|
||||
* helper) has done so before we reach return from cpu_tb_exec.
|
||||
*/
|
||||
#define DISAS_EXIT 12
|
||||
#define DISAS_EXIT DISAS_TARGET_9
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
void a64_translate_init(void);
|
||||
void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb);
|
||||
void gen_a64_set_pc_im(uint64_t val);
|
||||
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags);
|
||||
extern const TranslatorOps aarch64_translator_ops;
|
||||
#else
|
||||
static inline void a64_translate_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void gen_a64_set_pc_im(uint64_t val)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "mmu.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
#include "crisv32-decode.h"
|
||||
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -50,7 +51,11 @@
|
|||
#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
|
||||
#define BUG_ON(x) ({if (x) BUG();})
|
||||
|
||||
#define DISAS_SWI 5
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
#define DISAS_SWI DISAS_TARGET_3
|
||||
|
||||
/* Used by the decoder. */
|
||||
#define EXTRACT_FIELD(src, start, end) \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "exec/exec-all.h"
|
||||
#include "tcg-op.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -31,7 +32,6 @@
|
|||
#include "trace-tcg.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
|
||||
#define PREFIX_REPZ 0x01
|
||||
#define PREFIX_REPNZ 0x02
|
||||
#define PREFIX_LOCK 0x04
|
||||
|
@ -95,6 +95,8 @@ static int x86_64_hregs;
|
|||
#endif
|
||||
|
||||
typedef struct DisasContext {
|
||||
DisasContextBase base;
|
||||
|
||||
/* current insn context */
|
||||
int override; /* -1 if no override */
|
||||
int prefix;
|
||||
|
@ -102,8 +104,6 @@ typedef struct DisasContext {
|
|||
TCGMemOp dflag;
|
||||
target_ulong pc_start;
|
||||
target_ulong pc; /* pc = eip + cs_base */
|
||||
int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
|
||||
static state change (stop translation) */
|
||||
/* current block context */
|
||||
target_ulong cs_base; /* base of CS segment */
|
||||
int pe; /* protected mode */
|
||||
|
@ -124,12 +124,10 @@ typedef struct DisasContext {
|
|||
int cpl;
|
||||
int iopl;
|
||||
int tf; /* TF cpu flag */
|
||||
int singlestep_enabled; /* "hardware" single step enabled */
|
||||
int jmp_opt; /* use direct block chaining for direct jumps */
|
||||
int repz_opt; /* optimize jumps within repz instructions */
|
||||
int mem_index; /* select memory access functions */
|
||||
uint64_t flags; /* all execution flags */
|
||||
struct TranslationBlock *tb;
|
||||
int popl_esp_hack; /* for correct popl with esp base handling */
|
||||
int rip_offset; /* only used in x86_64, but left for simplicity */
|
||||
int cpuid_features;
|
||||
|
@ -1119,7 +1117,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
|
|||
|
||||
static inline void gen_ins(DisasContext *s, TCGMemOp ot)
|
||||
{
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_string_movl_A0_EDI(s);
|
||||
|
@ -1134,14 +1132,14 @@ static inline void gen_ins(DisasContext *s, TCGMemOp ot)
|
|||
gen_op_movl_T0_Dshift(ot);
|
||||
gen_op_add_reg_T0(s->aflag, R_EDI);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_outs(DisasContext *s, TCGMemOp ot)
|
||||
{
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_string_movl_A0_ESI(s);
|
||||
|
@ -1154,7 +1152,7 @@ static inline void gen_outs(DisasContext *s, TCGMemOp ot)
|
|||
gen_op_movl_T0_Dshift(ot);
|
||||
gen_op_add_reg_T0(s->aflag, R_ESI);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
}
|
||||
}
|
||||
|
@ -2137,7 +2135,7 @@ static inline int insn_const_size(TCGMemOp ot)
|
|||
static inline bool use_goto_tb(DisasContext *s, target_ulong pc)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) ||
|
||||
return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) ||
|
||||
(pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK);
|
||||
#else
|
||||
return true;
|
||||
|
@ -2152,7 +2150,8 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
|
|||
/* jump to same page: we can use a direct jump */
|
||||
tcg_gen_goto_tb(tb_num);
|
||||
gen_jmp_im(eip);
|
||||
tcg_gen_exit_tb((uintptr_t)s->tb + tb_num);
|
||||
tcg_gen_exit_tb((uintptr_t)s->base.tb + tb_num);
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
/* jump to another page */
|
||||
gen_jmp_im(eip);
|
||||
|
@ -2173,7 +2172,6 @@ static inline void gen_jcc(DisasContext *s, int b,
|
|||
|
||||
gen_set_label(l1);
|
||||
gen_goto_tb(s, 1, val);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
} else {
|
||||
l1 = gen_new_label();
|
||||
l2 = gen_new_label();
|
||||
|
@ -2243,12 +2241,14 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
|
|||
because ss32 may change. For R_SS, translation must always
|
||||
stop as a special handling must be done to disable hardware
|
||||
interrupts for the next instruction */
|
||||
if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) {
|
||||
s->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
} else {
|
||||
gen_op_movl_seg_T0_vm(seg_reg);
|
||||
if (seg_reg == R_SS)
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
if (seg_reg == R_SS) {
|
||||
s->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2420,7 +2420,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
|
|||
gen_update_cc_op(s);
|
||||
gen_jmp_im(cur_eip);
|
||||
gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
/* Generate #UD for the current instruction. The assumption here is that
|
||||
|
@ -2458,7 +2458,7 @@ static void gen_interrupt(DisasContext *s, int intno,
|
|||
gen_jmp_im(cur_eip);
|
||||
gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
|
||||
tcg_const_i32(next_eip - cur_eip));
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_debug(DisasContext *s, target_ulong cur_eip)
|
||||
|
@ -2466,7 +2466,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
|
|||
gen_update_cc_op(s);
|
||||
gen_jmp_im(cur_eip);
|
||||
gen_helper_debug(cpu_env);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_set_hflag(DisasContext *s, uint32_t mask)
|
||||
|
@ -2522,10 +2522,10 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
|
|||
gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
|
||||
}
|
||||
|
||||
if (s->tb->flags & HF_RF_MASK) {
|
||||
if (s->base.tb->flags & HF_RF_MASK) {
|
||||
gen_helper_reset_rf(cpu_env);
|
||||
}
|
||||
if (s->singlestep_enabled) {
|
||||
if (s->base.singlestep_enabled) {
|
||||
gen_helper_debug(cpu_env);
|
||||
} else if (recheck_tf) {
|
||||
gen_helper_rechecking_single_step(cpu_env);
|
||||
|
@ -2541,7 +2541,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, TCGv jr)
|
|||
} else {
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -2580,7 +2580,6 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
|
|||
set_cc_op(s, CC_OP_DYNAMIC);
|
||||
if (s->jmp_opt) {
|
||||
gen_goto_tb(s, tb_num, eip);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
} else {
|
||||
gen_jmp_im(eip);
|
||||
gen_eob(s);
|
||||
|
@ -4416,17 +4415,18 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||
}
|
||||
}
|
||||
|
||||
/* convert one instruction. s->is_jmp is set if the translation must
|
||||
/* convert one instruction. s->base.is_jmp is set if the translation must
|
||||
be stopped. Return the next pc value */
|
||||
static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
target_ulong pc_start)
|
||||
static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
||||
{
|
||||
CPUX86State *env = cpu->env_ptr;
|
||||
int b, prefixes;
|
||||
int shift;
|
||||
TCGMemOp ot, aflag, dflag;
|
||||
int modrm, reg, rm, mod, op, opreg, val;
|
||||
target_ulong next_eip, tval;
|
||||
int rex_w, rex_r;
|
||||
target_ulong pc_start = s->base.pc_next;
|
||||
|
||||
s->pc_start = s->pc = pc_start;
|
||||
prefixes = 0;
|
||||
|
@ -5376,7 +5376,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_movl_seg_T0(s, reg);
|
||||
gen_pop_update(s, ot);
|
||||
/* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
|
||||
if (s->is_jmp) {
|
||||
if (s->base.is_jmp) {
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
if (reg == R_SS) {
|
||||
s->tf = 0;
|
||||
|
@ -5391,7 +5391,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
ot = gen_pop_T0(s);
|
||||
gen_movl_seg_T0(s, (b >> 3) & 7);
|
||||
gen_pop_update(s, ot);
|
||||
if (s->is_jmp) {
|
||||
if (s->base.is_jmp) {
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
|
@ -5442,7 +5442,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
|
||||
gen_movl_seg_T0(s, reg);
|
||||
/* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
|
||||
if (s->is_jmp) {
|
||||
if (s->base.is_jmp) {
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
if (reg == R_SS) {
|
||||
s->tf = 0;
|
||||
|
@ -5651,7 +5651,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_movl_seg_T0(s, op);
|
||||
/* then put the data */
|
||||
gen_op_mov_reg_v(ot, reg, cpu_T1);
|
||||
if (s->is_jmp) {
|
||||
if (s->base.is_jmp) {
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
|
@ -6307,7 +6307,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
||||
} else {
|
||||
gen_ins(s, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
}
|
||||
|
@ -6322,7 +6322,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
||||
} else {
|
||||
gen_outs(s, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
}
|
||||
|
@ -6338,14 +6338,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_movi_tl(cpu_T0, val);
|
||||
gen_check_io(s, ot, pc_start - s->cs_base,
|
||||
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
tcg_gen_movi_i32(cpu_tmp2_i32, val);
|
||||
gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
|
||||
gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
|
@ -6359,14 +6359,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
svm_is_rep(prefixes));
|
||||
gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
|
||||
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
tcg_gen_movi_i32(cpu_tmp2_i32, val);
|
||||
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
|
||||
gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
|
@ -6377,14 +6377,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
tcg_gen_ext16u_tl(cpu_T0, cpu_regs[R_EDX]);
|
||||
gen_check_io(s, ot, pc_start - s->cs_base,
|
||||
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
|
||||
gen_helper_in_func(ot, cpu_T1, cpu_tmp2_i32);
|
||||
gen_op_mov_reg_v(ot, R_EAX, cpu_T1);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
|
@ -6397,14 +6397,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
svm_is_rep(prefixes));
|
||||
gen_op_mov_v_reg(ot, cpu_T1, R_EAX);
|
||||
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T0);
|
||||
tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T1);
|
||||
gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
|
||||
gen_bpt_io(s, cpu_tmp2_i32, ot);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
|
@ -6943,7 +6943,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_update_cc_op(s);
|
||||
gen_jmp_im(pc_start - s->cs_base);
|
||||
gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
break;
|
||||
case 0x9b: /* fwait */
|
||||
|
@ -7112,11 +7112,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
case 0x131: /* rdtsc */
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(pc_start - s->cs_base);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_rdtsc(cpu_env);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
|
@ -7188,7 +7188,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_update_cc_op(s);
|
||||
gen_jmp_im(pc_start - s->cs_base);
|
||||
gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
break;
|
||||
case 0x100:
|
||||
|
@ -7371,7 +7371,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
|
||||
tcg_const_i32(s->pc - pc_start));
|
||||
tcg_gen_exit_tb(0);
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
break;
|
||||
|
||||
case 0xd9: /* VMMCALL */
|
||||
|
@ -7571,11 +7571,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
}
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(pc_start - s->cs_base);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_rdtscp(cpu_env);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
gen_jmp(s, s->pc - s->cs_base);
|
||||
}
|
||||
|
@ -7940,24 +7940,24 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_update_cc_op(s);
|
||||
gen_jmp_im(pc_start - s->cs_base);
|
||||
if (b & 2) {
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_op_mov_v_reg(ot, cpu_T0, rm);
|
||||
gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
|
||||
cpu_T0);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
}
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
} else {
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_read_crN(cpu_T0, cpu_env, tcg_const_i32(reg));
|
||||
gen_op_mov_reg_v(ot, rm, cpu_T0);
|
||||
if (s->tb->cflags & CF_USE_ICOUNT) {
|
||||
if (s->base.tb->cflags & CF_USE_ICOUNT) {
|
||||
gen_io_end();
|
||||
}
|
||||
}
|
||||
|
@ -8378,22 +8378,13 @@ void tcg_x86_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
||||
static int i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu,
|
||||
int max_insns)
|
||||
{
|
||||
CPUX86State *env = cs->env_ptr;
|
||||
DisasContext dc1, *dc = &dc1;
|
||||
target_ulong pc_ptr;
|
||||
uint32_t flags;
|
||||
target_ulong pc_start;
|
||||
target_ulong cs_base;
|
||||
int num_insns;
|
||||
int max_insns;
|
||||
|
||||
/* generate intermediate code */
|
||||
pc_start = tb->pc;
|
||||
cs_base = tb->cs_base;
|
||||
flags = tb->flags;
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUX86State *env = cpu->env_ptr;
|
||||
uint32_t flags = dc->base.tb->flags;
|
||||
target_ulong cs_base = dc->base.tb->cs_base;
|
||||
|
||||
dc->pe = (flags >> HF_PE_SHIFT) & 1;
|
||||
dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
|
||||
|
@ -8404,11 +8395,9 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
|
||||
dc->iopl = (flags >> IOPL_SHIFT) & 3;
|
||||
dc->tf = (flags >> TF_SHIFT) & 1;
|
||||
dc->singlestep_enabled = cs->singlestep_enabled;
|
||||
dc->cc_op = CC_OP_DYNAMIC;
|
||||
dc->cc_op_dirty = false;
|
||||
dc->cs_base = cs_base;
|
||||
dc->tb = tb;
|
||||
dc->popl_esp_hack = 0;
|
||||
/* select memory access functions */
|
||||
dc->mem_index = 0;
|
||||
|
@ -8426,7 +8415,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
|
||||
#endif
|
||||
dc->flags = flags;
|
||||
dc->jmp_opt = !(dc->tf || cs->singlestep_enabled ||
|
||||
dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
|
||||
(flags & HF_INHIBIT_IRQ_MASK));
|
||||
/* Do not optimize repz jumps at all in icount mode, because
|
||||
rep movsS instructions are execured with different paths
|
||||
|
@ -8438,7 +8427,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
record/replay modes and there will always be an
|
||||
additional step for ecx=0 when icount is enabled.
|
||||
*/
|
||||
dc->repz_opt = !dc->jmp_opt && !(tb->cflags & CF_USE_ICOUNT);
|
||||
dc->repz_opt = !dc->jmp_opt && !(dc->base.tb->cflags & CF_USE_ICOUNT);
|
||||
#if 0
|
||||
/* check addseg logic */
|
||||
if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
|
||||
|
@ -8458,107 +8447,112 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
|
|||
cpu_ptr1 = tcg_temp_new_ptr();
|
||||
cpu_cc_srcT = tcg_temp_local_new();
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
pc_ptr = pc_start;
|
||||
num_insns = 0;
|
||||
max_insns = tb->cflags & CF_COUNT_MASK;
|
||||
if (max_insns == 0) {
|
||||
max_insns = CF_COUNT_MASK;
|
||||
}
|
||||
if (max_insns > TCG_MAX_INSNS) {
|
||||
max_insns = TCG_MAX_INSNS;
|
||||
return max_insns;
|
||||
}
|
||||
|
||||
static void i386_tr_tb_start(DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
|
||||
}
|
||||
|
||||
static bool i386_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
|
||||
const CPUBreakpoint *bp)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
/* If RF is set, suppress an internally generated breakpoint. */
|
||||
int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY;
|
||||
if (bp->flags & flags) {
|
||||
gen_debug(dc, dc->base.pc_next - dc->cs_base);
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
/* The address covered by the breakpoint must be included in
|
||||
[tb->pc, tb->pc + tb->size) in order to for it to be
|
||||
properly cleared -- thus we increment the PC here so that
|
||||
the generic logic setting tb->size later does the right thing. */
|
||||
dc->base.pc_next += 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gen_tb_start(tb);
|
||||
for(;;) {
|
||||
tcg_gen_insn_start(pc_ptr, dc->cc_op);
|
||||
num_insns++;
|
||||
static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
target_ulong pc_next = disas_insn(dc, cpu);
|
||||
|
||||
/* If RF is set, suppress an internally generated breakpoint. */
|
||||
if (unlikely(cpu_breakpoint_test(cs, pc_ptr,
|
||||
tb->flags & HF_RF_MASK
|
||||
? BP_GDB : BP_ANY))) {
|
||||
gen_debug(dc, pc_ptr - dc->cs_base);
|
||||
/* The address covered by the breakpoint must be included in
|
||||
[tb->pc, tb->pc + tb->size) in order to for it to be
|
||||
properly cleared -- thus we increment the PC here so that
|
||||
the logic setting tb->size below does the right thing. */
|
||||
pc_ptr += 1;
|
||||
goto done_generating;
|
||||
}
|
||||
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
|
||||
gen_io_start();
|
||||
}
|
||||
|
||||
pc_ptr = disas_insn(env, dc, pc_ptr);
|
||||
/* stop translation if indicated */
|
||||
if (dc->is_jmp)
|
||||
break;
|
||||
if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
|
||||
/* if single step mode, we generate only one instruction and
|
||||
generate an exception */
|
||||
/* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
|
||||
the flag and abort the translation to give the irqs a
|
||||
change to be happen */
|
||||
if (dc->tf || dc->singlestep_enabled ||
|
||||
(flags & HF_INHIBIT_IRQ_MASK)) {
|
||||
gen_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
||||
}
|
||||
chance to happen */
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
} else if ((dc->base.tb->cflags & CF_USE_ICOUNT)
|
||||
&& ((dc->base.pc_next & TARGET_PAGE_MASK)
|
||||
!= ((dc->base.pc_next + TARGET_MAX_INSN_SIZE - 1)
|
||||
& TARGET_PAGE_MASK)
|
||||
|| (dc->base.pc_next & ~TARGET_PAGE_MASK) == 0)) {
|
||||
/* Do not cross the boundary of the pages in icount mode,
|
||||
it can cause an exception. Do it only when boundary is
|
||||
crossed by the first instruction in the block.
|
||||
If current instruction already crossed the bound - it's ok,
|
||||
because an exception hasn't stopped this code.
|
||||
*/
|
||||
if ((tb->cflags & CF_USE_ICOUNT)
|
||||
&& ((pc_ptr & TARGET_PAGE_MASK)
|
||||
!= ((pc_ptr + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
|
||||
|| (pc_ptr & ~TARGET_PAGE_MASK) == 0)) {
|
||||
gen_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
||||
}
|
||||
/* if too long translation, stop generation too */
|
||||
if (tcg_op_buf_full() ||
|
||||
(pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
|
||||
num_insns >= max_insns) {
|
||||
gen_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
||||
}
|
||||
if (singlestep) {
|
||||
gen_jmp_im(pc_ptr - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
break;
|
||||
}
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
} else if ((pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32)) {
|
||||
dc->base.is_jmp = DISAS_TOO_MANY;
|
||||
}
|
||||
if (tb->cflags & CF_LAST_IO)
|
||||
gen_io_end();
|
||||
done_generating:
|
||||
gen_tb_end(tb, num_insns);
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
&& qemu_log_in_addr_range(pc_start)) {
|
||||
int disas_flags;
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
dc->base.pc_next = pc_next;
|
||||
}
|
||||
|
||||
static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
if (dc->base.is_jmp == DISAS_TOO_MANY) {
|
||||
gen_jmp_im(dc->base.pc_next - dc->cs_base);
|
||||
gen_eob(dc);
|
||||
}
|
||||
}
|
||||
|
||||
static void i386_tr_disas_log(const DisasContextBase *dcbase,
|
||||
CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
int disas_flags = !dc->code32;
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
#ifdef TARGET_X86_64
|
||||
if (dc->code64)
|
||||
disas_flags = 2;
|
||||
else
|
||||
#endif
|
||||
disas_flags = !dc->code32;
|
||||
log_target_disas(cs, pc_start, pc_ptr - pc_start, disas_flags);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock();
|
||||
if (dc->code64) {
|
||||
disas_flags = 2;
|
||||
}
|
||||
#endif
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size, disas_flags);
|
||||
}
|
||||
|
||||
tb->size = pc_ptr - pc_start;
|
||||
tb->icount = num_insns;
|
||||
static const TranslatorOps i386_tr_ops = {
|
||||
.init_disas_context = i386_tr_init_disas_context,
|
||||
.tb_start = i386_tr_tb_start,
|
||||
.insn_start = i386_tr_insn_start,
|
||||
.breakpoint_check = i386_tr_breakpoint_check,
|
||||
.translate_insn = i386_tr_translate_insn,
|
||||
.tb_stop = i386_tr_tb_stop,
|
||||
.disas_log = i386_tr_disas_log,
|
||||
};
|
||||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
|
||||
{
|
||||
DisasContext dc;
|
||||
|
||||
translator_loop(&i386_tr_ops, &dc.base, cpu, tb);
|
||||
}
|
||||
|
||||
void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "disas/disas.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/translator.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
@ -47,6 +48,11 @@
|
|||
|
||||
#define MEM_INDEX 0
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
|
||||
static TCGv_env cpu_env;
|
||||
static TCGv cpu_R[32];
|
||||
static TCGv cpu_pc;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "tcg-op.h"
|
||||
#include "qemu/log.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -173,7 +174,11 @@ static void do_writebacks(DisasContext *s)
|
|||
}
|
||||
}
|
||||
|
||||
#define DISAS_JUMP_NEXT 4
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
#define DISAS_JUMP_NEXT DISAS_TARGET_3
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define IS_USER(s) 1
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "microblaze-decode.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/helper-gen.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "trace-tcg.h"
|
||||
#include "exec/log.h"
|
||||
|
@ -46,6 +47,11 @@
|
|||
#define EXTRACT_FIELD(src, start, end) \
|
||||
(((src) >> start) & ((1 << (end - start + 1)) - 1))
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
|
||||
static TCGv env_debug;
|
||||
static TCGv_env cpu_env;
|
||||
static TCGv cpu_R[32];
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
#include "exec/helper-gen.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
|
||||
#define INSTRUCTION_FLG(func, flags) { (func), (flags) }
|
||||
#define INSTRUCTION(func) \
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "qemu/log.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -37,6 +38,11 @@
|
|||
#define LOG_DIS(str, ...) \
|
||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, "%08x: " str, dc->pc, ## __VA_ARGS__)
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
|
||||
typedef struct DisasContext {
|
||||
TranslationBlock *tb;
|
||||
target_ulong pc;
|
||||
|
|
|
@ -77,7 +77,8 @@ typedef struct {
|
|||
} u;
|
||||
} DisasCompare;
|
||||
|
||||
#define DISAS_EXCP 4
|
||||
/* is_jmp field values */
|
||||
#define DISAS_EXCP DISAS_TARGET_0
|
||||
|
||||
#ifdef DEBUG_INLINE_BRANCHES
|
||||
static uint64_t inline_branch_hit[CC_OP_MAX];
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "tcg-op.h"
|
||||
#include "qemu/log.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -45,9 +46,13 @@ typedef struct DisasContext {
|
|||
#define IS_USER(s) 1
|
||||
#endif
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
|
||||
/* These instructions trap after executing, so defer them until after the
|
||||
conditional executions state has been updated. */
|
||||
#define DISAS_SYSCALL 5
|
||||
#define DISAS_SYSCALL DISAS_TARGET_3
|
||||
|
||||
static TCGv_env cpu_env;
|
||||
static TCGv_i32 cpu_R[32];
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "sysemu/sysemu.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -46,6 +47,9 @@
|
|||
#include "exec/log.h"
|
||||
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_UPDATE DISAS_TARGET_0 /* cpu state was modified dynamically */
|
||||
|
||||
typedef struct DisasContext {
|
||||
const XtensaConfig *config;
|
||||
TranslationBlock *tb;
|
||||
|
|
Loading…
Reference in a new issue