From nobody Sat Feb 7 05:23:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; dkim=fail spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 149659905998325.944184956817026; Sun, 4 Jun 2017 10:57:39 -0700 (PDT) Received: from localhost ([::1]:57923 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dHZmU-0003E0-Ca for importer@patchew.org; Sun, 04 Jun 2017 13:57:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50418) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dHZRe-0007qS-Un for qemu-devel@nongnu.org; Sun, 04 Jun 2017 13:36:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dHZRc-0003We-Qk for qemu-devel@nongnu.org; Sun, 04 Jun 2017 13:36:06 -0400 Received: from mail-pf0-x242.google.com ([2607:f8b0:400e:c00::242]:36355) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dHZRc-0003Vp-Hn for qemu-devel@nongnu.org; Sun, 04 Jun 2017 13:36:04 -0400 Received: by mail-pf0-x242.google.com with SMTP id n23so18101145pfb.3 for ; Sun, 04 Jun 2017 10:36:04 -0700 (PDT) Received: from bigtime.ASUS (cpe-98-155-27-246.hawaii.res.rr.com. [98.155.27.246]) by smtp.gmail.com with ESMTPSA id j191sm52854419pgc.53.2017.06.04.10.36.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 04 Jun 2017 10:36:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=jyOanrLbHGCaidi6o/GDX7L2yIrh60YTfMKwZOoC86U=; b=FPdaSTuf2KjdQcSxboFuJKmtXgwNwXTqoYUt332/Vur79iIXz/Ws6tRFPdJyQzxWEF CXz+oXyrBjWXPzEO08yMyHjvuXK8JzEu6OAuQm14FCuxnuhKpaXIr5HNI5owlbCBjCzf ePBvlR8UFKMk8rDDPm5vajXgMrq7iPUJjM0LCWQodA+yqFgIm7XM+p2W/e0ePhcn28KL ZTAJt986nMDFcAzMJnkH0B1f4iGk4nYcgvUSsFRwZsm+z2uQHFxW+L6wGWlbPpPP98KV 0V1hx+1dojYQakoU2nW56TG23l/HFAzvoX6UyDxIrsBQucGbIr3Uwqoir+BEvedtEAOU KF7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=jyOanrLbHGCaidi6o/GDX7L2yIrh60YTfMKwZOoC86U=; b=mT1tFjkzh2QOE4Co23sniatDuuAIimTl9ki17i2x122h8PqyUg1MsOWw9lCdrAJKOh g/ZydcMrZ99uvzvKJtY9q4w2lI2ppIvrNzEvFe9o4faXdCzqVGdS6zVFI/n7xDpxKQEl gaaAsOGt9RM6LIQaHTaMcX43CK0kvx5pFxejTz/OMypRtlaEqn244eRV/EiEC6asGB1w leaYQnOcbWxy5wMAmWdxRBhPBqpDhT4eCBWoJOxXfDrDqrSNpY3bghSnMdilJglKdsf1 7gm4qTUJ4xrixqtlRMBEdnQNNowDEoy1N4dHy9xE3EDVPfWtZjhFyJiov2ZS9LwtZyE5 WSkA== X-Gm-Message-State: AODbwcBMU10i1agWZ5DF3sKWRIx2062SjCtsZcFNfEZ2gA30ogAv7nzy OkTJVdjg0kNcpI2UvWU= X-Received: by 10.99.116.7 with SMTP id p7mr16831603pgc.162.1496597763296; Sun, 04 Jun 2017 10:36:03 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Sun, 4 Jun 2017 10:34:37 -0700 Message-Id: <20170604173509.29684-38-rth@twiddle.net> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170604173509.29684-1-rth@twiddle.net> References: <20170604173509.29684-1-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c00::242 Subject: [Qemu-devel] [PULL 37/69] target/s390x: Implement EXECUTE via new TranslationBlock 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: , Cc: peter.maydell@linaro.org, aurelien@aurel32.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Previously, helper_ex would construct the insn and then implement the insn via direct calls other helpers. This was sufficient to boot Linux but that is all. It is easy enough to go the whole nine yards by stashing state for EXECUTE within the cpu, and then rely on a new TB to be created that properly and completely interprets the insn. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/cpu.h | 4 +- target/s390x/helper.c | 5 ++ target/s390x/machine.c | 19 ++++++++ target/s390x/mem_helper.c | 118 +++++-------------------------------------= ---- target/s390x/translate.c | 80 ++++++++++++++++++------------- 5 files changed, 85 insertions(+), 141 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index f463113..fdb2f50 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -107,6 +107,8 @@ typedef struct CPUS390XState { uint64_t cc_dst; uint64_t cc_vr; =20 + uint64_t ex_value; + uint64_t __excp_addr; uint64_t psa; =20 @@ -393,7 +395,7 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* = env, target_ulong *pc, target_ulong *cs_base, uint32_t *f= lags) { *pc =3D env->psw.addr; - *cs_base =3D 0; + *cs_base =3D env->ex_value; *flags =3D ((env->psw.mask >> 32) & ~FLAG_MASK_CC) | ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); } diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 4f8aadf..291db72 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -642,6 +642,11 @@ bool s390_cpu_exec_interrupt(CPUState *cs, int interru= pt_request) S390CPU *cpu =3D S390_CPU(cs); CPUS390XState *env =3D &cpu->env; =20 + if (env->ex_value) { + /* Execution of the target insn is indivisible from + the parent EXECUTE insn. */ + return false; + } if (env->psw.mask & PSW_MASK_EXT) { s390_cpu_do_interrupt(cs); return true; diff --git a/target/s390x/machine.c b/target/s390x/machine.c index 8503fa1..8f908bb 100644 --- a/target/s390x/machine.c +++ b/target/s390x/machine.c @@ -34,6 +34,7 @@ static int cpu_post_load(void *opaque, int version_id) =20 return 0; } + static void cpu_pre_save(void *opaque) { S390CPU *cpu =3D opaque; @@ -156,6 +157,23 @@ const VMStateDescription vmstate_riccb =3D { } }; =20 +static bool exval_needed(void *opaque) +{ + S390CPU *cpu =3D opaque; + return cpu->env.ex_value !=3D 0; +} + +const VMStateDescription vmstate_exval =3D { + .name =3D "cpu/exval", + .version_id =3D 1, + .minimum_version_id =3D 1, + .needed =3D exval_needed, + .fields =3D (VMStateField[]) { + VMSTATE_UINT64(env.ex_value, S390CPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_s390_cpu =3D { .name =3D "cpu", .post_load =3D cpu_post_load, @@ -188,6 +206,7 @@ const VMStateDescription vmstate_s390_cpu =3D { &vmstate_fpu, &vmstate_vregs, &vmstate_riccb, + &vmstate_exval, NULL }, }; diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index d57d5b1..3a77edc 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -435,37 +435,6 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, = uint64_t d, uint64_t s) return d + len; } =20 -static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t addre= ss, - uint32_t mask) -{ - int pos =3D 24; /* top of the lower half of r1 */ - uint64_t rmask =3D 0xff000000ULL; - uint8_t val =3D 0; - int ccd =3D 0; - uint32_t cc =3D 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &=3D ~rmask; - val =3D cpu_ldub_data(env, address); - if ((val & 0x80) && !ccd) { - cc =3D 1; - } - ccd =3D 1; - if (val && cc =3D=3D 0) { - cc =3D 2; - } - env->regs[r1] |=3D (uint64_t)val << pos; - address++; - } - mask =3D (mask << 1) & 0xf; - pos -=3D 8; - rmask >>=3D 8; - } - - return cc; -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { @@ -1222,19 +1191,17 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t a= ddr) } #endif =20 -/* execute instruction - this instruction executes an insn modified with the contents of r1 - it does not change the executed instruction in memory - it does not change the program counter - in other words: tricky... - currently implemented by interpreting the cases it is most commonly use= d. +/* Execute instruction. This instruction executes an insn modified with + the contents of r1. It does not change the executed instruction in mem= ory; + it does not change the program counter. + + Perform this by recording the modified instruction in env->ex_value. + This will be noticed by cpu_get_tb_cpu_state and thus tb translation. */ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t a= ddr) { - S390CPU *cpu =3D s390_env_get_cpu(env); uint64_t insn =3D cpu_lduw_code(env, addr); uint8_t opc =3D insn >> 8; - uint32_t cc; =20 /* Or in the contents of R1[56:63]. */ insn |=3D r1 & 0xff; @@ -1254,72 +1221,9 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, u= int64_t r1, uint64_t addr) g_assert_not_reached(); } =20 - HELPER_LOG("%s: addr 0x%lx insn 0x%" PRIx64 "\n", __func__, addr, insn= ); - - if ((opc & 0xf0) =3D=3D 0xd0) { - uint32_t l, b1, b2, d1, d2; - - l =3D extract64(insn, 48, 8); - b1 =3D extract64(insn, 44, 4); - b2 =3D extract64(insn, 28, 4); - d1 =3D extract64(insn, 32, 12); - d2 =3D extract64(insn, 16, 12); - - cc =3D env->cc_op; - switch (opc & 0xf) { - case 0x2: - do_helper_mvc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x4: - cc =3D do_helper_nc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x5: - cc =3D do_helper_clc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x6: - cc =3D do_helper_oc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x7: - cc =3D do_helper_xc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0xc: - do_helper_tr(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0xd: - cc =3D do_helper_trt(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - default: - goto abort; - } - } else if (opc =3D=3D 0x0a) { - /* supervisor call */ - env->int_svc_code =3D extract64(insn, 48, 8); - env->int_svc_ilen =3D ilen; - helper_exception(env, EXCP_SVC); - g_assert_not_reached(); - } else if (opc =3D=3D 0xbf) { - uint32_t r1, r3, b2, d2; - - r1 =3D extract64(insn, 52, 4); - r3 =3D extract64(insn, 48, 4); - b2 =3D extract64(insn, 44, 4); - d2 =3D extract64(insn, 32, 12); - cc =3D helper_icm(env, r1, get_address(env, 0, b2, d2), r3); - } else { - abort: - cpu_abort(CPU(cpu), - "EXECUTE on instruction prefix 0x%x not implemented\n", - opc); - g_assert_not_reached(); - } - - env->cc_op =3D cc; - env->psw.addr +=3D ilen; + /* Record the insn we want to execute as well as the ilen to use + during the execution of the target insn. This will also ensure + that ex_value is non-zero, which flags that we are in a state + that requires such execution. */ + env->ex_value =3D insn | ilen; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 70212c8..97ca639 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -57,6 +57,7 @@ struct DisasContext { struct TranslationBlock *tb; const DisasInsn *insn; DisasFields *fields; + uint64_t ex_value; uint64_t pc, next_pc; uint32_t ilen; enum cc_op cc_op; @@ -2186,23 +2187,18 @@ static ExitStatus op_epsw(DisasContext *s, DisasOps= *o) =20 static ExitStatus op_ex(DisasContext *s, DisasOps *o) { - /* ??? Perhaps a better way to implement EXECUTE is to set a bit in - tb->flags, (ab)use the tb->cs_base field as the address of - the template in memory, and grab 8 bits of tb->flags/cflags for - the contents of the register. We would then recognize all this - in gen_intermediate_code_internal, generating code for exactly - one instruction. This new TB then gets executed normally. - - On the other hand, this seems to be mostly used for modifying - MVC inside of memcpy, which needs a helper call anyway. So - perhaps this doesn't bear thinking about any further. */ - int r1 =3D get_field(s->fields, r1); TCGv_i32 ilen; TCGv_i64 v1; =20 + /* Nested EXECUTE is not allowed. */ + if (unlikely(s->ex_value)) { + gen_program_exception(s, PGM_EXECUTE); + return EXIT_NORETURN; + } + update_psw_addr(s); - gen_op_calc_cc(s); + update_cc_op(s); =20 if (r1 =3D=3D 0) { v1 =3D tcg_const_i64(0); @@ -5190,25 +5186,36 @@ static const DisasInsn *extract_insn(CPUS390XState = *env, DisasContext *s, int op, op2, ilen; const DisasInsn *info; =20 - insn =3D ld_code2(env, pc); - op =3D (insn >> 8) & 0xff; - ilen =3D get_ilen(op); - s->next_pc =3D s->pc + ilen; - s->ilen =3D ilen; + if (unlikely(s->ex_value)) { + /* Drop the EX data now, so that it's clear on exception paths. */ + TCGv_i64 zero =3D tcg_const_i64(0); + tcg_gen_st_i64(zero, cpu_env, offsetof(CPUS390XState, ex_value)); + tcg_temp_free_i64(zero); =20 - switch (ilen) { - case 2: - insn =3D insn << 48; - break; - case 4: - insn =3D ld_code4(env, pc) << 32; - break; - case 6: - insn =3D (insn << 48) | (ld_code4(env, pc + 2) << 16); - break; - default: - abort(); + /* Extract the values saved by EXECUTE. */ + insn =3D s->ex_value & 0xffffffffffff0000ull; + ilen =3D s->ex_value & 0xf; + op =3D insn >> 56; + } else { + insn =3D ld_code2(env, pc); + op =3D (insn >> 8) & 0xff; + ilen =3D get_ilen(op); + switch (ilen) { + case 2: + insn =3D insn << 48; + break; + case 4: + insn =3D ld_code4(env, pc) << 32; + break; + case 6: + insn =3D (insn << 48) | (ld_code4(env, pc + 2) << 16); + break; + default: + g_assert_not_reached(); + } } + s->next_pc =3D s->pc + ilen; + s->ilen =3D ilen; =20 /* We can't actually determine the insn format until we've looked up the full insn opcode. Which we can't do without locating the @@ -5425,6 +5432,7 @@ void gen_intermediate_code(CPUS390XState *env, struct= TranslationBlock *tb) dc.tb =3D tb; dc.pc =3D pc_start; dc.cc_op =3D CC_OP_DYNAMIC; + dc.ex_value =3D tb->cs_base; do_debug =3D dc.singlestep_enabled =3D cs->singlestep_enabled; =20 next_page_start =3D (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; @@ -5471,7 +5479,8 @@ void gen_intermediate_code(CPUS390XState *env, struct= TranslationBlock *tb) || tcg_op_buf_full() || num_insns >=3D max_insns || singlestep - || cs->singlestep_enabled)) { + || cs->singlestep_enabled + || dc.ex_value)) { status =3D EXIT_PC_STALE; } } while (status =3D=3D NO_EXIT); @@ -5513,9 +5522,14 @@ void gen_intermediate_code(CPUS390XState *env, struc= t TranslationBlock *tb) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) && qemu_log_in_addr_range(pc_start)) { qemu_log_lock(); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, dc.pc - pc_start, 1); - qemu_log("\n"); + if (unlikely(dc.ex_value)) { + /* ??? Unfortunately log_target_disas can't use host memory. = */ + qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value); + } else { + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(cs, pc_start, dc.pc - pc_start, 1); + qemu_log("\n"); + } qemu_log_unlock(); } #endif --=20 2.9.4