xref: /qemu/target/i386/tcg/misc_helper.c (revision cd6174843b0896c9e57176159b38ecba45bade0e)
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"
21*cd617484SPhilippe 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 
784a7443beSBlue Swirl void helper_rdtscp(CPUX86State *env)
79f7b2429fSBlue Swirl {
804a7443beSBlue Swirl     helper_rdtsc(env);
81a4165610Sliguang     env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
82f7b2429fSBlue Swirl }
83f7b2429fSBlue Swirl 
84b82055aeSRichard Henderson void QEMU_NORETURN helper_rdpmc(CPUX86State *env)
85f7b2429fSBlue Swirl {
86c45b426aSZheng Zhan Liang     if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
87c45b426aSZheng Zhan Liang         ((env->hflags & HF_CPL_MASK) != 0)) {
884054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
89f7b2429fSBlue Swirl     }
9065c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
91f7b2429fSBlue Swirl 
92f7b2429fSBlue Swirl     /* currently unimplemented */
93f7b2429fSBlue Swirl     qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
94f7b2429fSBlue Swirl     raise_exception_err(env, EXCP06_ILLOP, 0);
95f7b2429fSBlue Swirl }
96f7b2429fSBlue Swirl 
974ea2449bSRichard Henderson void QEMU_NORETURN do_pause(CPUX86State *env)
9881f3053bSPaolo Bonzini {
99eb26784fSRichard Henderson     CPUState *cs = env_cpu(env);
10081f3053bSPaolo Bonzini 
10181f3053bSPaolo Bonzini     /* Just let another CPU run.  */
10227103424SAndreas Färber     cs->exception_index = EXCP_INTERRUPT;
1035638d180SAndreas Färber     cpu_loop_exit(cs);
10481f3053bSPaolo Bonzini }
10581f3053bSPaolo Bonzini 
106b82055aeSRichard Henderson void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend)
10781f3053bSPaolo Bonzini {
10865c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
10981f3053bSPaolo Bonzini     env->eip += next_eip_addend;
11081f3053bSPaolo Bonzini 
111eb26784fSRichard Henderson     do_pause(env);
11281f3053bSPaolo Bonzini }
11381f3053bSPaolo Bonzini 
1140f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
1150f70ed47SPaolo Bonzini {
1160f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1170f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1180f70ed47SPaolo Bonzini     }
1190f70ed47SPaolo Bonzini     if (ecx != 0) {
1200f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1210f70ed47SPaolo Bonzini     }
1220f70ed47SPaolo Bonzini 
1230f70ed47SPaolo Bonzini     return env->pkru;
1240f70ed47SPaolo Bonzini }
1250f70ed47SPaolo Bonzini 
1260f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
1270f70ed47SPaolo Bonzini {
1286aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
1290f70ed47SPaolo Bonzini 
1300f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1310f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1320f70ed47SPaolo Bonzini     }
1330f70ed47SPaolo Bonzini     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
1340f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1350f70ed47SPaolo Bonzini     }
1360f70ed47SPaolo Bonzini 
1370f70ed47SPaolo Bonzini     env->pkru = val;
138d10eb08fSAlex Bennée     tlb_flush(cs);
1390f70ed47SPaolo Bonzini }
140