From c5b25fa78b3b7a55511f753552d35e8a9fc9b92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Wed, 12 Jan 2022 17:05:59 -0300 Subject: [PATCH 1/7] target/ppc: Implement hashst(p) and hashchk(p) instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementation for instructions hashst, hashchk, and its privileged versions. Signed-off-by: Víctor Colombo --- linux-headers/asm-powerpc/kvm.h | 3 + target/ppc/cpu.h | 2 + target/ppc/cpu_init.c | 7 ++ target/ppc/excp_helper.c | 86 ++++++++++++++++++++++ target/ppc/helper.h | 4 + target/ppc/insn32.decode | 10 +++ target/ppc/translate.c | 6 ++ target/ppc/translate/fixedpoint-impl.c.inc | 29 ++++++++ 8 files changed, 147 insertions(+) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 9f18fa090f1f..4ae4718143fa 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -646,6 +646,9 @@ struct kvm_ppc_cpu_char { #define KVM_REG_PPC_SIER3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc3) #define KVM_REG_PPC_DAWR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc4) #define KVM_REG_PPC_DAWRX1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc5) +/* FIXME: KVM hasn't exposed these registers yet */ +#define KVM_REG_PPC_HASHKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x00) +#define KVM_REG_PPC_HASHPKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x00) /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 047b24ba50ea..9b16b4e7bac1 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1674,6 +1674,8 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_GIVOR14 (0x1BD) #define SPR_TIR (0x1BE) #define SPR_PTCR (0x1D0) +#define SPR_POWER_HASHKEYR (0x1D4) +#define SPR_POWER_HASHPKEYR (0x1D5) #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_Exxx_BBEAR (0x201) #define SPR_Exxx_BBTAR (0x202) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 073fd101687c..fc0c04cc2c90 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6478,6 +6478,13 @@ static void init_proc_POWER10(CPUPPCState *env) spr_read_generic, spr_write_generic, KVM_REG_PPC_PSSCR, 0); + spr_register_kvm(env, SPR_POWER_HASHKEYR, "HASHPKEYR", + SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_HASHKEYR, 0x0); + spr_register_kvm(env, SPR_POWER_HASHPKEYR, "HASHPKEYR", + SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_HASHPKEYR, 0x0); + /* env variables */ env->dcache_line_size = 128; env->icache_line_size = 128; diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index d3e2cfcd7120..8902c0b84777 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2172,6 +2172,92 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, #endif #endif +static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) +{ + uint32_t c = 0xfffc; + uint64_t z0 = 0xfa2561cdf44ac398; + uint16_t z = 0, temp; + uint16_t k[32], eff_k[32], xleft[33], xright[33], fxleft[32]; + + for (int i = 3; i >= 0; i--) { + k[i] = key & 0xffff; + key >>= 16; + } + xleft[0] = x & 0xffff; + xright[0] = (x >> 16) & 0xffff; + + for (int i = 0; i < 28; i++) { + z |= ((z0 >> (63 - i)) & 1) << 48; + temp = ror16(k[i + 3], 3) ^ k[i + 1]; + k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1); + } + + for (int i = 0; i < 8; i++) + { + eff_k[4 * i + 0] = k[4 * i + ((0 + lane) % 4)]; + eff_k[4 * i + 1] = k[4 * i + ((1 + lane) % 4)]; + eff_k[4 * i + 2] = k[4 * i + ((2 + lane) % 4)]; + eff_k[4 * i + 3] = k[4 * i + ((3 + lane) % 4)]; + } + + for (int i = 0; i < 32; i++) + { + fxleft[i] = (rol16(xleft[i], 1) & + rol16(xleft[i], 8)) ^ rol16(xleft[i], 2); + xleft[i + 1] = xright[i] ^ fxleft[i] ^ eff_k[i]; + xright[i + 1] = xleft[i]; + } + + return (((uint32_t)xright[32]) << 16) | xleft[32]; +} + +/* TODO: check this implementation correctness; make it better */ +static uint64_t hash_digest(uint64_t ra, uint64_t rb, uint64_t key) +{ + uint64_t stage0_h = 0ULL, stage0_l = 0ULL; + uint64_t stage1_h, stage1_l; + + for (int i = 0; i < 4; i++) { + stage0_h |= ror64(rb & 0xff, 8 * (2 * i + 1)); + stage0_h |= ((ra >> 32) & 0xff) << (8 * 2 * i); + stage0_l |= ror64((rb >> 32) & 0xff, 8 * (2 * i +1)); + stage0_l |= (ra & 0xff) << (8 * 2 * i); + rb >>= 8; + ra >>= 8; + } + + stage1_h = (uint64_t)helper_SIMON_LIKE_32_64(stage0_h >> 32, key, 0) << 32; + stage1_h |= helper_SIMON_LIKE_32_64(stage0_h, key, 1); + stage1_l = (uint64_t)helper_SIMON_LIKE_32_64(stage0_l >> 32, key, 2) << 32; + stage1_l |= helper_SIMON_LIKE_32_64(stage0_l, key, 3); + + return (stage1_h ^ stage1_l); +} + +#define HELPER_HASH(op, key, store) \ +void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ + target_ulong rb) \ +{ \ + uint64_t chash = hash_digest(ra, rb, key), lhash; \ + \ + if (store) { \ + cpu_stq_data_ra(env, ea, chash, GETPC()); \ + } \ + else { \ + lhash = cpu_ldq_data_ra(env, ea, GETPC()); \ + if (lhash != chash) { \ + /* hashes don't match, trap */ \ + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, \ + POWERPC_EXCP_TRAP, GETPC()); \ + } \ + } \ +} + +HELPER_HASH(HASHST, env->spr[SPR_POWER_HASHKEYR], true) +HELPER_HASH(HASHCHK, env->spr[SPR_POWER_HASHKEYR], false) +HELPER_HASH(HASHSTP, env->spr[SPR_POWER_HASHPKEYR], true) +HELPER_HASH(HASHCHKP, env->spr[SPR_POWER_HASHPKEYR], false) + #if !defined(CONFIG_USER_ONLY) #ifdef CONFIG_TCG diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 57da11c77ec9..70f8dcfbecd4 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -4,6 +4,10 @@ DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32) #endif +DEF_HELPER_4(HASHST, void, env, tl, tl, tl) +DEF_HELPER_4(HASHCHK, void, env, tl, tl, tl) +DEF_HELPER_4(HASHSTP, void, env, tl, tl, tl) +DEF_HELPER_4(HASHCHKP, void, env, tl, tl, tl) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(store_msr, void, env, tl) DEF_HELPER_1(rfi, void, env) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index ac2d3da9a781..0914a3fd724f 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -142,6 +142,9 @@ @X_TSX ...... ..... ra:5 rb:5 .......... . &X rt=%x_rt_tsx @X_TSXP ...... ..... ra:5 rb:5 .......... . &X rt=%rt_tsxp +%x_dw 0:1 21:5 !function=dw_compose_ea +@X_DW ...... ..... ra:5 rb:5 .......... . &X rt=%x_dw + &X_frtp_vrb frtp vrb @X_frtp_vrb ...... ....0 ..... vrb:5 .......... . &X_frtp_vrb frtp=%x_frtp @@ -281,6 +284,13 @@ CNTTZDM 011111 ..... ..... ..... 1000111011 - @X PDEPD 011111 ..... ..... ..... 0010011100 - @X PEXTD 011111 ..... ..... ..... 0010111100 - @X +# Fixed-Point Hash Instructions + +HASHST 011111 ..... ..... ..... 1011010010 . @X_DW +HASHCHK 011111 ..... ..... ..... 1011110010 . @X_DW +HASHSTP 011111 ..... ..... ..... 1010010010 . @X_DW +HASHCHKP 011111 ..... ..... ..... 1010110010 . @X_DW + ### Float-Point Load Instructions LFS 110000 ..... ..... ................ @D diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 408ae26173de..46188d0d3b7a 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6547,6 +6547,12 @@ static int times_16(DisasContext *ctx, int x) return x * 16; } +static int64_t dw_compose_ea(DisasContext *ctx, int x) +{ + int64_t ea = 0xfffffffffffffe00 | (x << 3); + return ea; +} + /* * Helpers for trans_* functions to check for specific insns flags. * Use token pasting to ensure that we use the proper flag with the diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 1aab32be0364..9c973c29bb61 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -492,3 +492,32 @@ static bool trans_PEXTD(DisasContext *ctx, arg_X *a) #endif return true; } + +static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, + void (*helper)(TCGv_ptr, TCGv, TCGv, TCGv)) +{ + TCGv ea = tcg_temp_new(); + + if (!(ctx->insns_flags2 & PPC2_ISA310)) { + /* if version is before v3.1, this operation is a nop */ + return true; + } + + if (unlikely(priv && ctx->pr)) { + /* if instruction is privileged but the context is in user space */ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return 0; + } + + tcg_gen_addi_tl(ea, cpu_gpr[a->ra], a->rt); + helper(cpu_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); + + tcg_temp_free(ea); + + return true; +} + +TRANS(HASHST, do_hash, false, gen_helper_HASHST) +TRANS(HASHCHK, do_hash, false, gen_helper_HASHCHK) +TRANS(HASHSTP, do_hash, true, gen_helper_HASHSTP) +TRANS(HASHCHKP, do_hash, true, gen_helper_HASHCHKP) From 7c4ee6465ca66371ddbc84560d25c224608ad651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Fri, 8 Apr 2022 11:21:28 -0300 Subject: [PATCH 2/7] fixup! target/ppc: Implement hashst(p) and hashchk(p) instructions --- target/ppc/excp_helper.c | 7 +++---- target/ppc/translate.c | 3 +-- target/ppc/translate/fixedpoint-impl.c.inc | 9 +++++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 8902c0b84777..54e8fc0b632e 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2174,8 +2174,8 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) { - uint32_t c = 0xfffc; - uint64_t z0 = 0xfa2561cdf44ac398; + const uint16_t c = 0xfffc; + const uint64_t z0 = 0xfa2561cdf44ac398ULL; uint16_t z = 0, temp; uint16_t k[32], eff_k[32], xleft[33], xright[33], fxleft[32]; @@ -2242,8 +2242,7 @@ void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ \ if (store) { \ cpu_stq_data_ra(env, ea, chash, GETPC()); \ - } \ - else { \ + } else { \ lhash = cpu_ldq_data_ra(env, ea, GETPC()); \ if (lhash != chash) { \ /* hashes don't match, trap */ \ diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 46188d0d3b7a..ecf13e00bc34 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6549,8 +6549,7 @@ static int times_16(DisasContext *ctx, int x) static int64_t dw_compose_ea(DisasContext *ctx, int x) { - int64_t ea = 0xfffffffffffffe00 | (x << 3); - return ea; + return deposit64(0xfffffffffffffe00, 3, 6, x); } /* diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 9c973c29bb61..e89d85a2a45d 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -496,7 +496,7 @@ static bool trans_PEXTD(DisasContext *ctx, arg_X *a) static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, void (*helper)(TCGv_ptr, TCGv, TCGv, TCGv)) { - TCGv ea = tcg_temp_new(); + TCGv ea; if (!(ctx->insns_flags2 & PPC2_ISA310)) { /* if version is before v3.1, this operation is a nop */ @@ -509,7 +509,12 @@ static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, return 0; } - tcg_gen_addi_tl(ea, cpu_gpr[a->ra], a->rt); + if (a->ra == 0) { + gen_invalid(ctx); + return true; + } + + ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->rt)); helper(cpu_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); tcg_temp_free(ea); From bdaf75d0e464ed791c849341da2c5fc18c6c0323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Fri, 8 Apr 2022 11:33:15 -0300 Subject: [PATCH 3/7] fixup! target/ppc: Implement hashst(p) and hashchk(p) instructions --- target/ppc/excp_helper.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 54e8fc0b632e..cb25881c0f1a 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2192,16 +2192,14 @@ static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1); } - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < 8; i++) { eff_k[4 * i + 0] = k[4 * i + ((0 + lane) % 4)]; eff_k[4 * i + 1] = k[4 * i + ((1 + lane) % 4)]; eff_k[4 * i + 2] = k[4 * i + ((2 + lane) % 4)]; eff_k[4 * i + 3] = k[4 * i + ((3 + lane) % 4)]; } - for (int i = 0; i < 32; i++) - { + for (int i = 0; i < 32; i++) { fxleft[i] = (rol16(xleft[i], 1) & rol16(xleft[i], 8)) ^ rol16(xleft[i], 2); xleft[i + 1] = xright[i] ^ fxleft[i] ^ eff_k[i]; From d4adde4ecb497b7c85ed6aed0f14ee89f49563b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Fri, 8 Apr 2022 11:49:08 -0300 Subject: [PATCH 4/7] fixup! target/ppc: Implement hashst(p) and hashchk(p) instructions --- target/ppc/excp_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index cb25881c0f1a..13a0bb4e1e3e 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2187,7 +2187,7 @@ static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) xright[0] = (x >> 16) & 0xffff; for (int i = 0; i < 28; i++) { - z |= ((z0 >> (63 - i)) & 1) << 48; + z = (z0 >> (63 - i)) & 1; temp = ror16(k[i + 3], 3) ^ k[i + 1]; k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1); } From 449b18b42a7f54525462756e89097ca8426d55cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Fri, 8 Apr 2022 13:31:47 -0300 Subject: [PATCH 5/7] target/ppc: Optimize hashchkp and hashstp when in CONFIG_USER_ONLY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a method equivalent to CHK_SV that works with decodetree. Use it in hash instructions to optimize when CONFIG_USER_ONLY is defined. Suggested-by: Matheus Ferst Signed-off-by: Víctor Colombo --- target/ppc/translate.c | 12 ++++++++++++ target/ppc/translate/fixedpoint-impl.c.inc | 5 ++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index ecf13e00bc34..5b7c60adf089 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -1300,6 +1300,18 @@ typedef struct opcode_t { #define CHK_NONE +/* Helper for priv. check to be used in decodetree */ +static inline bool do_check_sv(DisasContext *ctx) +{ +#if !defined(CONFIG_USER_ONLY) + if (likely(ctx->pr != 0)) { + return false; + } +#endif + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; +} + /*****************************************************************************/ /* PowerPC instructions table */ diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index e89d85a2a45d..5cc1cfc325e1 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -503,10 +503,9 @@ static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, return true; } - if (unlikely(priv && ctx->pr)) { + if (unlikely(priv && do_check_sv(ctx))) { /* if instruction is privileged but the context is in user space */ - gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return 0; + return true; } if (a->ra == 0) { From 73c616ddfe5417eb83b9a0ab5f959b713d21d3eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Fri, 8 Apr 2022 14:18:44 -0300 Subject: [PATCH 6/7] fixup! target/ppc: Optimize hashchkp and hashstp when in CONFIG_USER_ONLY --- target/ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 5b7c60adf089..6c3df6c0a640 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -1301,7 +1301,7 @@ typedef struct opcode_t { #define CHK_NONE /* Helper for priv. check to be used in decodetree */ -static inline bool do_check_sv(DisasContext *ctx) +static bool do_check_sv(DisasContext *ctx) { #if !defined(CONFIG_USER_ONLY) if (likely(ctx->pr != 0)) { From 2611404a9c75651e1d6db3477c9599744eea4392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Colombo?= Date: Fri, 8 Apr 2022 14:19:09 -0300 Subject: [PATCH 7/7] fixup! target/ppc: Implement hashst(p) and hashchk(p) instructions --- target/ppc/translate/fixedpoint-impl.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 5cc1cfc325e1..4c1e978bdee1 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -508,7 +508,7 @@ static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, return true; } - if (a->ra == 0) { + if (unlikely(a->ra == 0)) { gen_invalid(ctx); return true; }