xref: /qemu/target/i386/tcg/misc_helper.c (revision 6ff5da16000f908140723e164d33a0b51a6c4162)
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