[Top][All Lists]
[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, ®_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, ®_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