From patchwork Wed Jan 24 23:25:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 125722 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp732424ljf; Wed, 24 Jan 2018 15:30:20 -0800 (PST) X-Google-Smtp-Source: AH8x225Et3YKvqD9Xkk9wF7HBrv49EGeY4IOiA9bO9cgWaTnz/CvHQz6O4+bgmci+RdqHDURbUiy X-Received: by 10.37.211.11 with SMTP id e11mr7067168ybf.243.1516836620470; Wed, 24 Jan 2018 15:30:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516836620; cv=none; d=google.com; s=arc-20160816; b=YHlcR2dNX2mqwNXYJc/ggS7Rqk8pwDa9AYsjXvKdIGzzAZ9Giuc1HdvZ8xRvLIZr9Y TdHO2tUJlVqsY3BXf8/66bMq16z+kwasejNhxhIwjJG5fXu8mHOvTrecUAX0kZgVaWFe 2ll5OzGlPd+o8/yasKcYGbs2hnb94uEIkOotIatby8fANX/mFv2qNfBV8QT4l2l/hShj o67PO0mKWsnQArBlmIVWwSyQ9LS2tOYFBrBg1eTytKCPKyz+a5buOi4sfuh3Y06gNg5o rnakbJojXST14jajwSPocUtel26DpKmyHXLYhmSlfDOgDYYEnQFz2zhtsaeZ9AOcT2Km 1mXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature:arc-authentication-results; bh=p+QD+b6Cw+XW39YAD69NZNQ9QvIBR9apORbL4Kd/U/Y=; b=0iLWxRZCWGM6dlnXeGvanJBvR+C4N/N3CsSUEZcFC7nGfO1uu/wn9B21Zfnha+AUdq Vz+ugsgG6eVQtxMb2NTkkd3EtCVQ3vAsv/iwC69slmYDA0RejJR7p/XEN5+kQSc76yE+ Z/30/axjURTEFPiuapOjo3VgOgUjNXDyYC8p92YmYi6hN0lBsWYo1vE0pVWk/4nE7I+D XPLCBIIrogqCmkD66ur6ysL9Q+oyTiQ4JQdV+e6uk75Yv1As1YMSdkvmmKi/uZ/AnW7I jCadMQ7qMyDCbkUizuG6RYDZf0Fb8e7mrmPBqIJ1vtQFZwA909bHOFUxPhLSN2YAWEJk cFOA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=HI1pPunD; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id x63si232081ywa.754.2018.01.24.15.30.20 for (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 24 Jan 2018 15:30:20 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=HI1pPunD; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:54471 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eeUUl-0007BF-Qp for patch@linaro.org; Wed, 24 Jan 2018 18:30:19 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51086) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eeURU-0004de-8b for qemu-devel@nongnu.org; Wed, 24 Jan 2018 18:26:58 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eeURS-0001lY-0u for qemu-devel@nongnu.org; Wed, 24 Jan 2018 18:26:56 -0500 Received: from mail-pg0-x231.google.com ([2607:f8b0:400e:c05::231]:45020) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eeURR-0001kY-Of for qemu-devel@nongnu.org; Wed, 24 Jan 2018 18:26:53 -0500 Received: by mail-pg0-x231.google.com with SMTP id m20so3808955pgc.11 for ; Wed, 24 Jan 2018 15:26:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=p+QD+b6Cw+XW39YAD69NZNQ9QvIBR9apORbL4Kd/U/Y=; b=HI1pPunDNFbWoUCVe5uwPIkELGJkHMsPYQooMaHo40lnOTg78inOLyNrQyYPOo6Ptb yrPrDYrW6uWNoetqN0pkIQMSUl3UqZnjm2kJSrx5ABEly3fDL5x3MImHpNufd40MPgAa UFRT6gX5ORVztMCO7mzB/rK0gq3vgILXKoA+U= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=p+QD+b6Cw+XW39YAD69NZNQ9QvIBR9apORbL4Kd/U/Y=; b=C3x7+9we/qNb4ErLtEy1ORWiEAy97yhCGnq5H+YmGRFqpARqQsmOudAK+8M24LV/Yk SLQcto9NAQFEoENZvWhACLOVtvKfcRJFQBsC9S4h46jbp4IqdbSQZzMoaU8uRmYRpaub t2Juuu8wBrnOpmj4LDcdVQdycJb3EyEXimEjn+fYFfOt6K5f7/am5xI9lWNLVof8H0h3 kd4oz2oSwG1qIzXQ8xSEueI7ACZZUrw0AfTmI+GFHakMsUmLwEc2o48SehvGFKPnegfM OUDOgWQOvhBmPeAHCwmjTdcQ1c7f/lVJUqUx8ocsPTL0t7gG58VLYl3qm7uW8vjcRTRU 7RRw== X-Gm-Message-State: AKwxytdY4qngiGl4j+165Kg1oj+PahXi8eaTwgSTNCJ5clHyPoNg4m91 qK7i+jbwZ2YfVClAIsr+9pAFhEZwHKg= X-Received: by 2002:a17:902:598e:: with SMTP id p14-v6mr9045846pli.289.1516836412108; Wed, 24 Jan 2018 15:26:52 -0800 (PST) Received: from cloudburst.twiddle.net (174-21-6-47.tukw.qwest.net. [174.21.6.47]) by smtp.gmail.com with ESMTPSA id z19sm9760028pfh.185.2018.01.24.15.26.50 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 24 Jan 2018 15:26:51 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Wed, 24 Jan 2018 15:25:56 -0800 Message-Id: <20180124232625.30105-17-richard.henderson@linaro.org> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180124232625.30105-1-richard.henderson@linaro.org> References: <20180124232625.30105-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::231 Subject: [Qemu-devel] [PATCH v3 16/45] target/hppa: Implement IASQ X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Any one TB will have only one space value. If we change spaces, we change TBs. Thus BE and BEV must exit the TB immediately. Signed-off-by: Richard Henderson --- target/hppa/cpu.h | 53 ++++++++++++++++++++- target/hppa/cpu.c | 15 ++++++ target/hppa/helper.c | 3 +- target/hppa/int_helper.c | 16 +++++-- target/hppa/op_helper.c | 2 + target/hppa/translate.c | 117 ++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 179 insertions(+), 27 deletions(-) -- 2.14.3 diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 94f9c8ca2b..d583ea43dd 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -186,6 +186,8 @@ struct CPUHPPAState { target_ureg iaoq_f; /* front */ target_ureg iaoq_b; /* back, aka next instruction */ + uint64_t iasq_f; + uint64_t iasq_b; uint32_t fr0_shadow; /* flags, c, ca/cq, rm, d, enables */ float_status fp_status; @@ -240,15 +242,62 @@ void hppa_translate_init(void); void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf); +static inline target_ulong hppa_form_gva_psw(target_ureg psw, uint64_t spc, + target_ureg off) +{ +#ifdef CONFIG_USER_ONLY + return off; +#else + off &= (psw & PSW_W ? 0x3fffffffffffffffull : 0xffffffffull); + return spc | off; +#endif +} + +static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc, + target_ureg off) +{ + return hppa_form_gva_psw(env->psw, spc, off); +} + +/* Since PSW_CB will never need to be in tb->flags, reuse them. */ +#define TB_FLAG_PRIV_SHIFT 8 + static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *pflags) { + uint32_t flags = env->psw_n * PSW_N; + + /* TB lookup assumes that PC contains the complete virtual address. + If we leave space+offset separate, we'll get ITLB misses to an + incomplete virtual address. This also means that we must separate + out current cpu priviledge from the low bits of IAOQ_F. */ +#ifdef CONFIG_USER_ONLY *pc = env->iaoq_f; *cs_base = env->iaoq_b; +#else /* ??? E, T, H, L, B, P bits need to be here, when implemented. */ - *pflags = (env->psw & (PSW_W | PSW_C | PSW_D)) - | env->psw_n * PSW_N; + flags |= env->psw & (PSW_W | PSW_C | PSW_D); + flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT; + + *pc = (env->psw & PSW_C + ? hppa_form_gva_psw(env->psw, env->iasq_f, env->iaoq_f & -4) + : env->iaoq_f & -4); + *cs_base = env->iasq_f; + + /* Insert a difference between IAOQ_B and IAOQ_F within the otherwise zero + low 32-bits of CS_BASE. This will succeed for all direct branches, + which is the primary case we care about -- using goto_tb within a page. + Failure is indicated by a zero difference. */ + if (env->iasq_f == env->iasq_b) { + target_sreg diff = env->iaoq_b - env->iaoq_f; + if (TARGET_REGISTER_BITS == 32 || diff == (int32_t)diff) { + *cs_base |= (uint32_t)diff; + } + } +#endif + + *pflags = flags; } target_ureg cpu_hppa_get_psw(CPUHPPAState *env); diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 4d0b760baa..2970afd58d 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -37,8 +37,23 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) { HPPACPU *cpu = HPPA_CPU(cs); +#ifdef CONFIG_USER_ONLY cpu->env.iaoq_f = tb->pc; cpu->env.iaoq_b = tb->cs_base; +#else + /* Recover the IAOQ values from the GVA + PRIV. */ + uint32_t priv = (tb->flags >> TB_FLAG_PRIV_SHIFT) & 3; + target_ulong cs_base = tb->cs_base; + target_ulong iasq_f = cs_base & ~0xffffffffull; + int32_t diff = cs_base; + + cpu->env.iasq_f = iasq_f; + cpu->env.iaoq_f = (tb->pc & ~iasq_f) + priv; + if (diff) { + cpu->env.iaoq_b = cpu->env.iaoq_f + diff; + } +#endif + cpu->env.psw_n = (tb->flags & PSW_N) != 0; } diff --git a/target/hppa/helper.c b/target/hppa/helper.c index 6e8758f82c..858ec205b6 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -78,7 +78,8 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int i; cpu_fprintf(f, "IA_F " TARGET_FMT_lx " IA_B " TARGET_FMT_lx "\n", - (target_ulong)env->iaoq_f, (target_ulong)env->iaoq_b); + hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f), + hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b)); psw_c[0] = (psw & PSW_W ? 'W' : '-'); psw_c[1] = (psw & PSW_E ? 'E' : '-'); diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c index a59aae1189..02963b80c6 100644 --- a/target/hppa/int_helper.c +++ b/target/hppa/int_helper.c @@ -32,6 +32,8 @@ void hppa_cpu_do_interrupt(CPUState *cs) int i = cs->exception_index; target_ureg iaoq_f = env->iaoq_f; target_ureg iaoq_b = env->iaoq_b; + uint64_t iasq_f = env->iasq_f; + uint64_t iasq_b = env->iasq_b; #ifndef CONFIG_USER_ONLY target_ureg old_psw; @@ -44,6 +46,8 @@ void hppa_cpu_do_interrupt(CPUState *cs) cpu_hppa_put_psw(env, PSW_W | (i == EXCP_HPMC ? PSW_M : 0)); /* step 3 */ + env->cr[CR_IIASQ] = iasq_f >> 32; + env->cr_back[0] = iasq_b >> 32; env->cr[CR_IIAOQ] = iaoq_f; env->cr_back[1] = iaoq_b; @@ -79,6 +83,9 @@ void hppa_cpu_do_interrupt(CPUState *cs) hwaddr paddr; paddr = vaddr = iaoq_f & -4; + if (old_psw & PSW_C) { + vaddr = hppa_form_gva_psw(old_psw, iasq_f, iaoq_f & -4); + } env->cr[CR_IIR] = ldl_phys(cs->as, paddr); } break; @@ -101,6 +108,8 @@ void hppa_cpu_do_interrupt(CPUState *cs) /* step 7 */ env->iaoq_f = env->cr[CR_IVA] + 32 * i; env->iaoq_b = env->iaoq_f + 4; + env->iasq_f = 0; + env->iasq_b = 0; #endif if (qemu_loglevel_mask(CPU_LOG_INT)) { @@ -151,10 +160,11 @@ void hppa_cpu_do_interrupt(CPUState *cs) qemu_log("INT %6d: %s @ " TARGET_FMT_lx "," TARGET_FMT_lx " -> " TREG_FMT_lx " " TARGET_FMT_lx "\n", ++count, name, - (target_ulong)iaoq_f, - (target_ulong)iaoq_b, + hppa_form_gva(env, iasq_f, iaoq_f), + hppa_form_gva(env, iasq_b, iaoq_b), env->iaoq_f, - (target_ulong)env->cr[CR_IOR]); + hppa_form_gva(env, (uint64_t)env->cr[CR_ISR] << 32, + env->cr[CR_IOR])); } cs->exception_index = -1; } diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 3f5dcbbca0..1963b2439b 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -622,6 +622,8 @@ void HELPER(rfi)(CPUHPPAState *env) if (env->psw & (PSW_I | PSW_R | PSW_Q)) { helper_excp(env, EXCP_ILL); } + env->iasq_f = (uint64_t)env->cr[CR_IIASQ] << 32; + env->iasq_b = (uint64_t)env->cr_back[0] << 32; env->iaoq_f = env->cr[CR_IIAOQ]; env->iaoq_b = env->cr_back[1]; cpu_hppa_put_psw(env, env->cr[CR_IPSW]); diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 4a69f05a91..44abc9006b 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -325,6 +325,8 @@ static TCGv_reg cpu_gr[32]; static TCGv_i64 cpu_sr[4]; static TCGv_reg cpu_iaoq_f; static TCGv_reg cpu_iaoq_b; +static TCGv_i64 cpu_iasq_f; +static TCGv_i64 cpu_iasq_b; static TCGv_reg cpu_sar; static TCGv_reg cpu_psw_n; static TCGv_reg cpu_psw_v; @@ -380,6 +382,13 @@ void hppa_translate_init(void) const GlobalVar *v = &vars[i]; *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name); } + + cpu_iasq_f = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUHPPAState, iasq_f), + "iasq_f"); + cpu_iasq_b = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUHPPAState, iasq_b), + "iasq_b"); } static DisasCond cond_make_f(void) @@ -1760,6 +1769,11 @@ static DisasJumpType do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n, ctx->null_lab = NULL; } nullify_set(ctx, n); + if (ctx->iaoq_n == -1) { + /* The temporary iaoq_n_var died at the branch above. + Regenerate it here instead of saving it. */ + tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4); + } gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); } @@ -1801,11 +1815,17 @@ static DisasJumpType do_ibranch(DisasContext *ctx, TCGv_reg dest, } next = get_temp(ctx); tcg_gen_mov_reg(next, dest); - ctx->iaoq_n = -1; - ctx->iaoq_n_var = next; if (is_n) { + if (use_nullify_skip(ctx)) { + tcg_gen_mov_reg(cpu_iaoq_f, next); + tcg_gen_addi_reg(cpu_iaoq_b, next, 4); + nullify_set(ctx, 0); + return DISAS_IAQ_N_UPDATED; + } ctx->null_cond.c = TCG_COND_ALWAYS; } + ctx->iaoq_n = -1; + ctx->iaoq_n_var = next; } else if (is_n && use_nullify_skip(ctx)) { /* The (conditional) branch, B, nullifies the next insn, N, and we're allowed to skip execution N (no single-step or @@ -3477,26 +3497,55 @@ static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l) target_sreg disp = assemble_17(insn); TCGv_reg tmp; - /* unsigned s = low_uextract(insn, 13, 3); */ +#ifdef CONFIG_USER_ONLY /* ??? It seems like there should be a good way of using "be disp(sr2, r0)", the canonical gateway entry mechanism to our advantage. But that appears to be inconvenient to manage along side branch delay slots. Therefore we handle entry into the gateway page via absolute address. */ - -#ifdef CONFIG_USER_ONLY /* Since we don't implement spaces, just branch. Do notice the special case of "be disp(*,r0)" using a direct branch to disp, so that we can goto_tb to the TB containing the syscall. */ if (b == 0) { return do_dbranch(ctx, disp, is_l ? 31 : 0, n); } +#else + int sp = assemble_sr3(insn); + nullify_over(ctx); #endif tmp = get_temp(ctx); tcg_gen_addi_reg(tmp, load_gpr(ctx, b), disp); tmp = do_ibranch_priv(ctx, tmp); + +#ifdef CONFIG_USER_ONLY return do_ibranch(ctx, tmp, is_l ? 31 : 0, n); +#else + TCGv_i64 new_spc = tcg_temp_new_i64(); + + load_spr(ctx, new_spc, sp); + if (is_l) { + copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); + tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); + } + if (n && use_nullify_skip(ctx)) { + tcg_gen_mov_reg(cpu_iaoq_f, tmp); + tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4); + tcg_gen_mov_i64(cpu_iasq_f, new_spc); + tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); + } else { + copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); + if (ctx->iaoq_b == -1) { + tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); + } + tcg_gen_mov_reg(cpu_iaoq_b, tmp); + tcg_gen_mov_i64(cpu_iasq_b, new_spc); + nullify_set(ctx, n); + } + tcg_temp_free_i64(new_spc); + tcg_gen_lookup_and_goto_ptr(); + return nullify_end(ctx, DISAS_NORETURN); +#endif } static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn, @@ -3559,8 +3608,26 @@ static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn, unsigned link = extract32(insn, 13, 1) ? 2 : 0; TCGv_reg dest; +#ifdef CONFIG_USER_ONLY dest = do_ibranch_priv(ctx, load_gpr(ctx, rb)); return do_ibranch(ctx, dest, link, n); +#else + nullify_over(ctx); + dest = do_ibranch_priv(ctx, load_gpr(ctx, rb)); + + copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); + if (ctx->iaoq_b == -1) { + tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); + } + copy_iaoq_entry(cpu_iaoq_b, -1, dest); + tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); + if (link) { + copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); + } + nullify_set(ctx, n); + tcg_gen_lookup_and_goto_ptr(); + return nullify_end(ctx, DISAS_NORETURN); +#endif } static const DisasInsn table_branch[] = { @@ -4267,15 +4334,21 @@ static int hppa_tr_init_disas_context(DisasContextBase *dcbase, #ifdef CONFIG_USER_ONLY ctx->privilege = MMU_USER_IDX; ctx->mmu_idx = MMU_USER_IDX; + ctx->iaoq_f = ctx->base.pc_first; + ctx->iaoq_b = ctx->base.tb->cs_base; #else - ctx->privilege = ctx->base.pc_first & 3; + ctx->privilege = (ctx->base.tb->flags >> TB_FLAG_PRIV_SHIFT) & 3; ctx->mmu_idx = (ctx->base.tb->flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX); -#endif - ctx->iaoq_f = ctx->base.pc_first; - ctx->iaoq_b = ctx->base.tb->cs_base; - ctx->base.pc_first &= -4; + /* Recover the IAOQ values from the GVA + PRIV. */ + uint64_t cs_base = ctx->base.tb->cs_base; + uint64_t iasq_f = cs_base & ~0xffffffffull; + int32_t diff = cs_base; + + ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; + ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); +#endif ctx->iaoq_n = -1; ctx->iaoq_n_var = NULL; @@ -4318,7 +4391,7 @@ static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG); - ctx->base.pc_next = (ctx->iaoq_f & -4) + 4; + ctx->base.pc_next += 4; return true; } @@ -4331,7 +4404,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) /* Execute one insn. */ #ifdef CONFIG_USER_ONLY - if (ctx->iaoq_f < TARGET_PAGE_SIZE) { + if (ctx->base.pc_next < TARGET_PAGE_SIZE) { ret = do_page_zero(ctx); assert(ret != DISAS_NEXT); } else @@ -4339,7 +4412,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { /* Always fetch the insn, even if nullified, so that we check the page permissions for execute. */ - uint32_t insn = cpu_ldl_code(env, ctx->iaoq_f & -4); + uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next); /* Set up the IA queue for the next insn. This will be overwritten by a branch. */ @@ -4377,18 +4450,21 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) /* Advance the insn queue. Note that this check also detects a priority change within the instruction queue. */ if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { - if (ctx->null_cond.c == TCG_COND_NEVER - || ctx->null_cond.c == TCG_COND_ALWAYS) { + if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 + && use_goto_tb(ctx, ctx->iaoq_b) + && (ctx->null_cond.c == TCG_COND_NEVER + || ctx->null_cond.c == TCG_COND_ALWAYS)) { nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); ret = DISAS_NORETURN; } else { ret = DISAS_IAQ_N_STALE; - } + } } ctx->iaoq_f = ctx->iaoq_b; ctx->iaoq_b = ctx->iaoq_n; ctx->base.is_jmp = ret; + ctx->base.pc_next += 4; if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) { return; @@ -4396,6 +4472,9 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) if (ctx->iaoq_f == -1) { tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b); copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); +#ifndef CONFIG_USER_ONLY + tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); +#endif nullify_save(ctx); ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; } else if (ctx->iaoq_b == -1) { @@ -4430,15 +4509,11 @@ static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) default: g_assert_not_reached(); } - - /* We don't actually use this during normal translation, - but we should interact with the generic main loop. */ - ctx->base.pc_next = ctx->base.pc_first + 4 * ctx->base.num_insns; } static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) { - target_ureg pc = dcbase->pc_first; + target_ulong pc = dcbase->pc_first; #ifdef CONFIG_USER_ONLY switch (pc) {