xref: /qemu/target/i386/tcg/misc_helper.c (revision 1da389c5dba3efca5de6b983cf788054880de432)
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"
2463c91552SPaolo Bonzini #include "exec/exec-all.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  */
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 
404a7443beSBlue Swirl void helper_into(CPUX86State *env, int next_eip_addend)
41f7b2429fSBlue Swirl {
42f7b2429fSBlue Swirl     int eflags;
43f7b2429fSBlue Swirl 
44f0967a1aSBlue Swirl     eflags = cpu_cc_compute_all(env, CC_OP);
45f7b2429fSBlue Swirl     if (eflags & CC_O) {
46f7b2429fSBlue Swirl         raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
47f7b2429fSBlue Swirl     }
48f7b2429fSBlue Swirl }
49f7b2429fSBlue Swirl 
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 
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 
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 
918905770bSMarc-André Lureau G_NORETURN void do_pause(CPUX86State *env)
9281f3053bSPaolo Bonzini {
93eb26784fSRichard Henderson     CPUState *cs = env_cpu(env);
9481f3053bSPaolo Bonzini 
9581f3053bSPaolo Bonzini     /* Just let another CPU run.  */
9627103424SAndreas Färber     cs->exception_index = EXCP_INTERRUPT;
975638d180SAndreas Färber     cpu_loop_exit(cs);
9881f3053bSPaolo Bonzini }
9981f3053bSPaolo Bonzini 
1008905770bSMarc-André Lureau G_NORETURN void helper_pause(CPUX86State *env, int next_eip_addend)
10181f3053bSPaolo Bonzini {
10265c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
10381f3053bSPaolo Bonzini     env->eip += next_eip_addend;
10481f3053bSPaolo Bonzini 
105eb26784fSRichard Henderson     do_pause(env);
10681f3053bSPaolo Bonzini }
10781f3053bSPaolo Bonzini 
1080f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
1090f70ed47SPaolo Bonzini {
1100f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1110f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1120f70ed47SPaolo Bonzini     }
1130f70ed47SPaolo Bonzini     if (ecx != 0) {
1140f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1150f70ed47SPaolo Bonzini     }
1160f70ed47SPaolo Bonzini 
1170f70ed47SPaolo Bonzini     return env->pkru;
1180f70ed47SPaolo Bonzini }
1190f70ed47SPaolo Bonzini 
1200f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
1210f70ed47SPaolo Bonzini {
1226aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
1230f70ed47SPaolo Bonzini 
1240f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1250f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1260f70ed47SPaolo Bonzini     }
1270f70ed47SPaolo Bonzini     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
1280f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1290f70ed47SPaolo Bonzini     }
1300f70ed47SPaolo Bonzini 
1310f70ed47SPaolo Bonzini     env->pkru = val;
132d10eb08fSAlex Bennée     tlb_flush(cs);
1330f70ed47SPaolo Bonzini }
1346750485bSPaolo Bonzini 
1356750485bSPaolo Bonzini target_ulong HELPER(rdpid)(CPUX86State *env)
1366750485bSPaolo Bonzini {
137*1da389c5SPhilippe Mathieu-Daudé #if !defined CONFIG_USER_ONLY
1386750485bSPaolo Bonzini     return env->tsc_aux;
1396750485bSPaolo Bonzini #elif defined CONFIG_LINUX && defined CONFIG_GETCPU
1406750485bSPaolo Bonzini     unsigned cpu, node;
1416750485bSPaolo Bonzini     getcpu(&cpu, &node);
1426750485bSPaolo Bonzini     return (node << 12) | (cpu & 0xfff);
1436750485bSPaolo Bonzini #elif defined CONFIG_SCHED_GETCPU
1446750485bSPaolo Bonzini     return sched_getcpu();
1456750485bSPaolo Bonzini #else
1466750485bSPaolo Bonzini     return 0;
1476750485bSPaolo Bonzini #endif
1486750485bSPaolo Bonzini }
149