qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 4/4] TCG x86: add RDTSCP support


From: Andre Przywara
Subject: [Qemu-devel] [PATCH 4/4] TCG x86: add RDTSCP support
Date: Sat, 19 Sep 2009 00:30:49 +0200

RDTSCP reads the time stamp counter and atomically also the content
of a 32-bit MSR, which can be freely set by the OS. This allows CPU
local data to be queried by userspace.
Linux uses this to allow a fast implementation of the getcpu()
syscall, which uses the vsyscall page to avoid a context switch.
AMD CPUs since K8RevF and Intel CPUs since Nehalem support this
instruction.
RDTSCP is guarded by the RDTSCP CPUID bit (Fn8000_0001:EDX[27]).

Signed-off-by: Andre Przywara <address@hidden>
---
 target-i386/cpu.h       |    5 +++-
 target-i386/helper.h    |    1 +
 target-i386/machine.c   |    4 +++
 target-i386/op_helper.c |   12 ++++++++++
 target-i386/translate.c |   57 ++++++++++++++++++++++++++++++++++------------
 5 files changed, 63 insertions(+), 16 deletions(-)

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index b9a6392..f318942 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -322,6 +322,7 @@
 #define MSR_FSBASE                      0xc0000100
 #define MSR_GSBASE                      0xc0000101
 #define MSR_KERNELGSBASE                0xc0000102
+#define MSR_TSC_AUX                     0xc0000103
 
 #define MSR_VM_HSAVE_PA                 0xc0010117
 
@@ -694,6 +695,8 @@ typedef struct CPUX86State {
     uint64 mcg_status;
     uint64 mcg_ctl;
     uint64 *mce_banks;
+
+    uint64_t tsc_aux;
 } CPUX86State;
 
 CPUX86State *cpu_x86_init(const char *cpu_model);
@@ -854,7 +857,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 #define cpu_signal_handler cpu_x86_signal_handler
 #define cpu_list x86_cpu_list
 
-#define CPU_SAVE_VERSION 10
+#define CPU_SAVE_VERSION 11
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 38d0708..ef8d4e1 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -80,6 +80,7 @@ DEF_HELPER_1(cmpxchg16b, void, tl)
 DEF_HELPER_0(single_step, void)
 DEF_HELPER_0(cpuid, void)
 DEF_HELPER_0(rdtsc, void)
+DEF_HELPER_0(rdtscp, void)
 DEF_HELPER_0(rdpmc, void)
 DEF_HELPER_0(rdmsr, void)
 DEF_HELPER_0(wrmsr, void)
diff --git a/target-i386/machine.c b/target-i386/machine.c
index ab31329..e5a060f 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -171,6 +171,7 @@ void cpu_save(QEMUFile *f, void *opaque)
             qemu_put_be64s(f, &env->mce_banks[4*i + 3]);
         }
     }
+    qemu_put_be64s(f, &env->tsc_aux);
  }
 
 #ifdef USE_X86LDOUBLE
@@ -377,6 +378,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         }
     }
 
+    if (version_id >= 11) {
+        qemu_get_be64s(f, &env->tsc_aux);
+    }
     /* XXX: ensure compatiblity for halted bit ? */
     /* XXX: compute redundant hflags bits */
     env->hflags = hflags;
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 9ffda36..a457bdd 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -2969,6 +2969,12 @@ void helper_rdtsc(void)
     EDX = (uint32_t)(val >> 32);
 }
 
+void helper_rdtscp(void)
+{
+    helper_rdtsc();
+    ECX = (uint32_t)(env->tsc_aux);
+}
+
 void helper_rdpmc(void)
 {
     if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
@@ -3107,6 +3113,9 @@ void helper_wrmsr(void)
             && (val == 0 || val == ~(uint64_t)0))
             env->mcg_ctl = val;
         break;
+    case MSR_TSC_AUX:
+        env->tsc_aux = val;
+        break;
     default:
         if ((uint32_t)ECX >= MSR_MC0_CTL
             && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
@@ -3177,6 +3186,9 @@ void helper_rdmsr(void)
     case MSR_KERNELGSBASE:
         val = env->kernelgsbase;
         break;
+    case MSR_TSC_AUX:
+        val = env->tsc_aux;
+        break;
 #endif
     case MSR_MTRRphysBase(0):
     case MSR_MTRRphysBase(1):
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 5cbcf07..306685d 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7217,31 +7217,58 @@ static target_ulong disas_insn(DisasContext *s, 
target_ulong pc_start)
                 gen_eob(s);
             }
             break;
-        case 7: /* invlpg */
-            if (s->cpl != 0) {
-                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        case 7:
+            if (mod != 3) { /* invlpg */
+                if (s->cpl != 0) {
+                    gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                } else {
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_jmp_im(pc_start - s->cs_base);
+                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+                    gen_helper_invlpg(cpu_A0);
+                    gen_jmp_im(s->pc - s->cs_base);
+                    gen_eob(s);
+                }
             } else {
-                if (mod == 3) {
+                switch (rm) {
+                case 0: /* swapgs */
 #ifdef TARGET_X86_64
-                    if (CODE64(s) && rm == 0) {
-                        /* swapgs */
-                        tcg_gen_ld_tl(cpu_T[0], cpu_env, 
offsetof(CPUX86State,segs[R_GS].base));
-                        tcg_gen_ld_tl(cpu_T[1], cpu_env, 
offsetof(CPUX86State,kernelgsbase));
-                        tcg_gen_st_tl(cpu_T[1], cpu_env, 
offsetof(CPUX86State,segs[R_GS].base));
-                        tcg_gen_st_tl(cpu_T[0], cpu_env, 
offsetof(CPUX86State,kernelgsbase));
+                    if (CODE64(s)) {
+                        if (s->cpl != 0) {
+                            gen_exception(s, EXCP0D_GPF, pc_start - 
s->cs_base);
+                        } else {
+                            tcg_gen_ld_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,segs[R_GS].base));
+                            tcg_gen_ld_tl(cpu_T[1], cpu_env,
+                                offsetof(CPUX86State,kernelgsbase));
+                            tcg_gen_st_tl(cpu_T[1], cpu_env,
+                                offsetof(CPUX86State,segs[R_GS].base));
+                            tcg_gen_st_tl(cpu_T[0], cpu_env,
+                                offsetof(CPUX86State,kernelgsbase));
+                        }
                     } else
 #endif
                     {
                         goto illegal_op;
                     }
-                } else {
+                    break;
+                case 1: /* rdtscp */
+                    if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP))
+                        goto illegal_op;
                     if (s->cc_op != CC_OP_DYNAMIC)
                         gen_op_set_cc_op(s->cc_op);
                     gen_jmp_im(pc_start - s->cs_base);
-                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
-                    gen_helper_invlpg(cpu_A0);
-                    gen_jmp_im(s->pc - s->cs_base);
-                    gen_eob(s);
+                    if (use_icount)
+                        gen_io_start();
+                    gen_helper_rdtscp();
+                    if (use_icount) {
+                        gen_io_end();
+                        gen_jmp(s, s->pc - s->cs_base);
+                    }
+                    break;
+                default:
+                    goto illegal_op;
                 }
             }
             break;
-- 
1.6.1.3






reply via email to

[Prev in Thread] Current Thread [Next in Thread]