diff mbox series

[6/7] target/i386: implement RDPID in TCG

Message ID 20230618215114.107337-7-pbonzini@redhat.com
State New
Headers show
Series target/i386: add a few simple features | expand

Commit Message

Paolo Bonzini June 18, 2023, 9:51 p.m. UTC
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).
For BSD, just return 0.

RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms
of serializability are not relevant to QEMU.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 linux-user/i386/target_cpu.h   |  8 ++++++++
 linux-user/x86_64/target_cpu.h |  1 +
 target/i386/cpu.c              | 10 +++++++++-
 target/i386/helper.h           |  2 +-
 target/i386/tcg/misc_helper.c  | 21 +++++++++++++++------
 target/i386/tcg/translate.c    | 15 +++++++++++++--
 6 files changed, 47 insertions(+), 10 deletions(-)

Comments

Richard Henderson June 19, 2023, 7:40 a.m. UTC | #1
On 6/18/23 23:51, Paolo Bonzini wrote:
> 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).
> For BSD, just return 0.
> 
> RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms
> of serializability are not relevant to QEMU.
> 
> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
> ---
>   linux-user/i386/target_cpu.h   |  8 ++++++++
>   linux-user/x86_64/target_cpu.h |  1 +
>   target/i386/cpu.c              | 10 +++++++++-
>   target/i386/helper.h           |  2 +-
>   target/i386/tcg/misc_helper.c  | 21 +++++++++++++++------
>   target/i386/tcg/translate.c    | 15 +++++++++++++--
>   6 files changed, 47 insertions(+), 10 deletions(-)
> 
> diff --git a/linux-user/i386/target_cpu.h b/linux-user/i386/target_cpu.h
> index 52caf788cc3..3539f790222 100644
> --- a/linux-user/i386/target_cpu.h
> +++ b/linux-user/i386/target_cpu.h
> @@ -54,4 +54,12 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
>   {
>       return state->regs[R_ESP];
>   }
> +
> +static inline uint32_t get_cpunode(void)
> +{
> +    unsigned cpu, node;
> +    getcpu(&cpu, &node);
> +    return (node << 12) | (cpu & 0xfff);
> +}
> +

What is our minimum glibc version?  This requires 2.29.

Also, not especially fond of the placement.  target/ including linux-user/ header isn't 
nice.  Might as well just place these 3 lines in misc_helper.c to begin.

r~
Paolo Bonzini June 20, 2023, 2:38 p.m. UTC | #2
On Mon, Jun 19, 2023 at 9:40 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
> What is our minimum glibc version?  This requires 2.29.

Ok, I'll add a test to meson.build.

> Also, not especially fond of the placement.  target/ including linux-user/ header isn't
> nice.  Might as well just place these 3 lines in misc_helper.c to begin.

Ok. Can be revisited later if BSD needs it, or split between sysemu/
and user/ so that the include is less jarring.

Thanks,

Paolo
diff mbox series

Patch

diff --git a/linux-user/i386/target_cpu.h b/linux-user/i386/target_cpu.h
index 52caf788cc3..3539f790222 100644
--- a/linux-user/i386/target_cpu.h
+++ b/linux-user/i386/target_cpu.h
@@ -54,4 +54,12 @@  static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
 {
     return state->regs[R_ESP];
 }
+
+static inline uint32_t get_cpunode(void)
+{
+    unsigned cpu, node;
+    getcpu(&cpu, &node);
+    return (node << 12) | (cpu & 0xfff);
+}
+
 #endif /* I386_TARGET_CPU_H */
diff --git a/linux-user/x86_64/target_cpu.h b/linux-user/x86_64/target_cpu.h
index 9ec7cbb7a4c..dec2e24f5a3 100644
--- a/linux-user/x86_64/target_cpu.h
+++ b/linux-user/x86_64/target_cpu.h
@@ -1 +1,2 @@ 
+#include "target_syscall.h"
 #include "../i386/target_cpu.h"
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 8e12616db5e..68218103108 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -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)
diff --git a/target/i386/helper.h b/target/i386/helper.h
index e627a931073..4e308aae643 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -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
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 5f7a3061ca5..9bcbf6fd60d 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -24,6 +24,10 @@ 
 #include "exec/exec-all.h"
 #include "helper-tcg.h"
 
+#if defined CONFIG_USER_ONLY && defined CONFIG_LINUX
+#include "target_cpu.h"
+#endif
+
 /*
  * NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
  * after generating a call to a helper that uses this.
@@ -75,12 +79,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 +135,14 @@  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
+    return get_cpunode();
+#else
+    return 0;
+#endif
+}
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 9783fe80a30..9023f47fa69 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3924,7 +3924,16 @@  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) &&
+                (s->prefix & PREFIX_REPZ) &&
+                (s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) {
+                gen_helper_rdpid(s->T0, cpu_env);
+                rm = (modrm & 7) | REX_B(s);
+                gen_op_mov_reg_v(s, dflag, rm, s->T0);
+                break;
+            }
+            /* fallthrough */
         case 6: /* RDRAND */
             if (mod != 3 ||
                 (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) ||
@@ -6108,7 +6117,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: