From: "Emilio G. Cota" <cota@braap.org>
To: "Lluís Vilanova" <vilanova@ac.upc.edu>
Cc: qemu-devel@nongnu.org, "Paolo Bonzini" <pbonzini@redhat.com>,
"Peter Crosthwaite" <crosthwaite.peter@gmail.com>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Richard Henderson" <rth@twiddle.net>
Subject: [Qemu-devel] [PATCH] translator mega-patch
Date: Thu, 15 Jun 2017 18:05:02 -0400 [thread overview]
Message-ID: <20170615220501.GA26408@flamenco> (raw)
In-Reply-To: <149727924970.28532.9346819516051209538.stgit@frigg.lan>
On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
> 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; 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'll send as a separate, proper patch the gen-icount changes; really
having cpu_env there as a global seems wrong to me.
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 <cota@braap.org>
---
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
next prev parent reply other threads:[~2017-06-15 22:05 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-12 14:53 [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic translation framework Lluís Vilanova
2017-06-12 14:53 ` [PATCH v6 1/6] Pass generic CPUState to gen_intermediate_code() Lluís Vilanova
2017-06-12 14:53 ` [Qemu-devel] " Lluís Vilanova
2017-06-13 1:40 ` David Gibson
2017-06-13 1:40 ` [Qemu-devel] " David Gibson
2017-06-14 21:35 ` Eduardo Habkost
2017-06-14 21:35 ` [Qemu-devel] " Eduardo Habkost
2017-06-14 22:30 ` Laurent Vivier
2017-06-16 14:07 ` Alex Bennée
2017-06-16 14:07 ` [Qemu-devel] " Alex Bennée
2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 2/6] queue: Add macro for incremental traversal Lluís Vilanova
2017-06-19 23:20 ` Richard Henderson
2017-06-26 12:33 ` Lluís Vilanova
2017-06-27 1:10 ` Richard Henderson
2017-06-27 9:13 ` Lluís Vilanova
2017-06-12 14:54 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Lluís Vilanova
2017-06-15 22:05 ` Emilio G. Cota [this message]
2017-06-18 14:37 ` [Qemu-devel] [PATCH] translator mega-patch Lluís Vilanova
2017-06-18 18:26 ` Peter Maydell
2017-06-19 4:08 ` Emilio G. Cota
2017-06-19 7:15 ` Peter Maydell
2017-06-15 22:19 ` [Qemu-devel] [PATCH v6 3/6] target: [tcg] Add generic translation framework Emilio G. Cota
2017-06-15 23:25 ` Emilio G. Cota
2017-06-17 1:09 ` Emilio G. Cota
2017-06-18 14:24 ` Lluís Vilanova
2017-06-18 14:22 ` Lluís Vilanova
2017-06-18 15:47 ` Lluís Vilanova
2017-06-18 21:54 ` Lluís Vilanova
2017-06-19 4:10 ` Emilio G. Cota
2017-06-19 8:37 ` Lluís Vilanova
2017-06-18 14:20 ` Lluís Vilanova
2017-06-12 14:54 ` [PATCH v6 4/6] target: [tcg] Redefine DISAS_* onto the generic translation framework (DJ_*) Lluís Vilanova
2017-06-12 14:54 ` [Qemu-devel] " Lluís Vilanova
2017-06-12 14:54 ` [PATCH v6 6/6] target: [tcg, arm] Port to generic translation framework Lluís Vilanova
2017-06-12 14:54 ` [Qemu-devel] " Lluís Vilanova
2017-06-16 0:18 ` Emilio G. Cota
2017-06-18 14:41 ` Lluís Vilanova
2017-06-19 4:22 ` Emilio G. Cota
2017-06-15 18:02 ` [Qemu-devel] [RFC PATCH v6 0/6] translate: [tcg] Generic " Emilio G. Cota
2017-06-18 14:41 ` Lluís Vilanova
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170615220501.GA26408@flamenco \
--to=cota@braap.org \
--cc=alex.bennee@linaro.org \
--cc=crosthwaite.peter@gmail.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=rth@twiddle.net \
--cc=vilanova@ac.upc.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.