1f7b2429fSBlue Swirl /*
2f7b2429fSBlue Swirl * x86 misc helpers
3f7b2429fSBlue Swirl *
4f7b2429fSBlue Swirl * Copyright (c) 2003 Fabrice Bellard
5f7b2429fSBlue Swirl *
6f7b2429fSBlue Swirl * This library is free software; you can redistribute it and/or
7f7b2429fSBlue Swirl * modify it under the terms of the GNU Lesser General Public
8f7b2429fSBlue Swirl * License as published by the Free Software Foundation; either
9d9ff33adSChetan Pant * version 2.1 of the License, or (at your option) any later version.
10f7b2429fSBlue Swirl *
11f7b2429fSBlue Swirl * This library is distributed in the hope that it will be useful,
12f7b2429fSBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of
13f7b2429fSBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14f7b2429fSBlue Swirl * Lesser General Public License for more details.
15f7b2429fSBlue Swirl *
16f7b2429fSBlue Swirl * You should have received a copy of the GNU Lesser General Public
17f7b2429fSBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18f7b2429fSBlue Swirl */
19f7b2429fSBlue Swirl
20b6a0aa05SPeter Maydell #include "qemu/osdep.h"
21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
22f7b2429fSBlue Swirl #include "cpu.h"
232ef6175aSRichard Henderson #include "exec/helper-proto.h"
24*6ff5da16SPhilippe Mathieu-Daudé #include "exec/cputlb.h"
25ed69e831SClaudio Fontana #include "helper-tcg.h"
2692fc4b58SBlue Swirl
2769483f31SClaudio Fontana /*
2869483f31SClaudio Fontana * NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
2969483f31SClaudio Fontana * after generating a call to a helper that uses this.
3069483f31SClaudio Fontana */
cpu_load_eflags(CPUX86State * env,int eflags,int update_mask)3169483f31SClaudio Fontana void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask)
3269483f31SClaudio Fontana {
3369483f31SClaudio Fontana CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
3469483f31SClaudio Fontana CC_OP = CC_OP_EFLAGS;
3569483f31SClaudio Fontana env->df = 1 - (2 * ((eflags >> 10) & 1));
3669483f31SClaudio Fontana env->eflags = (env->eflags & ~update_mask) |
3769483f31SClaudio Fontana (eflags & update_mask) | 0x2;
3869483f31SClaudio Fontana }
3969483f31SClaudio Fontana
helper_into(CPUX86State * env,int next_eip_addend)404a7443beSBlue Swirl void helper_into(CPUX86State *env, int next_eip_addend)
41f7b2429fSBlue Swirl {
42f7b2429fSBlue Swirl int eflags;
43f7b2429fSBlue Swirl
442455e9cfSPaolo Bonzini eflags = cpu_cc_compute_all(env);
45f7b2429fSBlue Swirl if (eflags & CC_O) {
4683280f6aSPaolo Bonzini raise_interrupt(env, EXCP04_INTO, next_eip_addend);
47f7b2429fSBlue Swirl }
48f7b2429fSBlue Swirl }
49f7b2429fSBlue Swirl
helper_cpuid(CPUX86State * env)504a7443beSBlue Swirl void helper_cpuid(CPUX86State *env)
51f7b2429fSBlue Swirl {
52f7b2429fSBlue Swirl uint32_t eax, ebx, ecx, edx;
53f7b2429fSBlue Swirl
5465c9d60aSPaolo Bonzini cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
55f7b2429fSBlue Swirl
5690a2541bSliguang cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
5790a2541bSliguang &eax, &ebx, &ecx, &edx);
584b34e3adSliguang env->regs[R_EAX] = eax;
5970b51365Sliguang env->regs[R_EBX] = ebx;
60a4165610Sliguang env->regs[R_ECX] = ecx;
6100f5e6f2Sliguang env->regs[R_EDX] = edx;
62f7b2429fSBlue Swirl }
63f7b2429fSBlue Swirl
helper_rdtsc(CPUX86State * env)644a7443beSBlue Swirl void helper_rdtsc(CPUX86State *env)
65f7b2429fSBlue Swirl {
66f7b2429fSBlue Swirl uint64_t val;
67f7b2429fSBlue Swirl
68f7b2429fSBlue Swirl if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
694054cdecSPavel Dovgalyuk raise_exception_ra(env, EXCP0D_GPF, GETPC());
70f7b2429fSBlue Swirl }
7165c9d60aSPaolo Bonzini cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC());
72f7b2429fSBlue Swirl
73f7b2429fSBlue Swirl val = cpu_get_tsc(env) + env->tsc_offset;
744b34e3adSliguang env->regs[R_EAX] = (uint32_t)(val);
7500f5e6f2Sliguang env->regs[R_EDX] = (uint32_t)(val >> 32);
76f7b2429fSBlue Swirl }
77f7b2429fSBlue Swirl
helper_rdpmc(CPUX86State * env)788905770bSMarc-André Lureau G_NORETURN void helper_rdpmc(CPUX86State *env)
79f7b2429fSBlue Swirl {
80c45b426aSZheng Zhan Liang if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
81c45b426aSZheng Zhan Liang ((env->hflags & HF_CPL_MASK) != 0)) {
824054cdecSPavel Dovgalyuk raise_exception_ra(env, EXCP0D_GPF, GETPC());
83f7b2429fSBlue Swirl }
8465c9d60aSPaolo Bonzini cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
85f7b2429fSBlue Swirl
86f7b2429fSBlue Swirl /* currently unimplemented */
87f7b2429fSBlue Swirl qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
88f7b2429fSBlue Swirl raise_exception_err(env, EXCP06_ILLOP, 0);
89f7b2429fSBlue Swirl }
90f7b2429fSBlue Swirl
helper_pause(CPUX86State * env)91330e6adcSPaolo Bonzini G_NORETURN void helper_pause(CPUX86State *env)
9281f3053bSPaolo Bonzini {
93eb26784fSRichard Henderson CPUState *cs = env_cpu(env);
9481f3053bSPaolo Bonzini
953718523dSPaolo Bonzini /* Do gen_eob() tasks before going back to the main loop. */
963718523dSPaolo Bonzini do_end_instruction(env);
973718523dSPaolo Bonzini helper_rechecking_single_step(env);
983718523dSPaolo Bonzini
9981f3053bSPaolo Bonzini /* Just let another CPU run. */
10027103424SAndreas Färber cs->exception_index = EXCP_INTERRUPT;
1015638d180SAndreas Färber cpu_loop_exit(cs);
10281f3053bSPaolo Bonzini }
10381f3053bSPaolo Bonzini
helper_rdpkru(CPUX86State * env,uint32_t ecx)1040f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
1050f70ed47SPaolo Bonzini {
1060f70ed47SPaolo Bonzini if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1070f70ed47SPaolo Bonzini raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1080f70ed47SPaolo Bonzini }
1090f70ed47SPaolo Bonzini if (ecx != 0) {
1100f70ed47SPaolo Bonzini raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1110f70ed47SPaolo Bonzini }
1120f70ed47SPaolo Bonzini
1130f70ed47SPaolo Bonzini return env->pkru;
1140f70ed47SPaolo Bonzini }
1150f70ed47SPaolo Bonzini
helper_wrpkru(CPUX86State * env,uint32_t ecx,uint64_t val)1160f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
1170f70ed47SPaolo Bonzini {
1186aa9e42fSRichard Henderson CPUState *cs = env_cpu(env);
1190f70ed47SPaolo Bonzini
1200f70ed47SPaolo Bonzini if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1210f70ed47SPaolo Bonzini raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1220f70ed47SPaolo Bonzini }
1230f70ed47SPaolo Bonzini if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
1240f70ed47SPaolo Bonzini raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1250f70ed47SPaolo Bonzini }
1260f70ed47SPaolo Bonzini
1270f70ed47SPaolo Bonzini env->pkru = val;
128d10eb08fSAlex Bennée tlb_flush(cs);
1290f70ed47SPaolo Bonzini }
1306750485bSPaolo Bonzini
HELPER(rdpid)1316750485bSPaolo Bonzini target_ulong HELPER(rdpid)(CPUX86State *env)
1326750485bSPaolo Bonzini {
1331da389c5SPhilippe Mathieu-Daudé #if !defined CONFIG_USER_ONLY
1346750485bSPaolo Bonzini return env->tsc_aux;
1356750485bSPaolo Bonzini #elif defined CONFIG_LINUX && defined CONFIG_GETCPU
1366750485bSPaolo Bonzini unsigned cpu, node;
1376750485bSPaolo Bonzini getcpu(&cpu, &node);
1386750485bSPaolo Bonzini return (node << 12) | (cpu & 0xfff);
1396750485bSPaolo Bonzini #elif defined CONFIG_SCHED_GETCPU
1406750485bSPaolo Bonzini return sched_getcpu();
1416750485bSPaolo Bonzini #else
1426750485bSPaolo Bonzini return 0;
1436750485bSPaolo Bonzini #endif
1446750485bSPaolo Bonzini }
145