aboutsummaryrefslogtreecommitdiff
path: root/target/i386/translate.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2019-03-14 20:01:42 -0700
committerRichard Henderson <richard.henderson@linaro.org>2019-05-22 12:38:54 -0400
commit369fd5ca66810b2ddb16e23a497eabe59385eceb (patch)
tree1fb3bf56e7df2e7f8ef9ccf2d16cf891665efd6d /target/i386/translate.c
parent3f74b6322cec37d23351df8caccfdfd85dceff9b (diff)
target/i386: Implement CPUID_EXT_RDRAND
We now have an interface for guest visible random numbers. Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/i386/translate.c')
-rw-r--r--target/i386/translate.c62
1 files changed, 47 insertions, 15 deletions
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;
/**************************/