target-i386: add RDTSCP support
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 <andre.przywara@amd.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
d9f4bb27db
commit
1b050077d2
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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):
|
||||
|
@ -7206,23 +7206,10 @@ 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);
|
||||
} else {
|
||||
if (mod == 3) {
|
||||
#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));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
goto illegal_op;
|
||||
}
|
||||
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);
|
||||
@ -7232,6 +7219,46 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
gen_jmp_im(s->pc - s->cs_base);
|
||||
gen_eob(s);
|
||||
}
|
||||
} else {
|
||||
switch (rm) {
|
||||
case 0: /* swapgs */
|
||||
#ifdef TARGET_X86_64
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user