[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] translator mega-patch
From: |
Lluís Vilanova |
Subject: |
Re: [Qemu-devel] [PATCH] translator mega-patch |
Date: |
Sun, 18 Jun 2017 17:37:39 +0300 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/25.1 (gnu/linux) |
Emilio G Cota writes:
> On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova <address@hidden>
>> ---
>> include/exec/gen-icount.h | 2
>> include/exec/translate-all_template.h | 73 ++++++++++++
>> include/qom/cpu.h | 22 ++++
>> translate-all_template.h | 204
>> +++++++++++++++++++++++++++++++++
> I think this concept of "template" is quite painful.
> Find appended something that I find more palatable: it embeds
> DisasContextBase in DisasContext, so that we can have a standalone
> object with all generic code;
I don't get it. Isn't that what my series is already doing? Or do you mean
explicitly passing DisasContextBase to all the generic translator functions
below? I kind of dislike it every time I see container_of, and it makes type
checking from the compiler a bit more fragile.
> target-specific code is called via
> an "ops" struct with function pointers that targets fill in.
> The target-specific DisasContext struct can then be retrieved from
> the base struct with container_of().
I seem to remember we discussed this at some point before I sent the first
version, to allow multiple targets on the same binary, but decided against it.
Still, I can leave the ops struct in place without even trying to support
multiple targets. It should be a little bit slower (using function pointers
instead of a "template"), but I don't think performance will suffer that much
since we're at the translation path.
Any other opinions on this and the point above?
> I'll send as a separate, proper patch the gen-icount changes; really
> having cpu_env there as a global seems wrong to me.
That's an orthogonal issue that can he handled in a separate series.
Thanks!
Lluis
> What do you think?
> Emilio
> PS. Apply with `git am --scissors'.
> --- 8< ---
> Warning: INCOMPLETE, do not even think of merging!
> This is just to show an alternative approach to including C
> code from the target translators (ugh!). Only arm and aarch64
> have been converted.
> This applies on top of this series:
> https://lists.gnu.org/archive/html/qemu-devel/2017-06/msg02833.html
> Signed-off-by: Emilio G. Cota <address@hidden>
> ---
> Makefile.target | 2 +-
> include/exec/exec-all.h | 2 +-
> include/exec/gen-icount.h | 6 +-
> include/exec/translator.h | 74 +++++++++++++++++++
> target/arm/translate-a64.c | 130 ++++++++++++++++++----------------
> target/arm/translate.c | 173
> +++++++++++++++++++++++----------------------
> target/arm/translate.h | 11 +--
> translator.c | 170 ++++++++++++++++++++++++++++++++++++++++++++
> 8 files changed, 411 insertions(+), 157 deletions(-)
> create mode 100644 include/exec/translator.h
> create mode 100644 translator.c
> diff --git a/Makefile.target b/Makefile.target
> index ce8dfe4..ef2d538 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -88,7 +88,7 @@ all: $(PROGS) stap
> #########################################################
> # cpu emulator library
> -obj-y = exec.o translate-all.o cpu-exec.o
> +obj-y = exec.o translate-all.o cpu-exec.o translator.o
> obj-y += translate-common.o
> obj-y += cpu-exec-common.o
> obj-y += tcg/tcg.o tcg/tcg-op.o tcg/optimize.o
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 6ad31a8..d376546 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -22,6 +22,7 @@
> #include "qemu-common.h"
> #include "exec/tb-context.h"
> +#include "exec/translator.h"
> /* allow to see translation results - the slowdown should be negligible, so
> we leave it */
> #define DEBUG_DISAS
> @@ -37,7 +38,6 @@ typedef ram_addr_t tb_page_addr_t;
> /* is_jmp field values */
> /* TODO: delete after all targets are transitioned to generic translation */
> -#include "exec/translate-all_template.h"
> #define DISAS_NEXT DJ_NEXT /* next instruction can be analyzed
> */
> #define DISAS_JUMP (DJ_TARGET + 0) /* only pc was modified dynamically
> */
> #define DISAS_UPDATE (DJ_TARGET + 1) /* cpu state was modified
> dynamically */
> diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
> index 547c979..f4ad610 100644
> --- a/include/exec/gen-icount.h
> +++ b/include/exec/gen-icount.h
> @@ -8,7 +8,7 @@
> static int icount_start_insn_idx;
> static TCGLabel *exitreq_label;
> -static inline void gen_tb_start(TranslationBlock *tb)
> +static inline void gen_tb_start(TranslationBlock *tb, TCGv_env cpu_env)
> {
> TCGv_i32 count, imm;
> @@ -59,14 +59,14 @@ static inline void gen_tb_end(TranslationBlock *tb, int
> num_insns)
> tcg_ctx.gen_op_buf[tcg_ctx.gen_op_buf[0].prev].next = 0;
> }
> -static inline void gen_io_start(void)
> +static inline void gen_io_start(TCGv_env cpu_env)
> {
> TCGv_i32 tmp = tcg_const_i32(1);
> tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState,
> can_do_io));
> tcg_temp_free_i32(tmp);
> }
> -static inline void gen_io_end(void)
> +static inline void gen_io_end(TCGv_env cpu_env)
> {
> TCGv_i32 tmp = tcg_const_i32(0);
> tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState,
> can_do_io));
> diff --git a/include/exec/translator.h b/include/exec/translator.h
> new file mode 100644
> index 0000000..f2da424
> --- /dev/null
> +++ b/include/exec/translator.h
> @@ -0,0 +1,74 @@
> +#ifndef EXEC_TRANSLATOR_H
> +#define EXEC_TRANSLATOR_H
> +
> +#include "exec/exec-all.h"
> +#include "tcg.h"
> +
> +/**
> + * BreakpointHitType:
> + * @BH_MISS: No hit
> + * @BH_HIT_INSN: Hit, but continue translating instruction
> + * @BH_HIT_TB: Hit, stop translating TB
> + *
> + * How to react to a breakpoint hit.
> + */
> +typedef enum BreakpointHitType {
> + BH_MISS,
> + BH_HIT_INSN,
> + BH_HIT_TB,
> +} BreakpointHitType;
> +
> +/**
> + * DisasJumpType:
> + * @DJ_NEXT: Next instruction in program order
> + * @DJ_TOO_MANY: Too many instructions executed
> + * @DJ_TARGET: Start of target-specific conditions
> + *
> + * What instruction to disassemble next.
> + */
> +typedef enum DisasJumpType {
> + DJ_NEXT,
> + DJ_TOO_MANY,
> + DJ_TARGET,
> +} 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).
> + * @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 jmp_type;
> + unsigned int num_insns;
> + bool singlestep_enabled;
> +} DisasContextBase;
> +
> +/* all void-returning ops are optional, i.e. can be NULL */
> +struct translator_ops {
> + void (*init_context)(DisasContextBase *, CPUArchState *);
> + void (*init_globals)(DisasContextBase *, CPUArchState *);
> + void (*tb_start)(DisasContextBase *, CPUArchState *);
> + void (*insn_start)(DisasContextBase *, CPUArchState *);
> + BreakpointHitType (*breakpoint_hit)(DisasContextBase *, CPUArchState *,
> + const CPUBreakpoint *);
> + target_ulong (*disas_insn)(DisasContextBase *, CPUArchState *);
> + DisasJumpType (*stop_check)(DisasContextBase *, CPUArchState *);
> + void (*stop)(DisasContextBase *, CPUArchState *);
> + int (*disas_flags)(const DisasContextBase *);
> +};
> +
> +typedef struct translator_ops TranslatorOps;
> +
> +void translator_gen(const TranslatorOps *tr, DisasContextBase *base,
> + CPUState *cpu, TranslationBlock *tb, TCGv_env cpu_env);
> +
> +#endif /* EXEC_TRANSLATOR_H */
> diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
> index 508a016..c486d04 100644
> --- a/target/arm/translate-a64.c
> +++ b/target/arm/translate-a64.c
> @@ -1561,7 +1561,7 @@ static void handle_sys(DisasContext *s, uint32_t insn,
> bool isread,
> }
> if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
> - gen_io_start();
> + gen_io_start(cpu_env);
> }
> tcg_rt = cpu_reg(s, rt);
> @@ -1593,7 +1593,7 @@ static void handle_sys(DisasContext *s, uint32_t insn,
> bool isread,
> 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_io_end(cpu_env);
s-> base.jmp_type = DJ_UPDATE;
> } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
> /* We default to ending the TB on a coprocessor register write,
> @@ -11191,16 +11191,10 @@ static void disas_a64_insn(CPUARMState *env,
> DisasContext *s)
> free_tmp_a64(s);
> }
> -
> -
> -/* Use separate top-level templates for each architecture */
> -#define gen_intermediate_code gen_intermediate_code_aarch64
> -#include "translate-all_template.h"
> -#undef gen_intermediate_code
> -
> -static void gen_intermediate_code_target_init_disas_context(
> - DisasContext *dc, CPUArchState *env)
> +static void a64_tr_init_dc(DisasContextBase *base, CPUArchState *env)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
dc-> condjmp = 0;
dc-> aarch64 = 1;
> @@ -11211,17 +11205,17 @@ static void
> gen_intermediate_code_target_init_disas_context(
> !arm_el_is_aa64(env, 3);
dc-> thumb = 0;
dc-> sctlr_b = 0;
> - dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
> + dc->be_data = ARM_TBFLAG_BE_DATA(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(dc->base.tb->flags));
> - dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
> - dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
> + dc->mmu_idx = core_to_arm_mmu_idx(env,
> ARM_TBFLAG_MMUIDX(base->tb->flags));
> + dc->tbi0 = ARM_TBFLAG_TBI0(base->tb->flags);
> + dc->tbi1 = ARM_TBFLAG_TBI1(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(dc->base.tb->flags);
> + dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(base->tb->flags);
dc-> vec_len = 0;
dc-> vec_stride = 0;
dc-> cp_regs = arm_env_get_cpu(env)->cp_regs;
> @@ -11242,43 +11236,35 @@ static void
> gen_intermediate_code_target_init_disas_context(
> * emit code to generate a software step exception
> * end the TB
> */
> - dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
> - dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
> + dc->ss_active = ARM_TBFLAG_SS_ACTIVE(base->tb->flags);
> + dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(base->tb->flags);
dc-> is_ldex = false;
dc-> ss_same_el = (arm_debug_target_el(env) == dc->current_el);
> init_tmp_a64_array(dc);
dc-> next_page_start =
> - (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> -}
> -
> -static void gen_intermediate_code_target_init_globals(
> - DisasContext *dc, CPUArchState *env)
> -{
> + (base->pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> }
> -static void gen_intermediate_code_target_tb_start(
> - DisasContext *dc, CPUArchState *env)
> +static void a64_tr_insn_start(DisasContextBase *base, CPUArchState *env)
> {
> -}
> + DisasContext *dc = container_of(base, DisasContext, base);
> -static void gen_intermediate_code_target_insn_start(
> - DisasContext *dc, CPUArchState *env)
> -{
dc-> insn_start_idx = tcg_op_buf_count();
> - tcg_gen_insn_start(dc->base.pc_next, 0, 0);
> + tcg_gen_insn_start(base->pc_next, 0, 0);
> }
> -static BreakpointHitType gen_intermediate_code_target_breakpoint_hit(
> - DisasContext *dc, CPUArchState *env,
> - const CPUBreakpoint *bp)
> +static BreakpointHitType
> +a64_tr_bp_hit(DisasContextBase *b, CPUArchState *env, const CPUBreakpoint
> *bp)
> {
> + DisasContext *dc = container_of(b, DisasContext, base);
> +
> if (bp->flags & BP_CPU) {
> - gen_a64_set_pc_im(dc->base.pc_next);
> + gen_a64_set_pc_im(b->pc_next);
> gen_helper_check_breakpoints(cpu_env);
> /* End the TB early; it likely won't be executed */
> - dc->base.jmp_type = DJ_UPDATE;
> + b->jmp_type = DJ_UPDATE;
> return BH_HIT_INSN;
> } else {
> gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
> @@ -11287,14 +11273,15 @@ static BreakpointHitType
> gen_intermediate_code_target_breakpoint_hit(
> 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->base.pc_next += 4;
> + b->pc_next += 4;
> return BH_HIT_TB;
> }
> }
> -static target_ulong gen_intermediate_code_target_disas_insn(
> - DisasContext *dc, CPUArchState *env)
> +static target_ulong a64_tr_disas_insn(DisasContextBase *base, CPUArchState
> *env)
> {
> + DisasContext *dc = container_of(base, 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
> @@ -11306,19 +11293,21 @@ static target_ulong
> gen_intermediate_code_target_disas_insn(
> * "did not step an insn" case, and so the syndrome ISV and EX
> * bits should be zero.
> */
> - assert(dc->base.num_insns == 1);
> + assert(base->num_insns == 1);
> gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
> default_exception_el(dc));
> - dc->base.jmp_type = DJ_EXC;
> + base->jmp_type = DJ_EXC;
> } else {
> disas_a64_insn(env, dc);
> }
> - return dc->base.pc_next;
> + return base->pc_next;
> }
> -static DisasJumpType gen_intermediate_code_target_stop_check(
> - DisasContext *dc, CPUArchState *env)
> +static DisasJumpType
> +a64_tr_stop_check(DisasContextBase *base, CPUArchState *env)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
> /* 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
> @@ -11327,41 +11316,42 @@ static DisasJumpType
> gen_intermediate_code_target_stop_check(
> if (dc->ss_active) {
> return DJ_SS;
> } else {
> - return dc->base.jmp_type;
> + return base->jmp_type;
> }
> }
> -static void gen_intermediate_code_target_stop(
> - DisasContext *dc, CPUArchState *env)
> +static void a64_tr_stop(DisasContextBase *base, CPUArchState *env)
> {
> - if (unlikely(dc->base.singlestep_enabled || dc->ss_active)
> - && dc->base.jmp_type != DJ_EXC) {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
> + if (unlikely(base->singlestep_enabled || dc->ss_active)
> + && base->jmp_type != DJ_EXC) {
> /* 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->base.jmp_type != DJ_TB_JUMP);
> - if (dc->base.jmp_type != DJ_JUMP) {
> - gen_a64_set_pc_im(dc->base.pc_next);
> + assert(base->jmp_type != DJ_TB_JUMP);
> + if (base->jmp_type != DJ_JUMP) {
> + gen_a64_set_pc_im(base->pc_next);
> }
> - if (dc->base.singlestep_enabled) {
> + if (base->singlestep_enabled) {
> gen_exception_internal(EXCP_DEBUG);
> } else {
> gen_step_complete_exception(dc);
> }
> } else {
> /* Cast because target-specific values are not in generic enum */
> - unsigned int jt = (unsigned int)dc->base.jmp_type;
> + unsigned int jt = (unsigned int)base->jmp_type;
> switch (jt) {
> case DJ_NEXT:
> case DJ_TOO_MANY: /* target set DJ_NEXT */
> - gen_goto_tb(dc, 1, dc->base.pc_next);
> + gen_goto_tb(dc, 1, base->pc_next);
> break;
> default:
> case DJ_UPDATE:
> - gen_a64_set_pc_im(dc->base.pc_next);
> + gen_a64_set_pc_im(base->pc_next);
> /* fall through */
> case DJ_JUMP:
> tcg_gen_lookup_and_goto_ptr(cpu_pc);
> @@ -11375,18 +11365,18 @@ static void gen_intermediate_code_target_stop(
> /* nothing to generate */
> break;
> case DJ_WFE:
> - gen_a64_set_pc_im(dc->base.pc_next);
> + gen_a64_set_pc_im(base->pc_next);
> gen_helper_wfe(cpu_env);
> break;
> case DJ_YIELD:
> - gen_a64_set_pc_im(dc->base.pc_next);
> + gen_a64_set_pc_im(base->pc_next);
> gen_helper_yield(cpu_env);
> break;
> case DJ_WFI:
> /* This is a special case because we don't want to just halt the
> CPU
> * if trying to debug across a WFI.
> */
> - gen_a64_set_pc_im(dc->base.pc_next);
> + gen_a64_set_pc_im(base->pc_next);
> gen_helper_wfi(cpu_env);
> /* The helper doesn't necessarily throw an exception, but we
> * must go back to the main loop to check for interrupts anyway.
> @@ -11397,8 +11387,26 @@ static void gen_intermediate_code_target_stop(
> }
> }
> -static int gen_intermediate_code_target_get_disas_flags(
> - const DisasContext *dc)
> +static int a64_tr_disas_flags(const DisasContextBase *base)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
> return 4 | (bswap_code(dc->sctlr_b) ? 2 : 0);
> }
> +
> +static const TranslatorOps a64_tr = {
> + .init_context = a64_tr_init_dc,
> + .insn_start = a64_tr_insn_start,
> + .breakpoint_hit = a64_tr_bp_hit,
> + .disas_insn = a64_tr_disas_insn,
> + .stop_check = a64_tr_stop_check,
> + .stop = a64_tr_stop,
> + .disas_flags = a64_tr_disas_flags,
> +};
> +
> +void gen_intermediate_code_a64(CPUState *cpu, struct TranslationBlock *tb)
> +{
> + DisasContext dc;
> +
> + translator_gen(&a64_tr, &dc.base, cpu, tb, cpu_env);
> +}
> diff --git a/target/arm/translate.c b/target/arm/translate.c
> index 06f207a..5ea9952 100644
> --- a/target/arm/translate.c
> +++ b/target/arm/translate.c
> @@ -7655,7 +7655,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t
> insn)
> }
> if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
> - gen_io_start();
> + gen_io_start(cpu_env);
> }
> if (isread) {
> @@ -7747,7 +7747,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t
> insn)
> 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_io_end(cpu_env);
> gen_lookup_tb(s);
> } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
> /* We default to ending the TB on a coprocessor register write,
> @@ -11864,31 +11864,10 @@ void restore_state_to_opc(CPUARMState *env,
> TranslationBlock *tb,
> }
> }
> -
> -
> -/* Use separate top-level templates for each architecture */
> -#define gen_intermediate_code gen_intermediate_code_arm
> -#include "translate-all_template.h"
> -#undef gen_intermediate_code
> -
> -#if !defined(TARGET_AARCH64)
> -void gen_intermediate_code_aarch64(CPUState *cpu, struct TranslationBlock
> *tb)
> -{
> -}
> -#endif
> -
> -void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
> +static void arm_tr_init_dc(DisasContextBase *base, CPUARMState *env)
> {
> - if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> - gen_intermediate_code_aarch64(cpu, tb);
> - } else {
> - gen_intermediate_code_arm(cpu, tb);
> - }
> -}
> + DisasContext *dc = container_of(base, DisasContext, base);
> -static void gen_intermediate_code_target_init_disas_context(
> - DisasContext *dc, CPUARMState *env)
> -{
dc-> condjmp = 0;
dc-> aarch64 = 0;
> @@ -11897,23 +11876,23 @@ static void
> gen_intermediate_code_target_init_disas_context(
> */
dc-> secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
> !arm_el_is_aa64(env, 3);
> - 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->thumb = ARM_TBFLAG_THUMB(base->tb->flags);
> + dc->sctlr_b = ARM_TBFLAG_SCTLR_B(base->tb->flags);
> + dc->be_data = ARM_TBFLAG_BE_DATA(base->tb->flags) ? MO_BE : MO_LE;
> + dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(base->tb->flags) & 0xf) << 1;
> + dc->condexec_cond = ARM_TBFLAG_CONDEXEC(base->tb->flags) >> 4;
> + dc->mmu_idx = core_to_arm_mmu_idx(env,
> ARM_TBFLAG_MMUIDX(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(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->ns = ARM_TBFLAG_NS(base->tb->flags);
> + dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(base->tb->flags);
> + dc->vfp_enabled = ARM_TBFLAG_VFPEN(base->tb->flags);
> + dc->vec_len = ARM_TBFLAG_VECLEN(base->tb->flags);
> + dc->vec_stride = ARM_TBFLAG_VECSTRIDE(base->tb->flags);
> + dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(base->tb->flags);
> + dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(base->tb->flags);
dc-> cp_regs = arm_env_get_cpu(env)->cp_regs;
dc-> features = env->features;
> @@ -11932,17 +11911,16 @@ static void
> gen_intermediate_code_target_init_disas_context(
> * emit code to generate a software step exception
> * end the TB
> */
> - dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
> - dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
> + dc->ss_active = ARM_TBFLAG_SS_ACTIVE(base->tb->flags);
> + dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(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;
> + (base->pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
> }
> -static void gen_intermediate_code_target_init_globals(
> - DisasContext *dc, CPUARMState *env)
> +static void arm_tr_init_globals(DisasContextBase *base, CPUARMState *env)
> {
> cpu_F0s = tcg_temp_new_i32();
> cpu_F1s = tcg_temp_new_i32();
> @@ -11954,8 +11932,7 @@ static void gen_intermediate_code_target_init_globals(
> cpu_M0 = tcg_temp_new_i64();
> }
> -static void gen_intermediate_code_target_tb_start(
> - DisasContext *dc, CPUARMState *env)
> +static void arm_tr_tb_start(DisasContextBase *base, CPUARMState *env)
> {
> /* A note on handling of the condexec (IT) bits:
> *
> @@ -11986,6 +11963,7 @@ static void gen_intermediate_code_target_tb_start(
> * we don't need to care about whether CPUARMState is correct in the
> * middle of a TB.
> */
> + DisasContext *dc = container_of(base, DisasContext, base);
> /*
> * Reset the conditional execution bits immediately. This avoids
> @@ -11998,43 +11976,45 @@ static void gen_intermediate_code_target_tb_start(
> }
> }
> -static void gen_intermediate_code_target_insn_start(
> - DisasContext *dc, CPUARMState *env)
> +static void arm_tr_insn_start(DisasContextBase *base, CPUARMState *env)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
dc-> insn_start_idx = tcg_op_buf_count();
> - tcg_gen_insn_start(dc->base.pc_next,
> + tcg_gen_insn_start(base->pc_next,
> (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
> 0);
> #ifdef CONFIG_USER_ONLY
> /* Intercept jump to the magic kernel page. */
> - if (dc->base.pc_next >= 0xffff0000) {
> + if (base->pc_next >= 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.jmp_type = DJ_EXC;
> + base->jmp_type = DJ_EXC;
> }
> #else
> - if (dc->base.pc_next >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M))
> {
> + if (base->pc_next >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) {
> /* We always get here via a jump, so know we are not in a
> conditional execution block. */
> gen_exception_internal(EXCP_EXCEPTION_EXIT);
> - dc->base.jmp_type = DJ_EXC;
> + base->jmp_type = DJ_EXC;
> }
> #endif
> }
> -static BreakpointHitType gen_intermediate_code_target_breakpoint_hit(
> - DisasContext *dc, CPUARMState *env,
> - const CPUBreakpoint *bp)
> +static BreakpointHitType
> +arm_tr_bp_hit(DisasContextBase *base, CPUARMState *env, const CPUBreakpoint
> *bp)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
> if (bp->flags & BP_CPU) {
> gen_set_condexec(dc);
> - gen_set_pc_im(dc, dc->base.pc_next);
> + gen_set_pc_im(dc, base->pc_next);
> gen_helper_check_breakpoints(cpu_env);
> /* End the TB early; it's likely not going to be executed */
> - dc->base.jmp_type = DJ_UPDATE;
> + base->jmp_type = DJ_UPDATE;
> return BH_HIT_INSN;
> } else {
> gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
> @@ -12045,14 +12025,15 @@ static BreakpointHitType
> gen_intermediate_code_target_breakpoint_hit(
tb-> size below does the right thing. */
> /* TODO: Advance PC by correct instruction length to avoid
> * disassembler error messages */
> - dc->base.pc_next += 2;
> + base->pc_next += 2;
> return BH_HIT_TB;
> }
> }
> -static target_ulong gen_intermediate_code_target_disas_insn(
> - DisasContext *dc, CPUArchState *env)
> +static target_ulong arm_tr_disas_insn(DisasContextBase *base, CPUArchState
> *env)
> {
> + DisasContext *dc = container_of(base, 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
> @@ -12064,11 +12045,11 @@ static target_ulong
> gen_intermediate_code_target_disas_insn(
> * "did not step an insn" case, and so the syndrome ISV and EX
> * bits should be zero.
> */
> - assert(dc->base.num_insns == 1);
> + assert(base->num_insns == 1);
> gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
> default_exception_el(dc));
> - dc->base.jmp_type = DJ_SKIP;
> - return dc->base.pc_next;
> + base->jmp_type = DJ_SKIP;
> + return base->pc_next;
> }
> if (dc->thumb) {
> @@ -12082,30 +12063,32 @@ static target_ulong
> gen_intermediate_code_target_disas_insn(
> }
> }
> } else {
> - unsigned int insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b);
> - dc->base.pc_next += 4;
> + unsigned int insn = arm_ldl_code(env, base->pc_next, dc->sctlr_b);
> + base->pc_next += 4;
> disas_arm_insn(dc, insn);
> }
> - if (dc->condjmp && !dc->base.jmp_type) {
> + if (dc->condjmp && !base->jmp_type) {
> gen_set_label(dc->condlabel);
dc-> condjmp = 0;
> }
> - return dc->base.pc_next;
> + return base->pc_next;
> }
> -static DisasJumpType gen_intermediate_code_target_stop_check(
> - DisasContext *dc, CPUARMState *env)
> +static DisasJumpType arm_tr_stop_check(DisasContextBase *base, CPUARMState
> *env)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
> /* 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. */
> + dc = container_of(base, DisasContext, base);
> if (is_singlestepping(dc)) {
> return DJ_SS;
> - } else if ((dc->base.pc_next >= dc->next_page_start - 3)
> + } else if ((base->pc_next >= dc->next_page_start - 3)
> && insn_crosses_page(env, dc)) {
> /*
> * Generic code already checked if the next insn starts in a new
> @@ -12122,21 +12105,21 @@ static DisasJumpType
> gen_intermediate_code_target_stop_check(
> */
> return DJ_PAGE_CROSS;
> } else {
> - return dc->base.jmp_type;
> + return base->jmp_type;
> }
> }
> -static void gen_intermediate_code_target_stop(
> - DisasContext *dc, CPUARMState *env)
> +static void arm_tr_stop(DisasContextBase *base, CPUARMState *env)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> /* Cast because target-specific values are not in generic enum */
> - unsigned int jt = (unsigned int)dc->base.jmp_type;
> + unsigned int jt = (unsigned int)base->jmp_type;
> if (jt == DJ_SKIP) {
> return;
> }
> - if ((dc->base.tb->cflags & CF_LAST_IO) && dc->condjmp) {
> + if ((base->tb->cflags & CF_LAST_IO) && dc->condjmp) {
> /* FIXME: This can theoretically happen with self-modifying code. */
> cpu_abort(ENV_GET_CPU(env), "IO on conditional branch instruction");
> }
> @@ -12145,7 +12128,7 @@ static void gen_intermediate_code_target_stop(
> instruction was a conditional branch or trap, and the PC has
> already been written. */
> gen_set_condexec(dc);
> - if (dc->base.jmp_type == DJ_BX_EXCRET) {
> + if (base->jmp_type == DJ_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
> @@ -12171,7 +12154,7 @@ static void gen_intermediate_code_target_stop(
> case DJ_NEXT:
> case DJ_TOO_MANY: /* target set DJ_NEXT */
> case DJ_UPDATE:
> - gen_set_pc_im(dc, dc->base.pc_next);
> + gen_set_pc_im(dc, base->pc_next);
> /* fall through */
> default:
> /* FIXME: Single stepping a WFI insn will not halt the CPU. */
> @@ -12191,10 +12174,10 @@ static void gen_intermediate_code_target_stop(
> switch (jt) {
> case DJ_NEXT:
> case DJ_TOO_MANY: /* target set DJ_NEXT */
> - gen_goto_tb(dc, 1, dc->base.pc_next);
> + gen_goto_tb(dc, 1, base->pc_next);
> break;
> case DJ_UPDATE:
> - gen_set_pc_im(dc, dc->base.pc_next);
> + gen_set_pc_im(dc, base->pc_next);
> /* fall through */
> case DJ_JUMP:
> gen_goto_ptr();
> @@ -12238,16 +12221,40 @@ static void gen_intermediate_code_target_stop(
> gen_set_label(dc->condlabel);
> gen_set_condexec(dc);
> if (unlikely(is_singlestepping(dc))) {
> - gen_set_pc_im(dc, dc->base.pc_next);
> + gen_set_pc_im(dc, base->pc_next);
> gen_singlestep_exception(dc);
> } else {
> - gen_goto_tb(dc, 1, dc->base.pc_next);
> + gen_goto_tb(dc, 1, base->pc_next);
> }
> }
> }
> -static int gen_intermediate_code_target_get_disas_flags(
> - const DisasContext *dc)
> +static int arm_tr_disas_flags(const DisasContextBase *base)
> {
> + DisasContext *dc = container_of(base, DisasContext, base);
> +
> return dc->thumb | (dc->sctlr_b << 1);
> }
> +
> +static const TranslatorOps arm_tr = {
> + .init_context = arm_tr_init_dc,
> + .init_globals = arm_tr_init_globals,
> + .tb_start = arm_tr_tb_start,
> + .insn_start = arm_tr_insn_start,
> + .breakpoint_hit = arm_tr_bp_hit,
> + .disas_insn = arm_tr_disas_insn,
> + .stop_check = arm_tr_stop_check,
> + .stop = arm_tr_stop,
> + .disas_flags = arm_tr_disas_flags,
> +};
> +
> +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb)
> +{
> + DisasContext dc;
> +
> + if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
> + gen_intermediate_code_a64(cpu, tb);
> + } else {
> + translator_gen(&arm_tr, &dc.base, cpu, tb, cpu_env);
> + }
> +}
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index 5473994..1aa5d49 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -1,8 +1,7 @@
> #ifndef TARGET_ARM_TRANSLATE_H
> #define TARGET_ARM_TRANSLATE_H
> -#include "exec/translate-all_template.h"
> -
> +#include "exec/translator.h"
> /* internal defines */
> typedef struct DisasContext {
> @@ -122,7 +121,6 @@ static void disas_set_insn_syndrome(DisasContext *s,
> uint32_t syn)
> }
> /* Target-specific values for DisasContextBase::jmp_type */
> -#include "exec/translate-all_template.h"
> #define DJ_JUMP (DJ_TARGET + 0)
> #define DJ_UPDATE (DJ_TARGET + 1)
> #define DJ_TB_JUMP (DJ_TARGET + 2)
> @@ -153,13 +151,10 @@ static void disas_set_insn_syndrome(DisasContext *s,
> uint32_t syn)
> #define DJ_PAGE_CROSS (DJ_TARGET + 13)
> #define DJ_SKIP (DJ_TARGET + 14)
> -void gen_intermediate_code_arm(CPUState *cpu, struct TranslationBlock *tb);
> -void gen_intermediate_code_aarch64(CPUState *cpu, struct TranslationBlock
> *tb);
> -
> #ifdef TARGET_AARCH64
> void init_tmp_a64_array(DisasContext *s);
> void a64_translate_init(void);
> -void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb);
> +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);
> @@ -172,7 +167,7 @@ static inline void a64_translate_init(void)
> {
> }
> -static inline void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock
> *tb)
> +static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock
> *tb)
> {
> }
> diff --git a/translator.c b/translator.c
> new file mode 100644
> index 0000000..2248b52
> --- /dev/null
> +++ b/translator.c
> @@ -0,0 +1,170 @@
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/error-report.h"
> +#include "disas/disas.h"
> +#include "cpu.h"
> +#include "tcg.h"
> +#include "tcg-op.h"
> +#include "exec/exec-all.h"
> +#include "exec/translator.h"
> +#include "exec/gen-icount.h"
> +#include "exec/log.h"
> +
> +static inline void check_tcg(const DisasContextBase *base)
> +{
> + if (tcg_check_temp_count()) {
> + error_report("warning: TCG temporary leaks before "TARGET_FMT_lx,
> + base->pc_next);
> + }
> +}
> +
> +void translator_gen(const TranslatorOps *tr, DisasContextBase *base,
> + CPUState *cpu, TranslationBlock *tb, TCGv_env cpu_env)
> +{
> + CPUArchState *env = cpu->env_ptr;
> + int max_insns;
> +
> + /* Initialize DisasContextBase */
> + base->tb = tb;
> + base->singlestep_enabled = cpu->singlestep_enabled;
> + base->pc_first = tb->pc;
> + base->pc_next = base->pc_first;
> + base->jmp_type = DJ_NEXT;
> + base->num_insns = 0;
> + if (tr->init_context) {
> + tr->init_context(base, env);
> + }
> +
> + /* Initialize globals */
> + if (tr->init_globals) {
> + tr->init_globals(base, env);
> + }
> + tcg_clear_temp_count();
> +
> + /* Instruction counting */
> + max_insns = base->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 (base->singlestep_enabled || singlestep) {
> + max_insns = 1;
> + }
> +
> + /* Start translating */
> + gen_tb_start(base->tb, cpu_env);
> + if (tr->tb_start) {
> + tr->tb_start(base, env);
> + }
> +
> + while (true) {
> + CPUBreakpoint *bp;
> +
> + base->num_insns++;
> + if (tr->insn_start) {
> + tr->insn_start(base, env);
> + }
> +
> + /* Early exit before breakpoint checks */
> + if (unlikely(base->jmp_type != DJ_NEXT)) {
> + break;
> + }
> +
> + /* Pass breakpoint hits to target for further processing */
> + bp = NULL;
> + do {
> + bp = cpu_breakpoint_get(cpu, base->pc_next, bp);
> + if (unlikely(bp)) {
> + BreakpointHitType bh = tr->breakpoint_hit(base, env, bp);
> + if (bh == BH_HIT_INSN) {
> + /* Hit, keep translating */
> + /*
> + * TODO: if we're never going to have more than one BP
> in a
> + * single address, we can simply use a bool here.
> + */
> + break;
> + } else if (bh == BH_HIT_TB) {
> + goto done_generating;
> + }
> + }
> + } while (bp != NULL);
> +
> + /* Accept I/O on last instruction */
> + if (base->num_insns == max_insns &&
> + (base->tb->cflags & CF_LAST_IO)) {
> + gen_io_start(cpu_env);
> + }
> +
> + /* Disassemble one instruction */
> + base->pc_next = tr->disas_insn(base, env);
> +
> + /**************************************************/
> + /* Conditions to stop translation */
> + /**************************************************/
> +
> + /* Disassembly already set a stop condition */
> + if (base->jmp_type >= DJ_TARGET) {
> + break;
> + }
> +
> + /* Target-specific conditions */
> + base->jmp_type = tr->stop_check(base, env);
> + if (base->jmp_type >= DJ_TARGET) {
> + break;
> + }
> +
> + /* Too many instructions */
> + if (tcg_op_buf_full() || base->num_insns >= max_insns) {
> + base->jmp_type = DJ_TOO_MANY;
> + break;
> + }
> +
> + /*
> + * Check if next instruction is on next page, which can cause an
> + * exception.
> + *
> + * NOTE: Target-specific code must check a single instruction does
> not
> + * cross page boundaries; the first in the TB is always
> allowed to
> + * cross pages (never goes through this check).
> + */
> + if ((base->pc_first & TARGET_PAGE_MASK)
> + != (base->pc_next & TARGET_PAGE_MASK)) {
> + base->jmp_type = DJ_TOO_MANY;
> + break;
> + }
> +
> + check_tcg(base);
> + }
> +
> + if (tr->stop) {
> + tr->stop(base, env);
> + }
> +
> + if (base->tb->cflags & CF_LAST_IO) {
> + gen_io_end(cpu_env);
> + }
> +
> + done_generating:
> + gen_tb_end(base->tb, base->num_insns);
> +
> + check_tcg(base);
> +
> +#ifdef DEBUG_DISAS
> + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
> + qemu_log_in_addr_range(base->pc_first)) {
> + qemu_log_lock();
> + qemu_log("----------------\n");
> + qemu_log("IN: %s\n", lookup_symbol(base->pc_first));
> + log_target_disas(cpu, base->pc_first,
> + base->pc_next - base->pc_first,
> + tr->disas_flags(base));
> + qemu_log("\n");
> + qemu_log_unlock();
> + }
> +#endif
> +
> + base->tb->size = base->pc_next - base->pc_first;
> + base->tb->icount = base->num_insns;
> +}
> --
> 2.7.4
- [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework, Lluís Vilanova, 2017/06/12
- Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework, Emilio G. Cota, 2017/06/15
- Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework, Lluís Vilanova, 2017/06/18
- Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework, Lluís Vilanova, 2017/06/18
- Re: [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework, Lluís Vilanova, 2017/06/18