xref: /qemu/target/i386/tcg/misc_helper.c (revision b82055aece019636c8f1c1b0e199066a0270c6c1)
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"
21f7b2429fSBlue Swirl #include "cpu.h"
222ef6175aSRichard Henderson #include "exec/helper-proto.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
24ed69e831SClaudio Fontana #include "helper-tcg.h"
2592fc4b58SBlue Swirl 
2669483f31SClaudio Fontana /*
2769483f31SClaudio Fontana  * NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
2869483f31SClaudio Fontana  * after generating a call to a helper that uses this.
2969483f31SClaudio Fontana  */
3069483f31SClaudio Fontana void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask)
3169483f31SClaudio Fontana {
3269483f31SClaudio Fontana     CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
3369483f31SClaudio Fontana     CC_OP = CC_OP_EFLAGS;
3469483f31SClaudio Fontana     env->df = 1 - (2 * ((eflags >> 10) & 1));
3569483f31SClaudio Fontana     env->eflags = (env->eflags & ~update_mask) |
3669483f31SClaudio Fontana         (eflags & update_mask) | 0x2;
3769483f31SClaudio Fontana }
3869483f31SClaudio Fontana 
394a7443beSBlue Swirl void helper_into(CPUX86State *env, int next_eip_addend)
40f7b2429fSBlue Swirl {
41f7b2429fSBlue Swirl     int eflags;
42f7b2429fSBlue Swirl 
43f0967a1aSBlue Swirl     eflags = cpu_cc_compute_all(env, CC_OP);
44f7b2429fSBlue Swirl     if (eflags & CC_O) {
45f7b2429fSBlue Swirl         raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
46f7b2429fSBlue Swirl     }
47f7b2429fSBlue Swirl }
48f7b2429fSBlue Swirl 
494a7443beSBlue Swirl void helper_cpuid(CPUX86State *env)
50f7b2429fSBlue Swirl {
51f7b2429fSBlue Swirl     uint32_t eax, ebx, ecx, edx;
52f7b2429fSBlue Swirl 
5365c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
54f7b2429fSBlue Swirl 
5590a2541bSliguang     cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
5690a2541bSliguang                   &eax, &ebx, &ecx, &edx);
574b34e3adSliguang     env->regs[R_EAX] = eax;
5870b51365Sliguang     env->regs[R_EBX] = ebx;
59a4165610Sliguang     env->regs[R_ECX] = ecx;
6000f5e6f2Sliguang     env->regs[R_EDX] = edx;
61f7b2429fSBlue Swirl }
62f7b2429fSBlue Swirl 
634a7443beSBlue Swirl void helper_lmsw(CPUX86State *env, target_ulong t0)
64f7b2429fSBlue Swirl {
65f7b2429fSBlue Swirl     /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
66f7b2429fSBlue Swirl        if already set to one. */
67f7b2429fSBlue Swirl     t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
684a7443beSBlue Swirl     helper_write_crN(env, 0, t0);
69f7b2429fSBlue Swirl }
70f7b2429fSBlue Swirl 
714a7443beSBlue Swirl void helper_invlpg(CPUX86State *env, target_ulong addr)
72f7b2429fSBlue Swirl {
736aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
7431b030d4SAndreas Färber 
7565c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
7631b030d4SAndreas Färber     tlb_flush_page(CPU(cpu), addr);
77f7b2429fSBlue Swirl }
78f7b2429fSBlue Swirl 
794a7443beSBlue Swirl void helper_rdtsc(CPUX86State *env)
80f7b2429fSBlue Swirl {
81f7b2429fSBlue Swirl     uint64_t val;
82f7b2429fSBlue Swirl 
83f7b2429fSBlue Swirl     if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
844054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
85f7b2429fSBlue Swirl     }
8665c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC());
87f7b2429fSBlue Swirl 
88f7b2429fSBlue Swirl     val = cpu_get_tsc(env) + env->tsc_offset;
894b34e3adSliguang     env->regs[R_EAX] = (uint32_t)(val);
9000f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)(val >> 32);
91f7b2429fSBlue Swirl }
92f7b2429fSBlue Swirl 
934a7443beSBlue Swirl void helper_rdtscp(CPUX86State *env)
94f7b2429fSBlue Swirl {
954a7443beSBlue Swirl     helper_rdtsc(env);
96a4165610Sliguang     env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
97f7b2429fSBlue Swirl }
98f7b2429fSBlue Swirl 
99*b82055aeSRichard Henderson void QEMU_NORETURN helper_rdpmc(CPUX86State *env)
100f7b2429fSBlue Swirl {
101c45b426aSZheng Zhan Liang     if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
102c45b426aSZheng Zhan Liang         ((env->hflags & HF_CPL_MASK) != 0)) {
1034054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
104f7b2429fSBlue Swirl     }
10565c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
106f7b2429fSBlue Swirl 
107f7b2429fSBlue Swirl     /* currently unimplemented */
108f7b2429fSBlue Swirl     qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
109f7b2429fSBlue Swirl     raise_exception_err(env, EXCP06_ILLOP, 0);
110f7b2429fSBlue Swirl }
111f7b2429fSBlue Swirl 
112*b82055aeSRichard Henderson static QEMU_NORETURN void do_pause(X86CPU *cpu)
11381f3053bSPaolo Bonzini {
11427103424SAndreas Färber     CPUState *cs = CPU(cpu);
11581f3053bSPaolo Bonzini 
11681f3053bSPaolo Bonzini     /* Just let another CPU run.  */
11727103424SAndreas Färber     cs->exception_index = EXCP_INTERRUPT;
1185638d180SAndreas Färber     cpu_loop_exit(cs);
11981f3053bSPaolo Bonzini }
12081f3053bSPaolo Bonzini 
121*b82055aeSRichard Henderson static QEMU_NORETURN void do_hlt(X86CPU *cpu)
122f7b2429fSBlue Swirl {
123259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
124259186a7SAndreas Färber     CPUX86State *env = &cpu->env;
125259186a7SAndreas Färber 
126f7b2429fSBlue Swirl     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
127259186a7SAndreas Färber     cs->halted = 1;
12827103424SAndreas Färber     cs->exception_index = EXCP_HLT;
1295638d180SAndreas Färber     cpu_loop_exit(cs);
130f7b2429fSBlue Swirl }
131f7b2429fSBlue Swirl 
132*b82055aeSRichard Henderson void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend)
133f7b2429fSBlue Swirl {
1346aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
135259186a7SAndreas Färber 
13665c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
137a78d0eabSliguang     env->eip += next_eip_addend;
138f7b2429fSBlue Swirl 
139259186a7SAndreas Färber     do_hlt(cpu);
140f7b2429fSBlue Swirl }
141f7b2429fSBlue Swirl 
1424a7443beSBlue Swirl void helper_monitor(CPUX86State *env, target_ulong ptr)
143f7b2429fSBlue Swirl {
144a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
1454054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
146f7b2429fSBlue Swirl     }
147f7b2429fSBlue Swirl     /* XXX: store address? */
14865c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
149f7b2429fSBlue Swirl }
150f7b2429fSBlue Swirl 
151*b82055aeSRichard Henderson void QEMU_NORETURN helper_mwait(CPUX86State *env, int next_eip_addend)
152f7b2429fSBlue Swirl {
1536aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
1546aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
15555e5c285SAndreas Färber 
156a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
1574054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
158f7b2429fSBlue Swirl     }
15965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
160a78d0eabSliguang     env->eip += next_eip_addend;
161f7b2429fSBlue Swirl 
162f7b2429fSBlue Swirl     /* XXX: not complete but not completely erroneous */
163bdc44640SAndreas Färber     if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
16481f3053bSPaolo Bonzini         do_pause(cpu);
165f7b2429fSBlue Swirl     } else {
166259186a7SAndreas Färber         do_hlt(cpu);
167f7b2429fSBlue Swirl     }
168f7b2429fSBlue Swirl }
169f7b2429fSBlue Swirl 
170*b82055aeSRichard Henderson void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend)
17181f3053bSPaolo Bonzini {
1726aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
17381f3053bSPaolo Bonzini 
17465c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
17581f3053bSPaolo Bonzini     env->eip += next_eip_addend;
17681f3053bSPaolo Bonzini 
17781f3053bSPaolo Bonzini     do_pause(cpu);
17881f3053bSPaolo Bonzini }
17981f3053bSPaolo Bonzini 
180*b82055aeSRichard Henderson void QEMU_NORETURN helper_debug(CPUX86State *env)
181f7b2429fSBlue Swirl {
1826aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
18327103424SAndreas Färber 
18427103424SAndreas Färber     cs->exception_index = EXCP_DEBUG;
1855638d180SAndreas Färber     cpu_loop_exit(cs);
186f7b2429fSBlue Swirl }
1870f70ed47SPaolo Bonzini 
1880f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
1890f70ed47SPaolo Bonzini {
1900f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
1910f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
1920f70ed47SPaolo Bonzini     }
1930f70ed47SPaolo Bonzini     if (ecx != 0) {
1940f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
1950f70ed47SPaolo Bonzini     }
1960f70ed47SPaolo Bonzini 
1970f70ed47SPaolo Bonzini     return env->pkru;
1980f70ed47SPaolo Bonzini }
1990f70ed47SPaolo Bonzini 
2000f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
2010f70ed47SPaolo Bonzini {
2026aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
2030f70ed47SPaolo Bonzini 
2040f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
2050f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
2060f70ed47SPaolo Bonzini     }
2070f70ed47SPaolo Bonzini     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
2080f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
2090f70ed47SPaolo Bonzini     }
2100f70ed47SPaolo Bonzini 
2110f70ed47SPaolo Bonzini     env->pkru = val;
212d10eb08fSAlex Bennée     tlb_flush(cs);
2130f70ed47SPaolo Bonzini }
214