xref: /qemu/target/i386/tcg/misc_helper.c (revision c45b426acd1ad8e30fbe1b9af8c07b2889c28c6b)
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"
21b4e79a50SAlex Bennée #include "qemu/main-loop.h"
22f7b2429fSBlue Swirl #include "cpu.h"
232ef6175aSRichard Henderson #include "exec/helper-proto.h"
2463c91552SPaolo Bonzini #include "exec/exec-all.h"
25f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
263f7d8464SPaolo Bonzini #include "exec/address-spaces.h"
27ed69e831SClaudio Fontana #include "helper-tcg.h"
2892fc4b58SBlue Swirl 
2969483f31SClaudio Fontana /*
3069483f31SClaudio Fontana  * NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
3169483f31SClaudio Fontana  * after generating a call to a helper that uses this.
3269483f31SClaudio Fontana  */
3369483f31SClaudio Fontana void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask)
3469483f31SClaudio Fontana {
3569483f31SClaudio Fontana     CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
3669483f31SClaudio Fontana     CC_OP = CC_OP_EFLAGS;
3769483f31SClaudio Fontana     env->df = 1 - (2 * ((eflags >> 10) & 1));
3869483f31SClaudio Fontana     env->eflags = (env->eflags & ~update_mask) |
3969483f31SClaudio Fontana         (eflags & update_mask) | 0x2;
4069483f31SClaudio Fontana }
4169483f31SClaudio Fontana 
423f7d8464SPaolo Bonzini void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
43f7b2429fSBlue Swirl {
443f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
453f7d8464SPaolo Bonzini     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data);
463f7d8464SPaolo Bonzini #else
473f7d8464SPaolo Bonzini     address_space_stb(&address_space_io, port, data,
483f7d8464SPaolo Bonzini                       cpu_get_mem_attrs(env), NULL);
493f7d8464SPaolo Bonzini #endif
50f7b2429fSBlue Swirl }
51f7b2429fSBlue Swirl 
523f7d8464SPaolo Bonzini target_ulong helper_inb(CPUX86State *env, uint32_t port)
53f7b2429fSBlue Swirl {
543f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
553f7d8464SPaolo Bonzini     fprintf(stderr, "inb: port=0x%04x\n", port);
563f7d8464SPaolo Bonzini     return 0;
573f7d8464SPaolo Bonzini #else
583f7d8464SPaolo Bonzini     return address_space_ldub(&address_space_io, port,
593f7d8464SPaolo Bonzini                               cpu_get_mem_attrs(env), NULL);
603f7d8464SPaolo Bonzini #endif
61f7b2429fSBlue Swirl }
62f7b2429fSBlue Swirl 
633f7d8464SPaolo Bonzini void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
64f7b2429fSBlue Swirl {
653f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
663f7d8464SPaolo Bonzini     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data);
673f7d8464SPaolo Bonzini #else
683f7d8464SPaolo Bonzini     address_space_stw(&address_space_io, port, data,
693f7d8464SPaolo Bonzini                       cpu_get_mem_attrs(env), NULL);
703f7d8464SPaolo Bonzini #endif
71f7b2429fSBlue Swirl }
72f7b2429fSBlue Swirl 
733f7d8464SPaolo Bonzini target_ulong helper_inw(CPUX86State *env, uint32_t port)
74f7b2429fSBlue Swirl {
753f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
763f7d8464SPaolo Bonzini     fprintf(stderr, "inw: port=0x%04x\n", port);
773f7d8464SPaolo Bonzini     return 0;
783f7d8464SPaolo Bonzini #else
793f7d8464SPaolo Bonzini     return address_space_lduw(&address_space_io, port,
803f7d8464SPaolo Bonzini                               cpu_get_mem_attrs(env), NULL);
813f7d8464SPaolo Bonzini #endif
82f7b2429fSBlue Swirl }
83f7b2429fSBlue Swirl 
843f7d8464SPaolo Bonzini void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
85f7b2429fSBlue Swirl {
863f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
87ce8540fdSPhilippe Mathieu-Daudé     fprintf(stderr, "outl: port=0x%04x, data=%08x\n", port, data);
883f7d8464SPaolo Bonzini #else
893f7d8464SPaolo Bonzini     address_space_stl(&address_space_io, port, data,
903f7d8464SPaolo Bonzini                       cpu_get_mem_attrs(env), NULL);
913f7d8464SPaolo Bonzini #endif
92f7b2429fSBlue Swirl }
93f7b2429fSBlue Swirl 
943f7d8464SPaolo Bonzini target_ulong helper_inl(CPUX86State *env, uint32_t port)
95f7b2429fSBlue Swirl {
963f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
973f7d8464SPaolo Bonzini     fprintf(stderr, "inl: port=0x%04x\n", port);
983f7d8464SPaolo Bonzini     return 0;
993f7d8464SPaolo Bonzini #else
1003f7d8464SPaolo Bonzini     return address_space_ldl(&address_space_io, port,
1013f7d8464SPaolo Bonzini                              cpu_get_mem_attrs(env), NULL);
1023f7d8464SPaolo Bonzini #endif
103f7b2429fSBlue Swirl }
104f7b2429fSBlue Swirl 
1054a7443beSBlue Swirl void helper_into(CPUX86State *env, int next_eip_addend)
106f7b2429fSBlue Swirl {
107f7b2429fSBlue Swirl     int eflags;
108f7b2429fSBlue Swirl 
109f0967a1aSBlue Swirl     eflags = cpu_cc_compute_all(env, CC_OP);
110f7b2429fSBlue Swirl     if (eflags & CC_O) {
111f7b2429fSBlue Swirl         raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
112f7b2429fSBlue Swirl     }
113f7b2429fSBlue Swirl }
114f7b2429fSBlue Swirl 
1154a7443beSBlue Swirl void helper_cpuid(CPUX86State *env)
116f7b2429fSBlue Swirl {
117f7b2429fSBlue Swirl     uint32_t eax, ebx, ecx, edx;
118f7b2429fSBlue Swirl 
11965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
120f7b2429fSBlue Swirl 
12190a2541bSliguang     cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
12290a2541bSliguang                   &eax, &ebx, &ecx, &edx);
1234b34e3adSliguang     env->regs[R_EAX] = eax;
12470b51365Sliguang     env->regs[R_EBX] = ebx;
125a4165610Sliguang     env->regs[R_ECX] = ecx;
12600f5e6f2Sliguang     env->regs[R_EDX] = edx;
127f7b2429fSBlue Swirl }
128f7b2429fSBlue Swirl 
129f7b2429fSBlue Swirl #if defined(CONFIG_USER_ONLY)
1304a7443beSBlue Swirl target_ulong helper_read_crN(CPUX86State *env, int reg)
131f7b2429fSBlue Swirl {
132f7b2429fSBlue Swirl     return 0;
133f7b2429fSBlue Swirl }
134f7b2429fSBlue Swirl 
1354a7443beSBlue Swirl void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
136f7b2429fSBlue Swirl {
137f7b2429fSBlue Swirl }
138f7b2429fSBlue Swirl #else
1394a7443beSBlue Swirl target_ulong helper_read_crN(CPUX86State *env, int reg)
140f7b2429fSBlue Swirl {
141f7b2429fSBlue Swirl     target_ulong val;
142f7b2429fSBlue Swirl 
14365c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
144f7b2429fSBlue Swirl     switch (reg) {
145f7b2429fSBlue Swirl     default:
146f7b2429fSBlue Swirl         val = env->cr[reg];
147f7b2429fSBlue Swirl         break;
148f7b2429fSBlue Swirl     case 8:
149f7b2429fSBlue Swirl         if (!(env->hflags2 & HF2_VINTR_MASK)) {
1506aa9e42fSRichard Henderson             val = cpu_get_apic_tpr(env_archcpu(env)->apic_state);
151f7b2429fSBlue Swirl         } else {
152f7b2429fSBlue Swirl             val = env->v_tpr;
153f7b2429fSBlue Swirl         }
154f7b2429fSBlue Swirl         break;
155f7b2429fSBlue Swirl     }
156f7b2429fSBlue Swirl     return val;
157f7b2429fSBlue Swirl }
158f7b2429fSBlue Swirl 
1594a7443beSBlue Swirl void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
160f7b2429fSBlue Swirl {
16165c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
162f7b2429fSBlue Swirl     switch (reg) {
163f7b2429fSBlue Swirl     case 0:
164f7b2429fSBlue Swirl         cpu_x86_update_cr0(env, t0);
165f7b2429fSBlue Swirl         break;
166f7b2429fSBlue Swirl     case 3:
167f7b2429fSBlue Swirl         cpu_x86_update_cr3(env, t0);
168f7b2429fSBlue Swirl         break;
169f7b2429fSBlue Swirl     case 4:
170f7b2429fSBlue Swirl         cpu_x86_update_cr4(env, t0);
171f7b2429fSBlue Swirl         break;
172f7b2429fSBlue Swirl     case 8:
173f7b2429fSBlue Swirl         if (!(env->hflags2 & HF2_VINTR_MASK)) {
174b4e79a50SAlex Bennée             qemu_mutex_lock_iothread();
1756aa9e42fSRichard Henderson             cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0);
176b4e79a50SAlex Bennée             qemu_mutex_unlock_iothread();
177f7b2429fSBlue Swirl         }
178f7b2429fSBlue Swirl         env->v_tpr = t0 & 0x0f;
179f7b2429fSBlue Swirl         break;
180f7b2429fSBlue Swirl     default:
181f7b2429fSBlue Swirl         env->cr[reg] = t0;
182f7b2429fSBlue Swirl         break;
183f7b2429fSBlue Swirl     }
184f7b2429fSBlue Swirl }
185f7b2429fSBlue Swirl #endif
186f7b2429fSBlue Swirl 
1874a7443beSBlue Swirl void helper_lmsw(CPUX86State *env, target_ulong t0)
188f7b2429fSBlue Swirl {
189f7b2429fSBlue Swirl     /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
190f7b2429fSBlue Swirl        if already set to one. */
191f7b2429fSBlue Swirl     t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
1924a7443beSBlue Swirl     helper_write_crN(env, 0, t0);
193f7b2429fSBlue Swirl }
194f7b2429fSBlue Swirl 
1954a7443beSBlue Swirl void helper_invlpg(CPUX86State *env, target_ulong addr)
196f7b2429fSBlue Swirl {
1976aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
19831b030d4SAndreas Färber 
19965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
20031b030d4SAndreas Färber     tlb_flush_page(CPU(cpu), addr);
201f7b2429fSBlue Swirl }
202f7b2429fSBlue Swirl 
2034a7443beSBlue Swirl void helper_rdtsc(CPUX86State *env)
204f7b2429fSBlue Swirl {
205f7b2429fSBlue Swirl     uint64_t val;
206f7b2429fSBlue Swirl 
207f7b2429fSBlue Swirl     if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2084054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
209f7b2429fSBlue Swirl     }
21065c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC());
211f7b2429fSBlue Swirl 
212f7b2429fSBlue Swirl     val = cpu_get_tsc(env) + env->tsc_offset;
2134b34e3adSliguang     env->regs[R_EAX] = (uint32_t)(val);
21400f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)(val >> 32);
215f7b2429fSBlue Swirl }
216f7b2429fSBlue Swirl 
2174a7443beSBlue Swirl void helper_rdtscp(CPUX86State *env)
218f7b2429fSBlue Swirl {
2194a7443beSBlue Swirl     helper_rdtsc(env);
220a4165610Sliguang     env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
221f7b2429fSBlue Swirl }
222f7b2429fSBlue Swirl 
2234a7443beSBlue Swirl void helper_rdpmc(CPUX86State *env)
224f7b2429fSBlue Swirl {
225*c45b426aSZheng Zhan Liang     if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
226*c45b426aSZheng Zhan Liang         ((env->hflags & HF_CPL_MASK) != 0)) {
2274054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
228f7b2429fSBlue Swirl     }
22965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
230f7b2429fSBlue Swirl 
231f7b2429fSBlue Swirl     /* currently unimplemented */
232f7b2429fSBlue Swirl     qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
233f7b2429fSBlue Swirl     raise_exception_err(env, EXCP06_ILLOP, 0);
234f7b2429fSBlue Swirl }
235f7b2429fSBlue Swirl 
236f7b2429fSBlue Swirl #if defined(CONFIG_USER_ONLY)
2374a7443beSBlue Swirl void helper_wrmsr(CPUX86State *env)
238f7b2429fSBlue Swirl {
239f7b2429fSBlue Swirl }
240f7b2429fSBlue Swirl 
2414a7443beSBlue Swirl void helper_rdmsr(CPUX86State *env)
242f7b2429fSBlue Swirl {
243f7b2429fSBlue Swirl }
244f7b2429fSBlue Swirl #else
2454a7443beSBlue Swirl void helper_wrmsr(CPUX86State *env)
246f7b2429fSBlue Swirl {
247f7b2429fSBlue Swirl     uint64_t val;
248e7e7bdabSPaolo Bonzini     CPUState *cs = env_cpu(env);
249f7b2429fSBlue Swirl 
25065c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());
251f7b2429fSBlue Swirl 
25290a2541bSliguang     val = ((uint32_t)env->regs[R_EAX]) |
25390a2541bSliguang         ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
254f7b2429fSBlue Swirl 
255a4165610Sliguang     switch ((uint32_t)env->regs[R_ECX]) {
256f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_CS:
257f7b2429fSBlue Swirl         env->sysenter_cs = val & 0xffff;
258f7b2429fSBlue Swirl         break;
259f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_ESP:
260f7b2429fSBlue Swirl         env->sysenter_esp = val;
261f7b2429fSBlue Swirl         break;
262f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_EIP:
263f7b2429fSBlue Swirl         env->sysenter_eip = val;
264f7b2429fSBlue Swirl         break;
265f7b2429fSBlue Swirl     case MSR_IA32_APICBASE:
2666aa9e42fSRichard Henderson         cpu_set_apic_base(env_archcpu(env)->apic_state, val);
267f7b2429fSBlue Swirl         break;
268f7b2429fSBlue Swirl     case MSR_EFER:
269f7b2429fSBlue Swirl         {
270f7b2429fSBlue Swirl             uint64_t update_mask;
271f7b2429fSBlue Swirl 
272f7b2429fSBlue Swirl             update_mask = 0;
2730514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
274f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_SCE;
275f7b2429fSBlue Swirl             }
2760514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
277f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_LME;
278f7b2429fSBlue Swirl             }
2790514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
280f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_FFXSR;
281f7b2429fSBlue Swirl             }
2820514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
283f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_NXE;
284f7b2429fSBlue Swirl             }
2850514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
286f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_SVME;
287f7b2429fSBlue Swirl             }
2880514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
289f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_FFXSR;
290f7b2429fSBlue Swirl             }
291f7b2429fSBlue Swirl             cpu_load_efer(env, (env->efer & ~update_mask) |
292f7b2429fSBlue Swirl                           (val & update_mask));
293f7b2429fSBlue Swirl         }
294f7b2429fSBlue Swirl         break;
295f7b2429fSBlue Swirl     case MSR_STAR:
296f7b2429fSBlue Swirl         env->star = val;
297f7b2429fSBlue Swirl         break;
298f7b2429fSBlue Swirl     case MSR_PAT:
299f7b2429fSBlue Swirl         env->pat = val;
300f7b2429fSBlue Swirl         break;
301e7e7bdabSPaolo Bonzini     case MSR_IA32_PKRS:
302e7e7bdabSPaolo Bonzini         if (val & 0xFFFFFFFF00000000ull) {
303e7e7bdabSPaolo Bonzini             goto error;
304e7e7bdabSPaolo Bonzini         }
305e7e7bdabSPaolo Bonzini         env->pkrs = val;
306e7e7bdabSPaolo Bonzini         tlb_flush(cs);
307e7e7bdabSPaolo Bonzini         break;
308f7b2429fSBlue Swirl     case MSR_VM_HSAVE_PA:
309f7b2429fSBlue Swirl         env->vm_hsave = val;
310f7b2429fSBlue Swirl         break;
311f7b2429fSBlue Swirl #ifdef TARGET_X86_64
312f7b2429fSBlue Swirl     case MSR_LSTAR:
313f7b2429fSBlue Swirl         env->lstar = val;
314f7b2429fSBlue Swirl         break;
315f7b2429fSBlue Swirl     case MSR_CSTAR:
316f7b2429fSBlue Swirl         env->cstar = val;
317f7b2429fSBlue Swirl         break;
318f7b2429fSBlue Swirl     case MSR_FMASK:
319f7b2429fSBlue Swirl         env->fmask = val;
320f7b2429fSBlue Swirl         break;
321f7b2429fSBlue Swirl     case MSR_FSBASE:
322f7b2429fSBlue Swirl         env->segs[R_FS].base = val;
323f7b2429fSBlue Swirl         break;
324f7b2429fSBlue Swirl     case MSR_GSBASE:
325f7b2429fSBlue Swirl         env->segs[R_GS].base = val;
326f7b2429fSBlue Swirl         break;
327f7b2429fSBlue Swirl     case MSR_KERNELGSBASE:
328f7b2429fSBlue Swirl         env->kernelgsbase = val;
329f7b2429fSBlue Swirl         break;
330f7b2429fSBlue Swirl #endif
331f7b2429fSBlue Swirl     case MSR_MTRRphysBase(0):
332f7b2429fSBlue Swirl     case MSR_MTRRphysBase(1):
333f7b2429fSBlue Swirl     case MSR_MTRRphysBase(2):
334f7b2429fSBlue Swirl     case MSR_MTRRphysBase(3):
335f7b2429fSBlue Swirl     case MSR_MTRRphysBase(4):
336f7b2429fSBlue Swirl     case MSR_MTRRphysBase(5):
337f7b2429fSBlue Swirl     case MSR_MTRRphysBase(6):
338f7b2429fSBlue Swirl     case MSR_MTRRphysBase(7):
33990a2541bSliguang         env->mtrr_var[((uint32_t)env->regs[R_ECX] -
34090a2541bSliguang                        MSR_MTRRphysBase(0)) / 2].base = val;
341f7b2429fSBlue Swirl         break;
342f7b2429fSBlue Swirl     case MSR_MTRRphysMask(0):
343f7b2429fSBlue Swirl     case MSR_MTRRphysMask(1):
344f7b2429fSBlue Swirl     case MSR_MTRRphysMask(2):
345f7b2429fSBlue Swirl     case MSR_MTRRphysMask(3):
346f7b2429fSBlue Swirl     case MSR_MTRRphysMask(4):
347f7b2429fSBlue Swirl     case MSR_MTRRphysMask(5):
348f7b2429fSBlue Swirl     case MSR_MTRRphysMask(6):
349f7b2429fSBlue Swirl     case MSR_MTRRphysMask(7):
35090a2541bSliguang         env->mtrr_var[((uint32_t)env->regs[R_ECX] -
35190a2541bSliguang                        MSR_MTRRphysMask(0)) / 2].mask = val;
352f7b2429fSBlue Swirl         break;
353f7b2429fSBlue Swirl     case MSR_MTRRfix64K_00000:
35490a2541bSliguang         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
35590a2541bSliguang                         MSR_MTRRfix64K_00000] = val;
356f7b2429fSBlue Swirl         break;
357f7b2429fSBlue Swirl     case MSR_MTRRfix16K_80000:
358f7b2429fSBlue Swirl     case MSR_MTRRfix16K_A0000:
35990a2541bSliguang         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
36090a2541bSliguang                         MSR_MTRRfix16K_80000 + 1] = val;
361f7b2429fSBlue Swirl         break;
362f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C0000:
363f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C8000:
364f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D0000:
365f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D8000:
366f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E0000:
367f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E8000:
368f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F0000:
369f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F8000:
37090a2541bSliguang         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
37190a2541bSliguang                         MSR_MTRRfix4K_C0000 + 3] = val;
372f7b2429fSBlue Swirl         break;
373f7b2429fSBlue Swirl     case MSR_MTRRdefType:
374f7b2429fSBlue Swirl         env->mtrr_deftype = val;
375f7b2429fSBlue Swirl         break;
376f7b2429fSBlue Swirl     case MSR_MCG_STATUS:
377f7b2429fSBlue Swirl         env->mcg_status = val;
378f7b2429fSBlue Swirl         break;
379f7b2429fSBlue Swirl     case MSR_MCG_CTL:
380f7b2429fSBlue Swirl         if ((env->mcg_cap & MCG_CTL_P)
381f7b2429fSBlue Swirl             && (val == 0 || val == ~(uint64_t)0)) {
382f7b2429fSBlue Swirl             env->mcg_ctl = val;
383f7b2429fSBlue Swirl         }
384f7b2429fSBlue Swirl         break;
385f7b2429fSBlue Swirl     case MSR_TSC_AUX:
386f7b2429fSBlue Swirl         env->tsc_aux = val;
387f7b2429fSBlue Swirl         break;
388f7b2429fSBlue Swirl     case MSR_IA32_MISC_ENABLE:
389f7b2429fSBlue Swirl         env->msr_ia32_misc_enable = val;
390f7b2429fSBlue Swirl         break;
391f4f1110eSRichard Henderson     case MSR_IA32_BNDCFGS:
392f4f1110eSRichard Henderson         /* FIXME: #GP if reserved bits are set.  */
393f4f1110eSRichard Henderson         /* FIXME: Extend highest implemented bit of linear address.  */
394f4f1110eSRichard Henderson         env->msr_bndcfgs = val;
395f4f1110eSRichard Henderson         cpu_sync_bndcs_hflags(env);
396f4f1110eSRichard Henderson         break;
397f7b2429fSBlue Swirl     default:
398a4165610Sliguang         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
39990a2541bSliguang             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
40090a2541bSliguang             (4 * env->mcg_cap & 0xff)) {
401a4165610Sliguang             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
402f7b2429fSBlue Swirl             if ((offset & 0x3) != 0
403f7b2429fSBlue Swirl                 || (val == 0 || val == ~(uint64_t)0)) {
404f7b2429fSBlue Swirl                 env->mce_banks[offset] = val;
405f7b2429fSBlue Swirl             }
406f7b2429fSBlue Swirl             break;
407f7b2429fSBlue Swirl         }
408f7b2429fSBlue Swirl         /* XXX: exception? */
409f7b2429fSBlue Swirl         break;
410f7b2429fSBlue Swirl     }
411e7e7bdabSPaolo Bonzini     return;
412e7e7bdabSPaolo Bonzini error:
413e7e7bdabSPaolo Bonzini     raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
414f7b2429fSBlue Swirl }
415f7b2429fSBlue Swirl 
4164a7443beSBlue Swirl void helper_rdmsr(CPUX86State *env)
417f7b2429fSBlue Swirl {
4189028c75cSPaolo Bonzini     X86CPU *x86_cpu = env_archcpu(env);
419f7b2429fSBlue Swirl     uint64_t val;
420f7b2429fSBlue Swirl 
42165c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
422f7b2429fSBlue Swirl 
423a4165610Sliguang     switch ((uint32_t)env->regs[R_ECX]) {
424f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_CS:
425f7b2429fSBlue Swirl         val = env->sysenter_cs;
426f7b2429fSBlue Swirl         break;
427f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_ESP:
428f7b2429fSBlue Swirl         val = env->sysenter_esp;
429f7b2429fSBlue Swirl         break;
430f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_EIP:
431f7b2429fSBlue Swirl         val = env->sysenter_eip;
432f7b2429fSBlue Swirl         break;
433f7b2429fSBlue Swirl     case MSR_IA32_APICBASE:
4346aa9e42fSRichard Henderson         val = cpu_get_apic_base(env_archcpu(env)->apic_state);
435f7b2429fSBlue Swirl         break;
436f7b2429fSBlue Swirl     case MSR_EFER:
437f7b2429fSBlue Swirl         val = env->efer;
438f7b2429fSBlue Swirl         break;
439f7b2429fSBlue Swirl     case MSR_STAR:
440f7b2429fSBlue Swirl         val = env->star;
441f7b2429fSBlue Swirl         break;
442f7b2429fSBlue Swirl     case MSR_PAT:
443f7b2429fSBlue Swirl         val = env->pat;
444f7b2429fSBlue Swirl         break;
445e7e7bdabSPaolo Bonzini     case MSR_IA32_PKRS:
446e7e7bdabSPaolo Bonzini         val = env->pkrs;
447e7e7bdabSPaolo Bonzini         break;
448f7b2429fSBlue Swirl     case MSR_VM_HSAVE_PA:
449f7b2429fSBlue Swirl         val = env->vm_hsave;
450f7b2429fSBlue Swirl         break;
451f7b2429fSBlue Swirl     case MSR_IA32_PERF_STATUS:
452f7b2429fSBlue Swirl         /* tsc_increment_by_tick */
453f7b2429fSBlue Swirl         val = 1000ULL;
454f7b2429fSBlue Swirl         /* CPU multiplier */
455f7b2429fSBlue Swirl         val |= (((uint64_t)4ULL) << 40);
456f7b2429fSBlue Swirl         break;
457f7b2429fSBlue Swirl #ifdef TARGET_X86_64
458f7b2429fSBlue Swirl     case MSR_LSTAR:
459f7b2429fSBlue Swirl         val = env->lstar;
460f7b2429fSBlue Swirl         break;
461f7b2429fSBlue Swirl     case MSR_CSTAR:
462f7b2429fSBlue Swirl         val = env->cstar;
463f7b2429fSBlue Swirl         break;
464f7b2429fSBlue Swirl     case MSR_FMASK:
465f7b2429fSBlue Swirl         val = env->fmask;
466f7b2429fSBlue Swirl         break;
467f7b2429fSBlue Swirl     case MSR_FSBASE:
468f7b2429fSBlue Swirl         val = env->segs[R_FS].base;
469f7b2429fSBlue Swirl         break;
470f7b2429fSBlue Swirl     case MSR_GSBASE:
471f7b2429fSBlue Swirl         val = env->segs[R_GS].base;
472f7b2429fSBlue Swirl         break;
473f7b2429fSBlue Swirl     case MSR_KERNELGSBASE:
474f7b2429fSBlue Swirl         val = env->kernelgsbase;
475f7b2429fSBlue Swirl         break;
476f7b2429fSBlue Swirl     case MSR_TSC_AUX:
477f7b2429fSBlue Swirl         val = env->tsc_aux;
478f7b2429fSBlue Swirl         break;
479f7b2429fSBlue Swirl #endif
4801d3db6bdSPaolo Bonzini     case MSR_SMI_COUNT:
4811d3db6bdSPaolo Bonzini         val = env->msr_smi_count;
4821d3db6bdSPaolo Bonzini         break;
483f7b2429fSBlue Swirl     case MSR_MTRRphysBase(0):
484f7b2429fSBlue Swirl     case MSR_MTRRphysBase(1):
485f7b2429fSBlue Swirl     case MSR_MTRRphysBase(2):
486f7b2429fSBlue Swirl     case MSR_MTRRphysBase(3):
487f7b2429fSBlue Swirl     case MSR_MTRRphysBase(4):
488f7b2429fSBlue Swirl     case MSR_MTRRphysBase(5):
489f7b2429fSBlue Swirl     case MSR_MTRRphysBase(6):
490f7b2429fSBlue Swirl     case MSR_MTRRphysBase(7):
49190a2541bSliguang         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
49290a2541bSliguang                              MSR_MTRRphysBase(0)) / 2].base;
493f7b2429fSBlue Swirl         break;
494f7b2429fSBlue Swirl     case MSR_MTRRphysMask(0):
495f7b2429fSBlue Swirl     case MSR_MTRRphysMask(1):
496f7b2429fSBlue Swirl     case MSR_MTRRphysMask(2):
497f7b2429fSBlue Swirl     case MSR_MTRRphysMask(3):
498f7b2429fSBlue Swirl     case MSR_MTRRphysMask(4):
499f7b2429fSBlue Swirl     case MSR_MTRRphysMask(5):
500f7b2429fSBlue Swirl     case MSR_MTRRphysMask(6):
501f7b2429fSBlue Swirl     case MSR_MTRRphysMask(7):
50290a2541bSliguang         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
50390a2541bSliguang                              MSR_MTRRphysMask(0)) / 2].mask;
504f7b2429fSBlue Swirl         break;
505f7b2429fSBlue Swirl     case MSR_MTRRfix64K_00000:
506f7b2429fSBlue Swirl         val = env->mtrr_fixed[0];
507f7b2429fSBlue Swirl         break;
508f7b2429fSBlue Swirl     case MSR_MTRRfix16K_80000:
509f7b2429fSBlue Swirl     case MSR_MTRRfix16K_A0000:
51090a2541bSliguang         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
51190a2541bSliguang                               MSR_MTRRfix16K_80000 + 1];
512f7b2429fSBlue Swirl         break;
513f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C0000:
514f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C8000:
515f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D0000:
516f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D8000:
517f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E0000:
518f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E8000:
519f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F0000:
520f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F8000:
52190a2541bSliguang         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
52290a2541bSliguang                               MSR_MTRRfix4K_C0000 + 3];
523f7b2429fSBlue Swirl         break;
524f7b2429fSBlue Swirl     case MSR_MTRRdefType:
525f7b2429fSBlue Swirl         val = env->mtrr_deftype;
526f7b2429fSBlue Swirl         break;
527f7b2429fSBlue Swirl     case MSR_MTRRcap:
5280514ef2fSEduardo Habkost         if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
529f7b2429fSBlue Swirl             val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
530f7b2429fSBlue Swirl                 MSR_MTRRcap_WC_SUPPORTED;
531f7b2429fSBlue Swirl         } else {
532f7b2429fSBlue Swirl             /* XXX: exception? */
533f7b2429fSBlue Swirl             val = 0;
534f7b2429fSBlue Swirl         }
535f7b2429fSBlue Swirl         break;
536f7b2429fSBlue Swirl     case MSR_MCG_CAP:
537f7b2429fSBlue Swirl         val = env->mcg_cap;
538f7b2429fSBlue Swirl         break;
539f7b2429fSBlue Swirl     case MSR_MCG_CTL:
540f7b2429fSBlue Swirl         if (env->mcg_cap & MCG_CTL_P) {
541f7b2429fSBlue Swirl             val = env->mcg_ctl;
542f7b2429fSBlue Swirl         } else {
543f7b2429fSBlue Swirl             val = 0;
544f7b2429fSBlue Swirl         }
545f7b2429fSBlue Swirl         break;
546f7b2429fSBlue Swirl     case MSR_MCG_STATUS:
547f7b2429fSBlue Swirl         val = env->mcg_status;
548f7b2429fSBlue Swirl         break;
549f7b2429fSBlue Swirl     case MSR_IA32_MISC_ENABLE:
550f7b2429fSBlue Swirl         val = env->msr_ia32_misc_enable;
551f7b2429fSBlue Swirl         break;
552f4f1110eSRichard Henderson     case MSR_IA32_BNDCFGS:
553f4f1110eSRichard Henderson         val = env->msr_bndcfgs;
554f4f1110eSRichard Henderson         break;
5559028c75cSPaolo Bonzini      case MSR_IA32_UCODE_REV:
5569028c75cSPaolo Bonzini         val = x86_cpu->ucode_rev;
5579028c75cSPaolo Bonzini         break;
558f7b2429fSBlue Swirl     default:
559a4165610Sliguang         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
56090a2541bSliguang             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
56190a2541bSliguang             (4 * env->mcg_cap & 0xff)) {
562a4165610Sliguang             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
563f7b2429fSBlue Swirl             val = env->mce_banks[offset];
564f7b2429fSBlue Swirl             break;
565f7b2429fSBlue Swirl         }
566f7b2429fSBlue Swirl         /* XXX: exception? */
567f7b2429fSBlue Swirl         val = 0;
568f7b2429fSBlue Swirl         break;
569f7b2429fSBlue Swirl     }
5704b34e3adSliguang     env->regs[R_EAX] = (uint32_t)(val);
57100f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)(val >> 32);
572f7b2429fSBlue Swirl }
573f7b2429fSBlue Swirl #endif
574f7b2429fSBlue Swirl 
57581f3053bSPaolo Bonzini static void do_pause(X86CPU *cpu)
57681f3053bSPaolo Bonzini {
57727103424SAndreas Färber     CPUState *cs = CPU(cpu);
57881f3053bSPaolo Bonzini 
57981f3053bSPaolo Bonzini     /* Just let another CPU run.  */
58027103424SAndreas Färber     cs->exception_index = EXCP_INTERRUPT;
5815638d180SAndreas Färber     cpu_loop_exit(cs);
58281f3053bSPaolo Bonzini }
58381f3053bSPaolo Bonzini 
584259186a7SAndreas Färber static void do_hlt(X86CPU *cpu)
585f7b2429fSBlue Swirl {
586259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
587259186a7SAndreas Färber     CPUX86State *env = &cpu->env;
588259186a7SAndreas Färber 
589f7b2429fSBlue Swirl     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
590259186a7SAndreas Färber     cs->halted = 1;
59127103424SAndreas Färber     cs->exception_index = EXCP_HLT;
5925638d180SAndreas Färber     cpu_loop_exit(cs);
593f7b2429fSBlue Swirl }
594f7b2429fSBlue Swirl 
5954a7443beSBlue Swirl void helper_hlt(CPUX86State *env, int next_eip_addend)
596f7b2429fSBlue Swirl {
5976aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
598259186a7SAndreas Färber 
59965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
600a78d0eabSliguang     env->eip += next_eip_addend;
601f7b2429fSBlue Swirl 
602259186a7SAndreas Färber     do_hlt(cpu);
603f7b2429fSBlue Swirl }
604f7b2429fSBlue Swirl 
6054a7443beSBlue Swirl void helper_monitor(CPUX86State *env, target_ulong ptr)
606f7b2429fSBlue Swirl {
607a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
6084054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
609f7b2429fSBlue Swirl     }
610f7b2429fSBlue Swirl     /* XXX: store address? */
61165c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
612f7b2429fSBlue Swirl }
613f7b2429fSBlue Swirl 
6144a7443beSBlue Swirl void helper_mwait(CPUX86State *env, int next_eip_addend)
615f7b2429fSBlue Swirl {
6166aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
6176aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
61855e5c285SAndreas Färber 
619a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
6204054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
621f7b2429fSBlue Swirl     }
62265c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
623a78d0eabSliguang     env->eip += next_eip_addend;
624f7b2429fSBlue Swirl 
625f7b2429fSBlue Swirl     /* XXX: not complete but not completely erroneous */
626bdc44640SAndreas Färber     if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
62781f3053bSPaolo Bonzini         do_pause(cpu);
628f7b2429fSBlue Swirl     } else {
629259186a7SAndreas Färber         do_hlt(cpu);
630f7b2429fSBlue Swirl     }
631f7b2429fSBlue Swirl }
632f7b2429fSBlue Swirl 
63381f3053bSPaolo Bonzini void helper_pause(CPUX86State *env, int next_eip_addend)
63481f3053bSPaolo Bonzini {
6356aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
63681f3053bSPaolo Bonzini 
63765c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
63881f3053bSPaolo Bonzini     env->eip += next_eip_addend;
63981f3053bSPaolo Bonzini 
64081f3053bSPaolo Bonzini     do_pause(cpu);
64181f3053bSPaolo Bonzini }
64281f3053bSPaolo Bonzini 
6434a7443beSBlue Swirl void helper_debug(CPUX86State *env)
644f7b2429fSBlue Swirl {
6456aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
64627103424SAndreas Färber 
64727103424SAndreas Färber     cs->exception_index = EXCP_DEBUG;
6485638d180SAndreas Färber     cpu_loop_exit(cs);
649f7b2429fSBlue Swirl }
6500f70ed47SPaolo Bonzini 
6510f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
6520f70ed47SPaolo Bonzini {
6530f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
6540f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
6550f70ed47SPaolo Bonzini     }
6560f70ed47SPaolo Bonzini     if (ecx != 0) {
6570f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
6580f70ed47SPaolo Bonzini     }
6590f70ed47SPaolo Bonzini 
6600f70ed47SPaolo Bonzini     return env->pkru;
6610f70ed47SPaolo Bonzini }
6620f70ed47SPaolo Bonzini 
6630f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
6640f70ed47SPaolo Bonzini {
6656aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
6660f70ed47SPaolo Bonzini 
6670f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
6680f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
6690f70ed47SPaolo Bonzini     }
6700f70ed47SPaolo Bonzini     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
6710f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
6720f70ed47SPaolo Bonzini     }
6730f70ed47SPaolo Bonzini 
6740f70ed47SPaolo Bonzini     env->pkru = val;
675d10eb08fSAlex Bennée     tlb_flush(cs);
6760f70ed47SPaolo Bonzini }
677