diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 9f18fa090f1f1..4ae4718143fab 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 047b24ba50ead..9b16b4e7bac12 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 073fd101687cc..fc0c04cc2c906 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 d3e2cfcd7120a..13a0bb4e1e3e9 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2172,6 +2172,89 @@ 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) +{ + 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]; + + 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; + 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 57da11c77ec9c..70f8dcfbecd41 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 ac2d3da9a781b..0914a3fd724ff 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 408ae26173de6..6c3df6c0a640c 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 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 */ @@ -6547,6 +6559,11 @@ static int times_16(DisasContext *ctx, int x) return x * 16; } +static int64_t dw_compose_ea(DisasContext *ctx, int x) +{ + return deposit64(0xfffffffffffffe00, 3, 6, x); +} + /* * 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 1aab32be03641..4c1e978bdee19 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -492,3 +492,36 @@ 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; + + if (!(ctx->insns_flags2 & PPC2_ISA310)) { + /* if version is before v3.1, this operation is a nop */ + return true; + } + + if (unlikely(priv && do_check_sv(ctx))) { + /* if instruction is privileged but the context is in user space */ + return true; + } + + if (unlikely(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); + + 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)