target/i386: Implement CPUID_EXT_RDRAND

We now have an interface for guest visible random numbers.

Backports commit 369fd5ca66810b2ddb16e23a497eabe59385eceb from qemu with
the actual RNG portion disabled for the time being.
This commit is contained in:
Richard Henderson 2019-05-23 15:09:23 -04:00 committed by Lioncash
parent 3dd7358a53
commit 0412b3be8a
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7
4 changed files with 69 additions and 16 deletions

View File

@ -720,13 +720,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)

View File

@ -228,3 +228,6 @@ 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)

View File

@ -470,3 +470,25 @@ void helper_cr4_testbit(CPUX86State *env, uint32_t bit)
raise_exception_ra(env, EXCP06_ILLOP, GETPC());
}
}
target_ulong HELPER(rdrand)(CPUX86State *env)
{
target_ulong ret = 0;
// Unicorn: Commented out to avoid depending on the host for the time being.
#if 0
Error *err = NULL;
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;
}
#endif
/* Success sets CF and clears all others. */
env->cc_src = CC_C;
return ret;
}

View File

@ -5859,31 +5859,58 @@ 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(tcg_ctx, cpu_env, s->A0);
} else {
gen_helper_cmpxchg16b_unlocked(tcg_ctx, 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(tcg_ctx, cpu_env, s->A0);
} else {
gen_helper_cmpxchg16b_unlocked(tcg_ctx, 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)) {
gen_helper_cmpxchg8b(tcg_ctx, cpu_env, s->A0);
} else {
gen_helper_cmpxchg8b_unlocked(tcg_ctx, 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;
}
gen_helper_rdrand(tcg_ctx, 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_jmp(s, s->pc - s->cs_base);
}
break;
default:
goto illegal_op;
}
set_cc_op(s, CC_OP_EFLAGS);
break;
/**************************/