target/i386: implement RDPID in TCG
RDPID corresponds to a RDMSR(TSC_AUX); however, it is unprivileged so for user-mode emulation we must provide the value that the kernel places in the MSR. For Linux, it is a combination of the current CPU and the current NUMA node, both of which can be retrieved with getcpu(2). Also try sched_getcpu(), which might be there on the BSDs. If there is no portable way to retrieve the current CPU id from userspace, return 0. RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms of serializability are not relevant to QEMU. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
53b9b4cc9f
commit
6750485bf4
@ -2232,6 +2232,8 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime'))
|
||||
config_host_data.set('CONFIG_DUP3', cc.has_function('dup3'))
|
||||
config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate'))
|
||||
config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
|
||||
config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix))
|
||||
config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include <sched.h>'))
|
||||
# Note that we need to specify prefix: here to avoid incorrectly
|
||||
# thinking that Windows has posix_memalign()
|
||||
config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include <stdlib.h>'))
|
||||
|
@ -661,9 +661,17 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
|
||||
/* missing:
|
||||
CPUID_7_0_EBX_HLE
|
||||
CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */
|
||||
|
||||
#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX
|
||||
#define TCG_7_0_ECX_RDPID CPUID_7_0_ECX_RDPID
|
||||
#else
|
||||
#define TCG_7_0_ECX_RDPID 0
|
||||
#endif
|
||||
#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \
|
||||
/* CPUID_7_0_ECX_OSPKE is dynamic */ \
|
||||
CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES)
|
||||
CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES | \
|
||||
TCG_7_0_ECX_RDPID)
|
||||
|
||||
#define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM
|
||||
#define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \
|
||||
CPUID_7_1_EAX_FSRC)
|
||||
|
@ -69,8 +69,8 @@ DEF_HELPER_2(into, void, env, int)
|
||||
DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env)
|
||||
DEF_HELPER_1(rechecking_single_step, void, env)
|
||||
DEF_HELPER_1(cpuid, void, env)
|
||||
DEF_HELPER_FLAGS_1(rdpid, TCG_CALL_NO_WG, tl, env)
|
||||
DEF_HELPER_1(rdtsc, void, env)
|
||||
DEF_HELPER_1(rdtscp, void, env)
|
||||
DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@ -75,12 +75,6 @@ void helper_rdtsc(CPUX86State *env)
|
||||
env->regs[R_EDX] = (uint32_t)(val >> 32);
|
||||
}
|
||||
|
||||
void helper_rdtscp(CPUX86State *env)
|
||||
{
|
||||
helper_rdtsc(env);
|
||||
env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
|
||||
}
|
||||
|
||||
G_NORETURN void helper_rdpmc(CPUX86State *env)
|
||||
{
|
||||
if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
|
||||
@ -137,3 +131,18 @@ void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
|
||||
env->pkru = val;
|
||||
tlb_flush(cs);
|
||||
}
|
||||
|
||||
target_ulong HELPER(rdpid)(CPUX86State *env)
|
||||
{
|
||||
#if defined CONFIG_SOFTMMU
|
||||
return env->tsc_aux;
|
||||
#elif defined CONFIG_LINUX && defined CONFIG_GETCPU
|
||||
unsigned cpu, node;
|
||||
getcpu(&cpu, &node);
|
||||
return (node << 12) | (cpu & 0xfff);
|
||||
#elif defined CONFIG_SCHED_GETCPU
|
||||
return sched_getcpu();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -3924,13 +3924,25 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
|
||||
gen_cmpxchg8b(s, env, modrm);
|
||||
break;
|
||||
|
||||
case 7: /* RDSEED */
|
||||
case 7: /* RDSEED, RDPID with f3 prefix */
|
||||
if (mod != 3 ||
|
||||
(s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) ||
|
||||
!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) {
|
||||
(s->prefix & (PREFIX_LOCK | PREFIX_REPNZ))) {
|
||||
goto illegal_op;
|
||||
}
|
||||
if (s->prefix & PREFIX_REPZ) {
|
||||
if (!(s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_helper_rdpid(s->T0, cpu_env);
|
||||
rm = (modrm & 7) | REX_B(s);
|
||||
gen_op_mov_reg_v(s, dflag, rm, s->T0);
|
||||
break;
|
||||
} else {
|
||||
if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
goto do_rdrand;
|
||||
}
|
||||
|
||||
case 6: /* RDRAND */
|
||||
if (mod != 3 ||
|
||||
@ -6125,7 +6137,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
|
||||
gen_update_cc_op(s);
|
||||
gen_update_eip_cur(s);
|
||||
translator_io_start(&s->base);
|
||||
gen_helper_rdtscp(cpu_env);
|
||||
gen_helper_rdtsc(cpu_env);
|
||||
gen_helper_rdpid(s->T0, cpu_env);
|
||||
gen_op_mov_reg_v(s, dflag, R_ECX, s->T0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user