diff --git a/qemu/target/i386/cpu.c b/qemu/target/i386/cpu.c index 86103b09e3..59af62c5d5 100644 --- a/qemu/target/i386/cpu.c +++ b/qemu/target/i386/cpu.c @@ -631,11 +631,10 @@ static CPUCacheInfo legacy_l3_cache = { CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \ - CPUID_7_0_EBX_ERMS) + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RDSEED) /* missing: CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, - CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, - CPUID_7_0_EBX_RDSEED */ + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ CPUID_7_0_ECX_LA57) diff --git a/qemu/target/i386/translate.c b/qemu/target/i386/translate.c index 5cfbd680e7..5893e576cd 100644 --- a/qemu/target/i386/translate.c +++ b/qemu/target/i386/translate.c @@ -5845,12 +5845,20 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 7: /* RDSEED */ + if (mod != 3 || + (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || + !(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + goto illegal_op; + } + goto do_rdrand; + case 6: /* RDRAND */ if (mod != 3 || (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || !(s->cpuid_ext_features & CPUID_EXT_RDRAND)) { goto illegal_op; } + do_rdrand: if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(tcg_ctx); } diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 8deb08daed..87543a38bc 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -2377,6 +2377,30 @@ static void test_x86_hook_insn_rdtscp(void) OK(uc_close(uc)); } +static void test_x86_rdseed(void) +{ + char code[] = "\x48\x0F\xC7\xFB"; // RDSEED RBX + uc_engine *uc; + + // RDSEED requires CPU support. + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_ctl_set_cpu_model(uc, UC_CPU_X86_HASWELL)); + OK(uc_mem_map(uc, code_start, code_len, UC_PROT_ALL)); + OK(uc_mem_write(uc, code_start, code, sizeof(code) - 1)); + uc_assert_err(UC_ERR_INSN_INVALID, + uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, + 0, 0)); + + OK(uc_close(uc)); + + // RDSEED executes on supported CPUs. + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_ctl_set_cpu_model(uc, UC_CPU_X86_BROADWELL)); + OK(uc_mem_map(uc, code_start, code_len, UC_PROT_ALL)); + OK(uc_mem_write(uc, code_start, code, sizeof(code) - 1)); + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + OK(uc_close(uc)); +} static int test_x86_hook_insn_wrmsr_cb(uc_engine *uc, void *user_data) { *(int *)user_data = 1; @@ -2802,6 +2826,7 @@ TEST_LIST = { {"test_x86_ro_segfault", test_x86_ro_segfault}, {"test_x86_hook_insn_rdtsc", test_x86_hook_insn_rdtsc}, {"test_x86_hook_insn_rdtscp", test_x86_hook_insn_rdtscp}, + {"test_x86_rdseed", test_x86_rdseed}, {"test_x86_hook_insn_wrmsr", test_x86_hook_insn_wrmsr}, {"test_x86_hook_insn_rdmsr", test_x86_hook_insn_rdmsr}, {"test_x86_dr7", test_x86_dr7},