aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-05-23 12:57:17 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-05-23 12:57:17 +0100
commitd418238dca7b4e0b124135827ead3076233052b1 (patch)
tree5869c8301e18962d3ddb4e927e152220c21ce33f /target
parentc4600d5d417ea13e0f1cc047b227a2b5b0e694f5 (diff)
parent369fd5ca66810b2ddb16e23a497eabe59385eceb (diff)
Merge remote-tracking branch 'remotes/rth/tags/pull-rng-20190522' into staging
Introduce qemu_guest_getrandom. Use qemu_guest_getrandom in aspeed, nrf51, bcm2835, exynos4210 rng devices. Use qemu_guest_getrandom in target/ppc darn instruction. Support ARMv8.5-RNG extension. Support x86 RDRAND extension. Acked-by: Daniel P. Berrangé <berrange@redhat.com> Acked-by: Laurent Vivier <laurent@vivier.eu> # gpg: Signature made Wed 22 May 2019 19:36:43 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-rng-20190522: (25 commits) target/i386: Implement CPUID_EXT_RDRAND target/ppc: Use qemu_guest_getrandom for DARN target/ppc: Use gen_io_start/end around DARN target/arm: Implement ARMv8.5-RNG target/arm: Put all PAC keys into a structure hw/misc/exynos4210_rng: Use qemu_guest_getrandom hw/misc/bcm2835_rng: Use qemu_guest_getrandom_nofail hw/misc/nrf51_rng: Use qemu_guest_getrandom_nofail aspeed/scu: Use qemu_guest_getrandom_nofail linux-user: Remove srand call linux-user/aarch64: Use qemu_guest_getrandom for PAUTH keys linux-user: Use qemu_guest_getrandom_nofail for AT_RANDOM linux-user: Call qcrypto_init if not using -seed linux-user: Initialize pseudo-random seeds for all guest cpus cpus: Initialize pseudo-random seeds for all guest cpus util: Add qemu_guest_getrandom and associated routines ui/vnc: Use gcrypto_random_bytes for start_auth_vnc ui/vnc: Split out authentication_failed crypto: Change the qcrypto_random_bytes buffer type to void* crypto: Use getrandom for qcrypto_random_bytes ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/arm/cpu.h17
-rw-r--r--target/arm/cpu64.c1
-rw-r--r--target/arm/helper.c64
-rw-r--r--target/arm/pauth_helper.c18
-rw-r--r--target/i386/cpu.c5
-rw-r--r--target/i386/helper.h2
-rw-r--r--target/i386/int_helper.c21
-rw-r--r--target/i386/translate.c62
-rw-r--r--target/ppc/int_helper.c37
-rw-r--r--target/ppc/translate.c21
10 files changed, 190 insertions, 58 deletions
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 733b840a71..c34207611b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -636,11 +636,13 @@ typedef struct CPUARMState {
} iwmmxt;
#ifdef TARGET_AARCH64
- ARMPACKey apia_key;
- ARMPACKey apib_key;
- ARMPACKey apda_key;
- ARMPACKey apdb_key;
- ARMPACKey apga_key;
+ struct {
+ ARMPACKey apia;
+ ARMPACKey apib;
+ ARMPACKey apda;
+ ARMPACKey apdb;
+ ARMPACKey apga;
+ } keys;
#endif
#if defined(CONFIG_USER_ONLY)
@@ -3519,6 +3521,11 @@ static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2;
}
+static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0;
+}
+
static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0;
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 228906f267..835f73cceb 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -310,6 +310,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1);
t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1);
t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */
+ t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1);
cpu->isar.id_aa64isar0 = t;
t = cpu->isar.id_aa64isar1;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e2d5c8e34f..acd23c53ca 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -22,6 +22,8 @@
#include "fpu/softfloat.h"
#include "qemu/range.h"
#include "qapi/qapi-commands-target.h"
+#include "qapi/error.h"
+#include "qemu/guest-random.h"
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
@@ -5707,43 +5709,82 @@ static const ARMCPRegInfo pauth_reginfo[] = {
{ .name = "APDAKEYLO_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 0,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apda_key.lo) },
+ .fieldoffset = offsetof(CPUARMState, keys.apda.lo) },
{ .name = "APDAKEYHI_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 1,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apda_key.hi) },
+ .fieldoffset = offsetof(CPUARMState, keys.apda.hi) },
{ .name = "APDBKEYLO_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 2,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apdb_key.lo) },
+ .fieldoffset = offsetof(CPUARMState, keys.apdb.lo) },
{ .name = "APDBKEYHI_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 3,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apdb_key.hi) },
+ .fieldoffset = offsetof(CPUARMState, keys.apdb.hi) },
{ .name = "APGAKEYLO_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 3, .opc2 = 0,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apga_key.lo) },
+ .fieldoffset = offsetof(CPUARMState, keys.apga.lo) },
{ .name = "APGAKEYHI_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 3, .opc2 = 1,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apga_key.hi) },
+ .fieldoffset = offsetof(CPUARMState, keys.apga.hi) },
{ .name = "APIAKEYLO_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 0,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apia_key.lo) },
+ .fieldoffset = offsetof(CPUARMState, keys.apia.lo) },
{ .name = "APIAKEYHI_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 1,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apia_key.hi) },
+ .fieldoffset = offsetof(CPUARMState, keys.apia.hi) },
{ .name = "APIBKEYLO_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 2,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apib_key.lo) },
+ .fieldoffset = offsetof(CPUARMState, keys.apib.lo) },
{ .name = "APIBKEYHI_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 3,
.access = PL1_RW, .accessfn = access_pauth,
- .fieldoffset = offsetof(CPUARMState, apib_key.hi) },
+ .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
+ REGINFO_SENTINEL
+};
+
+static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ Error *err = NULL;
+ uint64_t ret;
+
+ /* Success sets NZCV = 0000. */
+ env->NF = env->CF = env->VF = 0, env->ZF = 1;
+
+ if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
+ /*
+ * ??? Failed, for unknown reasons in the crypto subsystem.
+ * The best we can do is log the reason and return the
+ * timed-out indication to the guest. There is no reason
+ * we know to expect this failure to be transitory, so the
+ * guest may well hang retrying the operation.
+ */
+ qemu_log_mask(LOG_UNIMP, "%s: Crypto failure: %s",
+ ri->name, error_get_pretty(err));
+ error_free(err);
+
+ env->ZF = 0; /* NZCF = 0100 */
+ return 0;
+ }
+ return ret;
+}
+
+/* We do not support re-seeding, so the two registers operate the same. */
+static const ARMCPRegInfo rndr_reginfo[] = {
+ { .name = "RNDR", .state = ARM_CP_STATE_AA64,
+ .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
+ .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
+ .access = PL0_R, .readfn = rndr_readfn },
+ { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
+ .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
+ .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
+ .access = PL0_R, .readfn = rndr_readfn },
REGINFO_SENTINEL
};
#endif
@@ -6690,6 +6731,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (cpu_isar_feature(aa64_pauth, cpu)) {
define_arm_cp_regs(cpu, pauth_reginfo);
}
+ if (cpu_isar_feature(aa64_rndr, cpu)) {
+ define_arm_cp_regs(cpu, rndr_reginfo);
+ }
#endif
/*
diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c
index d750f96edf..7f30ae7395 100644
--- a/target/arm/pauth_helper.c
+++ b/target/arm/pauth_helper.c
@@ -403,7 +403,7 @@ uint64_t HELPER(pacia)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_addpac(env, x, y, &env->apia_key, false);
+ return pauth_addpac(env, x, y, &env->keys.apia, false);
}
uint64_t HELPER(pacib)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -413,7 +413,7 @@ uint64_t HELPER(pacib)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_addpac(env, x, y, &env->apib_key, false);
+ return pauth_addpac(env, x, y, &env->keys.apib, false);
}
uint64_t HELPER(pacda)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -423,7 +423,7 @@ uint64_t HELPER(pacda)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_addpac(env, x, y, &env->apda_key, true);
+ return pauth_addpac(env, x, y, &env->keys.apda, true);
}
uint64_t HELPER(pacdb)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -433,7 +433,7 @@ uint64_t HELPER(pacdb)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_addpac(env, x, y, &env->apdb_key, true);
+ return pauth_addpac(env, x, y, &env->keys.apdb, true);
}
uint64_t HELPER(pacga)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -441,7 +441,7 @@ uint64_t HELPER(pacga)(CPUARMState *env, uint64_t x, uint64_t y)
uint64_t pac;
pauth_check_trap(env, arm_current_el(env), GETPC());
- pac = pauth_computepac(x, y, env->apga_key);
+ pac = pauth_computepac(x, y, env->keys.apga);
return pac & 0xffffffff00000000ull;
}
@@ -453,7 +453,7 @@ uint64_t HELPER(autia)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_auth(env, x, y, &env->apia_key, false, 0);
+ return pauth_auth(env, x, y, &env->keys.apia, false, 0);
}
uint64_t HELPER(autib)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -463,7 +463,7 @@ uint64_t HELPER(autib)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_auth(env, x, y, &env->apib_key, false, 1);
+ return pauth_auth(env, x, y, &env->keys.apib, false, 1);
}
uint64_t HELPER(autda)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -473,7 +473,7 @@ uint64_t HELPER(autda)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_auth(env, x, y, &env->apda_key, true, 0);
+ return pauth_auth(env, x, y, &env->keys.apda, true, 0);
}
uint64_t HELPER(autdb)(CPUARMState *env, uint64_t x, uint64_t y)
@@ -483,7 +483,7 @@ uint64_t HELPER(autdb)(CPUARMState *env, uint64_t x, uint64_t y)
return x;
}
pauth_check_trap(env, el, GETPC());
- return pauth_auth(env, x, y, &env->apdb_key, true, 1);
+ return pauth_auth(env, x, y, &env->keys.apdb, true, 1);
}
uint64_t HELPER(xpaci)(CPUARMState *env, uint64_t a)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 2f151dad8c..536d7d1520 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -730,13 +730,14 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | \
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \
- CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR)
+ CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR | \
+ CPUID_EXT_RDRAND)
/* missing:
CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX,
CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA,
CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA,
CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AVX,
- CPUID_EXT_F16C, CPUID_EXT_RDRAND */
+ CPUID_EXT_F16C */
#ifdef TARGET_X86_64
#define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM)
diff --git a/target/i386/helper.h b/target/i386/helper.h
index 6fb8fb9b74..8f9e1905c3 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -226,3 +226,5 @@ DEF_HELPER_3(rcrl, tl, env, tl, tl)
DEF_HELPER_3(rclq, tl, env, tl, tl)
DEF_HELPER_3(rcrq, tl, env, tl, tl)
#endif
+
+DEF_HELPER_1(rdrand, tl, env)
diff --git a/target/i386/int_helper.c b/target/i386/int_helper.c
index 4dc5c65991..334469ca8c 100644
--- a/target/i386/int_helper.c
+++ b/target/i386/int_helper.c
@@ -22,6 +22,8 @@
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
+#include "qapi/error.h"
+#include "qemu/guest-random.h"
//#define DEBUG_MULDIV
@@ -470,3 +472,22 @@ void helper_cr4_testbit(CPUX86State *env, uint32_t bit)
raise_exception_ra(env, EXCP06_ILLOP, GETPC());
}
}
+
+target_ulong HELPER(rdrand)(CPUX86State *env)
+{
+ Error *err = NULL;
+ target_ulong ret;
+
+ if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
+ qemu_log_mask(LOG_UNIMP, "rdrand: Crypto failure: %s",
+ error_get_pretty(err));
+ error_free(err);
+ /* Failure clears CF and all other flags, and returns 0. */
+ env->cc_src = 0;
+ return 0;
+ }
+
+ /* Success sets CF and clears all others. */
+ env->cc_src = CC_C;
+ return ret;
+}
diff --git a/target/i386/translate.c b/target/i386/translate.c
index 77d6b73e42..03150a86e2 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -5332,31 +5332,63 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x1c7: /* cmpxchg8b */
modrm = x86_ldub_code(env, s);
mod = (modrm >> 6) & 3;
- if ((mod == 3) || ((modrm & 0x38) != 0x8))
- goto illegal_op;
-#ifdef TARGET_X86_64
- if (dflag == MO_64) {
- if (!(s->cpuid_ext_features & CPUID_EXT_CX16))
+ switch ((modrm >> 3) & 7) {
+ case 1: /* CMPXCHG8, CMPXCHG16 */
+ if (mod == 3) {
goto illegal_op;
- gen_lea_modrm(env, s, modrm);
- if ((s->prefix & PREFIX_LOCK) && (tb_cflags(s->base.tb) & CF_PARALLEL)) {
- gen_helper_cmpxchg16b(cpu_env, s->A0);
- } else {
- gen_helper_cmpxchg16b_unlocked(cpu_env, s->A0);
}
- } else
+#ifdef TARGET_X86_64
+ if (dflag == MO_64) {
+ if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) {
+ goto illegal_op;
+ }
+ gen_lea_modrm(env, s, modrm);
+ if ((s->prefix & PREFIX_LOCK) &&
+ (tb_cflags(s->base.tb) & CF_PARALLEL)) {
+ gen_helper_cmpxchg16b(cpu_env, s->A0);
+ } else {
+ gen_helper_cmpxchg16b_unlocked(cpu_env, s->A0);
+ }
+ set_cc_op(s, CC_OP_EFLAGS);
+ break;
+ }
#endif
- {
- if (!(s->cpuid_features & CPUID_CX8))
+ if (!(s->cpuid_features & CPUID_CX8)) {
goto illegal_op;
+ }
gen_lea_modrm(env, s, modrm);
- if ((s->prefix & PREFIX_LOCK) && (tb_cflags(s->base.tb) & CF_PARALLEL)) {
+ if ((s->prefix & PREFIX_LOCK) &&
+ (tb_cflags(s->base.tb) & CF_PARALLEL)) {
gen_helper_cmpxchg8b(cpu_env, s->A0);
} else {
gen_helper_cmpxchg8b_unlocked(cpu_env, s->A0);
}
+ set_cc_op(s, CC_OP_EFLAGS);
+ break;
+
+ case 7: /* RDSEED */
+ case 6: /* RDRAND */
+ if (mod != 3 ||
+ (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) ||
+ !(s->cpuid_ext_features & CPUID_EXT_RDRAND)) {
+ goto illegal_op;
+ }
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_rdrand(s->T0, cpu_env);
+ rm = (modrm & 7) | REX_B(s);
+ gen_op_mov_reg_v(s, dflag, rm, s->T0);
+ set_cc_op(s, CC_OP_EFLAGS);
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_end();
+ gen_jmp(s, s->pc - s->cs_base);
+ }
+ break;
+
+ default:
+ goto illegal_op;
}
- set_cc_op(s, CC_OP_EFLAGS);
break;
/**************************/
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index f6a088ac08..9af779ad38 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -23,6 +23,8 @@
#include "exec/helper-proto.h"
#include "crypto/aes.h"
#include "fpu/softfloat.h"
+#include "qapi/error.h"
+#include "qemu/guest-random.h"
#include "helper_regs.h"
/*****************************************************************************/
@@ -158,24 +160,37 @@ uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb)
#undef hasvalue
/*
- * Return invalid random number.
- *
- * FIXME: Add rng backend or other mechanism to get cryptographically suitable
- * random number
+ * Return a random number.
*/
-target_ulong helper_darn32(void)
+uint64_t helper_darn32(void)
{
- return -1;
+ Error *err = NULL;
+ uint32_t ret;
+
+ if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
+ qemu_log_mask(LOG_UNIMP, "darn: Crypto failure: %s",
+ error_get_pretty(err));
+ error_free(err);
+ return -1;
+ }
+
+ return ret;
}
-target_ulong helper_darn64(void)
+uint64_t helper_darn64(void)
{
- return -1;
-}
+ Error *err = NULL;
+ uint64_t ret;
-#endif
+ if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
+ qemu_log_mask(LOG_UNIMP, "darn: Crypto failure: %s",
+ error_get_pretty(err));
+ error_free(err);
+ return -1;
+ }
-#if defined(TARGET_PPC64)
+ return ret;
+}
uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
{
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index b5217f632f..4a5de28036 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -1847,13 +1847,22 @@ static void gen_darn(DisasContext *ctx)
{
int l = L(ctx->opcode);
- if (l == 0) {
- gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]);
- } else if (l <= 2) {
- /* Return 64-bit random for both CRN and RRN */
- gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]);
- } else {
+ if (l > 2) {
tcg_gen_movi_i64(cpu_gpr[rD(ctx->opcode)], -1);
+ } else {
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ if (l == 0) {
+ gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]);
+ } else {
+ /* Return 64-bit random for both CRN and RRN */
+ gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]);
+ }
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_end();
+ gen_stop_exception(ctx);
+ }
}
}
#endif