xref: /qemu/target/i386/tcg/misc_helper.c (revision 9028c75c9d08be303ccc425bfe3d3b23d8f4cac7)
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
9f7b2429fSBlue Swirl  * version 2 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"
2792fc4b58SBlue Swirl 
283f7d8464SPaolo Bonzini void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
29f7b2429fSBlue Swirl {
303f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
313f7d8464SPaolo Bonzini     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data);
323f7d8464SPaolo Bonzini #else
333f7d8464SPaolo Bonzini     address_space_stb(&address_space_io, port, data,
343f7d8464SPaolo Bonzini                       cpu_get_mem_attrs(env), NULL);
353f7d8464SPaolo Bonzini #endif
36f7b2429fSBlue Swirl }
37f7b2429fSBlue Swirl 
383f7d8464SPaolo Bonzini target_ulong helper_inb(CPUX86State *env, uint32_t port)
39f7b2429fSBlue Swirl {
403f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
413f7d8464SPaolo Bonzini     fprintf(stderr, "inb: port=0x%04x\n", port);
423f7d8464SPaolo Bonzini     return 0;
433f7d8464SPaolo Bonzini #else
443f7d8464SPaolo Bonzini     return address_space_ldub(&address_space_io, port,
453f7d8464SPaolo Bonzini                               cpu_get_mem_attrs(env), NULL);
463f7d8464SPaolo Bonzini #endif
47f7b2429fSBlue Swirl }
48f7b2429fSBlue Swirl 
493f7d8464SPaolo Bonzini void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
50f7b2429fSBlue Swirl {
513f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
523f7d8464SPaolo Bonzini     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data);
533f7d8464SPaolo Bonzini #else
543f7d8464SPaolo Bonzini     address_space_stw(&address_space_io, port, data,
553f7d8464SPaolo Bonzini                       cpu_get_mem_attrs(env), NULL);
563f7d8464SPaolo Bonzini #endif
57f7b2429fSBlue Swirl }
58f7b2429fSBlue Swirl 
593f7d8464SPaolo Bonzini target_ulong helper_inw(CPUX86State *env, uint32_t port)
60f7b2429fSBlue Swirl {
613f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
623f7d8464SPaolo Bonzini     fprintf(stderr, "inw: port=0x%04x\n", port);
633f7d8464SPaolo Bonzini     return 0;
643f7d8464SPaolo Bonzini #else
653f7d8464SPaolo Bonzini     return address_space_lduw(&address_space_io, port,
663f7d8464SPaolo Bonzini                               cpu_get_mem_attrs(env), NULL);
673f7d8464SPaolo Bonzini #endif
68f7b2429fSBlue Swirl }
69f7b2429fSBlue Swirl 
703f7d8464SPaolo Bonzini void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
71f7b2429fSBlue Swirl {
723f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
733f7d8464SPaolo Bonzini     fprintf(stderr, "outw: port=0x%04x, data=%08x\n", port, data);
743f7d8464SPaolo Bonzini #else
753f7d8464SPaolo Bonzini     address_space_stl(&address_space_io, port, data,
763f7d8464SPaolo Bonzini                       cpu_get_mem_attrs(env), NULL);
773f7d8464SPaolo Bonzini #endif
78f7b2429fSBlue Swirl }
79f7b2429fSBlue Swirl 
803f7d8464SPaolo Bonzini target_ulong helper_inl(CPUX86State *env, uint32_t port)
81f7b2429fSBlue Swirl {
823f7d8464SPaolo Bonzini #ifdef CONFIG_USER_ONLY
833f7d8464SPaolo Bonzini     fprintf(stderr, "inl: port=0x%04x\n", port);
843f7d8464SPaolo Bonzini     return 0;
853f7d8464SPaolo Bonzini #else
863f7d8464SPaolo Bonzini     return address_space_ldl(&address_space_io, port,
873f7d8464SPaolo Bonzini                              cpu_get_mem_attrs(env), NULL);
883f7d8464SPaolo Bonzini #endif
89f7b2429fSBlue Swirl }
90f7b2429fSBlue Swirl 
914a7443beSBlue Swirl void helper_into(CPUX86State *env, int next_eip_addend)
92f7b2429fSBlue Swirl {
93f7b2429fSBlue Swirl     int eflags;
94f7b2429fSBlue Swirl 
95f0967a1aSBlue Swirl     eflags = cpu_cc_compute_all(env, CC_OP);
96f7b2429fSBlue Swirl     if (eflags & CC_O) {
97f7b2429fSBlue Swirl         raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
98f7b2429fSBlue Swirl     }
99f7b2429fSBlue Swirl }
100f7b2429fSBlue Swirl 
1014a7443beSBlue Swirl void helper_cpuid(CPUX86State *env)
102f7b2429fSBlue Swirl {
103f7b2429fSBlue Swirl     uint32_t eax, ebx, ecx, edx;
104f7b2429fSBlue Swirl 
10565c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
106f7b2429fSBlue Swirl 
10790a2541bSliguang     cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
10890a2541bSliguang                   &eax, &ebx, &ecx, &edx);
1094b34e3adSliguang     env->regs[R_EAX] = eax;
11070b51365Sliguang     env->regs[R_EBX] = ebx;
111a4165610Sliguang     env->regs[R_ECX] = ecx;
11200f5e6f2Sliguang     env->regs[R_EDX] = edx;
113f7b2429fSBlue Swirl }
114f7b2429fSBlue Swirl 
115f7b2429fSBlue Swirl #if defined(CONFIG_USER_ONLY)
1164a7443beSBlue Swirl target_ulong helper_read_crN(CPUX86State *env, int reg)
117f7b2429fSBlue Swirl {
118f7b2429fSBlue Swirl     return 0;
119f7b2429fSBlue Swirl }
120f7b2429fSBlue Swirl 
1214a7443beSBlue Swirl void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
122f7b2429fSBlue Swirl {
123f7b2429fSBlue Swirl }
124f7b2429fSBlue Swirl #else
1254a7443beSBlue Swirl target_ulong helper_read_crN(CPUX86State *env, int reg)
126f7b2429fSBlue Swirl {
127f7b2429fSBlue Swirl     target_ulong val;
128f7b2429fSBlue Swirl 
12965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
130f7b2429fSBlue Swirl     switch (reg) {
131f7b2429fSBlue Swirl     default:
132f7b2429fSBlue Swirl         val = env->cr[reg];
133f7b2429fSBlue Swirl         break;
134f7b2429fSBlue Swirl     case 8:
135f7b2429fSBlue Swirl         if (!(env->hflags2 & HF2_VINTR_MASK)) {
1366aa9e42fSRichard Henderson             val = cpu_get_apic_tpr(env_archcpu(env)->apic_state);
137f7b2429fSBlue Swirl         } else {
138f7b2429fSBlue Swirl             val = env->v_tpr;
139f7b2429fSBlue Swirl         }
140f7b2429fSBlue Swirl         break;
141f7b2429fSBlue Swirl     }
142f7b2429fSBlue Swirl     return val;
143f7b2429fSBlue Swirl }
144f7b2429fSBlue Swirl 
1454a7443beSBlue Swirl void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
146f7b2429fSBlue Swirl {
14765c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
148f7b2429fSBlue Swirl     switch (reg) {
149f7b2429fSBlue Swirl     case 0:
150f7b2429fSBlue Swirl         cpu_x86_update_cr0(env, t0);
151f7b2429fSBlue Swirl         break;
152f7b2429fSBlue Swirl     case 3:
153f7b2429fSBlue Swirl         cpu_x86_update_cr3(env, t0);
154f7b2429fSBlue Swirl         break;
155f7b2429fSBlue Swirl     case 4:
156f7b2429fSBlue Swirl         cpu_x86_update_cr4(env, t0);
157f7b2429fSBlue Swirl         break;
158f7b2429fSBlue Swirl     case 8:
159f7b2429fSBlue Swirl         if (!(env->hflags2 & HF2_VINTR_MASK)) {
160b4e79a50SAlex Bennée             qemu_mutex_lock_iothread();
1616aa9e42fSRichard Henderson             cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0);
162b4e79a50SAlex Bennée             qemu_mutex_unlock_iothread();
163f7b2429fSBlue Swirl         }
164f7b2429fSBlue Swirl         env->v_tpr = t0 & 0x0f;
165f7b2429fSBlue Swirl         break;
166f7b2429fSBlue Swirl     default:
167f7b2429fSBlue Swirl         env->cr[reg] = t0;
168f7b2429fSBlue Swirl         break;
169f7b2429fSBlue Swirl     }
170f7b2429fSBlue Swirl }
171f7b2429fSBlue Swirl #endif
172f7b2429fSBlue Swirl 
1734a7443beSBlue Swirl void helper_lmsw(CPUX86State *env, target_ulong t0)
174f7b2429fSBlue Swirl {
175f7b2429fSBlue Swirl     /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
176f7b2429fSBlue Swirl        if already set to one. */
177f7b2429fSBlue Swirl     t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
1784a7443beSBlue Swirl     helper_write_crN(env, 0, t0);
179f7b2429fSBlue Swirl }
180f7b2429fSBlue Swirl 
1814a7443beSBlue Swirl void helper_invlpg(CPUX86State *env, target_ulong addr)
182f7b2429fSBlue Swirl {
1836aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
18431b030d4SAndreas Färber 
18565c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
18631b030d4SAndreas Färber     tlb_flush_page(CPU(cpu), addr);
187f7b2429fSBlue Swirl }
188f7b2429fSBlue Swirl 
1894a7443beSBlue Swirl void helper_rdtsc(CPUX86State *env)
190f7b2429fSBlue Swirl {
191f7b2429fSBlue Swirl     uint64_t val;
192f7b2429fSBlue Swirl 
193f7b2429fSBlue Swirl     if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
1944054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
195f7b2429fSBlue Swirl     }
19665c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC());
197f7b2429fSBlue Swirl 
198f7b2429fSBlue Swirl     val = cpu_get_tsc(env) + env->tsc_offset;
1994b34e3adSliguang     env->regs[R_EAX] = (uint32_t)(val);
20000f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)(val >> 32);
201f7b2429fSBlue Swirl }
202f7b2429fSBlue Swirl 
2034a7443beSBlue Swirl void helper_rdtscp(CPUX86State *env)
204f7b2429fSBlue Swirl {
2054a7443beSBlue Swirl     helper_rdtsc(env);
206a4165610Sliguang     env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
207f7b2429fSBlue Swirl }
208f7b2429fSBlue Swirl 
2094a7443beSBlue Swirl void helper_rdpmc(CPUX86State *env)
210f7b2429fSBlue Swirl {
211f7b2429fSBlue Swirl     if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
2124054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
213f7b2429fSBlue Swirl     }
21465c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
215f7b2429fSBlue Swirl 
216f7b2429fSBlue Swirl     /* currently unimplemented */
217f7b2429fSBlue Swirl     qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
218f7b2429fSBlue Swirl     raise_exception_err(env, EXCP06_ILLOP, 0);
219f7b2429fSBlue Swirl }
220f7b2429fSBlue Swirl 
221f7b2429fSBlue Swirl #if defined(CONFIG_USER_ONLY)
2224a7443beSBlue Swirl void helper_wrmsr(CPUX86State *env)
223f7b2429fSBlue Swirl {
224f7b2429fSBlue Swirl }
225f7b2429fSBlue Swirl 
2264a7443beSBlue Swirl void helper_rdmsr(CPUX86State *env)
227f7b2429fSBlue Swirl {
228f7b2429fSBlue Swirl }
229f7b2429fSBlue Swirl #else
2304a7443beSBlue Swirl void helper_wrmsr(CPUX86State *env)
231f7b2429fSBlue Swirl {
232f7b2429fSBlue Swirl     uint64_t val;
233f7b2429fSBlue Swirl 
23465c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());
235f7b2429fSBlue Swirl 
23690a2541bSliguang     val = ((uint32_t)env->regs[R_EAX]) |
23790a2541bSliguang         ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
238f7b2429fSBlue Swirl 
239a4165610Sliguang     switch ((uint32_t)env->regs[R_ECX]) {
240f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_CS:
241f7b2429fSBlue Swirl         env->sysenter_cs = val & 0xffff;
242f7b2429fSBlue Swirl         break;
243f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_ESP:
244f7b2429fSBlue Swirl         env->sysenter_esp = val;
245f7b2429fSBlue Swirl         break;
246f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_EIP:
247f7b2429fSBlue Swirl         env->sysenter_eip = val;
248f7b2429fSBlue Swirl         break;
249f7b2429fSBlue Swirl     case MSR_IA32_APICBASE:
2506aa9e42fSRichard Henderson         cpu_set_apic_base(env_archcpu(env)->apic_state, val);
251f7b2429fSBlue Swirl         break;
252f7b2429fSBlue Swirl     case MSR_EFER:
253f7b2429fSBlue Swirl         {
254f7b2429fSBlue Swirl             uint64_t update_mask;
255f7b2429fSBlue Swirl 
256f7b2429fSBlue Swirl             update_mask = 0;
2570514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
258f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_SCE;
259f7b2429fSBlue Swirl             }
2600514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
261f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_LME;
262f7b2429fSBlue Swirl             }
2630514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
264f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_FFXSR;
265f7b2429fSBlue Swirl             }
2660514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
267f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_NXE;
268f7b2429fSBlue Swirl             }
2690514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
270f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_SVME;
271f7b2429fSBlue Swirl             }
2720514ef2fSEduardo Habkost             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
273f7b2429fSBlue Swirl                 update_mask |= MSR_EFER_FFXSR;
274f7b2429fSBlue Swirl             }
275f7b2429fSBlue Swirl             cpu_load_efer(env, (env->efer & ~update_mask) |
276f7b2429fSBlue Swirl                           (val & update_mask));
277f7b2429fSBlue Swirl         }
278f7b2429fSBlue Swirl         break;
279f7b2429fSBlue Swirl     case MSR_STAR:
280f7b2429fSBlue Swirl         env->star = val;
281f7b2429fSBlue Swirl         break;
282f7b2429fSBlue Swirl     case MSR_PAT:
283f7b2429fSBlue Swirl         env->pat = val;
284f7b2429fSBlue Swirl         break;
285f7b2429fSBlue Swirl     case MSR_VM_HSAVE_PA:
286f7b2429fSBlue Swirl         env->vm_hsave = val;
287f7b2429fSBlue Swirl         break;
288f7b2429fSBlue Swirl #ifdef TARGET_X86_64
289f7b2429fSBlue Swirl     case MSR_LSTAR:
290f7b2429fSBlue Swirl         env->lstar = val;
291f7b2429fSBlue Swirl         break;
292f7b2429fSBlue Swirl     case MSR_CSTAR:
293f7b2429fSBlue Swirl         env->cstar = val;
294f7b2429fSBlue Swirl         break;
295f7b2429fSBlue Swirl     case MSR_FMASK:
296f7b2429fSBlue Swirl         env->fmask = val;
297f7b2429fSBlue Swirl         break;
298f7b2429fSBlue Swirl     case MSR_FSBASE:
299f7b2429fSBlue Swirl         env->segs[R_FS].base = val;
300f7b2429fSBlue Swirl         break;
301f7b2429fSBlue Swirl     case MSR_GSBASE:
302f7b2429fSBlue Swirl         env->segs[R_GS].base = val;
303f7b2429fSBlue Swirl         break;
304f7b2429fSBlue Swirl     case MSR_KERNELGSBASE:
305f7b2429fSBlue Swirl         env->kernelgsbase = val;
306f7b2429fSBlue Swirl         break;
307f7b2429fSBlue Swirl #endif
308f7b2429fSBlue Swirl     case MSR_MTRRphysBase(0):
309f7b2429fSBlue Swirl     case MSR_MTRRphysBase(1):
310f7b2429fSBlue Swirl     case MSR_MTRRphysBase(2):
311f7b2429fSBlue Swirl     case MSR_MTRRphysBase(3):
312f7b2429fSBlue Swirl     case MSR_MTRRphysBase(4):
313f7b2429fSBlue Swirl     case MSR_MTRRphysBase(5):
314f7b2429fSBlue Swirl     case MSR_MTRRphysBase(6):
315f7b2429fSBlue Swirl     case MSR_MTRRphysBase(7):
31690a2541bSliguang         env->mtrr_var[((uint32_t)env->regs[R_ECX] -
31790a2541bSliguang                        MSR_MTRRphysBase(0)) / 2].base = val;
318f7b2429fSBlue Swirl         break;
319f7b2429fSBlue Swirl     case MSR_MTRRphysMask(0):
320f7b2429fSBlue Swirl     case MSR_MTRRphysMask(1):
321f7b2429fSBlue Swirl     case MSR_MTRRphysMask(2):
322f7b2429fSBlue Swirl     case MSR_MTRRphysMask(3):
323f7b2429fSBlue Swirl     case MSR_MTRRphysMask(4):
324f7b2429fSBlue Swirl     case MSR_MTRRphysMask(5):
325f7b2429fSBlue Swirl     case MSR_MTRRphysMask(6):
326f7b2429fSBlue Swirl     case MSR_MTRRphysMask(7):
32790a2541bSliguang         env->mtrr_var[((uint32_t)env->regs[R_ECX] -
32890a2541bSliguang                        MSR_MTRRphysMask(0)) / 2].mask = val;
329f7b2429fSBlue Swirl         break;
330f7b2429fSBlue Swirl     case MSR_MTRRfix64K_00000:
33190a2541bSliguang         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
33290a2541bSliguang                         MSR_MTRRfix64K_00000] = val;
333f7b2429fSBlue Swirl         break;
334f7b2429fSBlue Swirl     case MSR_MTRRfix16K_80000:
335f7b2429fSBlue Swirl     case MSR_MTRRfix16K_A0000:
33690a2541bSliguang         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
33790a2541bSliguang                         MSR_MTRRfix16K_80000 + 1] = val;
338f7b2429fSBlue Swirl         break;
339f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C0000:
340f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C8000:
341f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D0000:
342f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D8000:
343f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E0000:
344f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E8000:
345f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F0000:
346f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F8000:
34790a2541bSliguang         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
34890a2541bSliguang                         MSR_MTRRfix4K_C0000 + 3] = val;
349f7b2429fSBlue Swirl         break;
350f7b2429fSBlue Swirl     case MSR_MTRRdefType:
351f7b2429fSBlue Swirl         env->mtrr_deftype = val;
352f7b2429fSBlue Swirl         break;
353f7b2429fSBlue Swirl     case MSR_MCG_STATUS:
354f7b2429fSBlue Swirl         env->mcg_status = val;
355f7b2429fSBlue Swirl         break;
356f7b2429fSBlue Swirl     case MSR_MCG_CTL:
357f7b2429fSBlue Swirl         if ((env->mcg_cap & MCG_CTL_P)
358f7b2429fSBlue Swirl             && (val == 0 || val == ~(uint64_t)0)) {
359f7b2429fSBlue Swirl             env->mcg_ctl = val;
360f7b2429fSBlue Swirl         }
361f7b2429fSBlue Swirl         break;
362f7b2429fSBlue Swirl     case MSR_TSC_AUX:
363f7b2429fSBlue Swirl         env->tsc_aux = val;
364f7b2429fSBlue Swirl         break;
365f7b2429fSBlue Swirl     case MSR_IA32_MISC_ENABLE:
366f7b2429fSBlue Swirl         env->msr_ia32_misc_enable = val;
367f7b2429fSBlue Swirl         break;
368f4f1110eSRichard Henderson     case MSR_IA32_BNDCFGS:
369f4f1110eSRichard Henderson         /* FIXME: #GP if reserved bits are set.  */
370f4f1110eSRichard Henderson         /* FIXME: Extend highest implemented bit of linear address.  */
371f4f1110eSRichard Henderson         env->msr_bndcfgs = val;
372f4f1110eSRichard Henderson         cpu_sync_bndcs_hflags(env);
373f4f1110eSRichard Henderson         break;
374f7b2429fSBlue Swirl     default:
375a4165610Sliguang         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
37690a2541bSliguang             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
37790a2541bSliguang             (4 * env->mcg_cap & 0xff)) {
378a4165610Sliguang             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
379f7b2429fSBlue Swirl             if ((offset & 0x3) != 0
380f7b2429fSBlue Swirl                 || (val == 0 || val == ~(uint64_t)0)) {
381f7b2429fSBlue Swirl                 env->mce_banks[offset] = val;
382f7b2429fSBlue Swirl             }
383f7b2429fSBlue Swirl             break;
384f7b2429fSBlue Swirl         }
385f7b2429fSBlue Swirl         /* XXX: exception? */
386f7b2429fSBlue Swirl         break;
387f7b2429fSBlue Swirl     }
388f7b2429fSBlue Swirl }
389f7b2429fSBlue Swirl 
3904a7443beSBlue Swirl void helper_rdmsr(CPUX86State *env)
391f7b2429fSBlue Swirl {
3929028c75cSPaolo Bonzini     X86CPU *x86_cpu = env_archcpu(env);
393f7b2429fSBlue Swirl     uint64_t val;
394f7b2429fSBlue Swirl 
39565c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
396f7b2429fSBlue Swirl 
397a4165610Sliguang     switch ((uint32_t)env->regs[R_ECX]) {
398f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_CS:
399f7b2429fSBlue Swirl         val = env->sysenter_cs;
400f7b2429fSBlue Swirl         break;
401f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_ESP:
402f7b2429fSBlue Swirl         val = env->sysenter_esp;
403f7b2429fSBlue Swirl         break;
404f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_EIP:
405f7b2429fSBlue Swirl         val = env->sysenter_eip;
406f7b2429fSBlue Swirl         break;
407f7b2429fSBlue Swirl     case MSR_IA32_APICBASE:
4086aa9e42fSRichard Henderson         val = cpu_get_apic_base(env_archcpu(env)->apic_state);
409f7b2429fSBlue Swirl         break;
410f7b2429fSBlue Swirl     case MSR_EFER:
411f7b2429fSBlue Swirl         val = env->efer;
412f7b2429fSBlue Swirl         break;
413f7b2429fSBlue Swirl     case MSR_STAR:
414f7b2429fSBlue Swirl         val = env->star;
415f7b2429fSBlue Swirl         break;
416f7b2429fSBlue Swirl     case MSR_PAT:
417f7b2429fSBlue Swirl         val = env->pat;
418f7b2429fSBlue Swirl         break;
419f7b2429fSBlue Swirl     case MSR_VM_HSAVE_PA:
420f7b2429fSBlue Swirl         val = env->vm_hsave;
421f7b2429fSBlue Swirl         break;
422f7b2429fSBlue Swirl     case MSR_IA32_PERF_STATUS:
423f7b2429fSBlue Swirl         /* tsc_increment_by_tick */
424f7b2429fSBlue Swirl         val = 1000ULL;
425f7b2429fSBlue Swirl         /* CPU multiplier */
426f7b2429fSBlue Swirl         val |= (((uint64_t)4ULL) << 40);
427f7b2429fSBlue Swirl         break;
428f7b2429fSBlue Swirl #ifdef TARGET_X86_64
429f7b2429fSBlue Swirl     case MSR_LSTAR:
430f7b2429fSBlue Swirl         val = env->lstar;
431f7b2429fSBlue Swirl         break;
432f7b2429fSBlue Swirl     case MSR_CSTAR:
433f7b2429fSBlue Swirl         val = env->cstar;
434f7b2429fSBlue Swirl         break;
435f7b2429fSBlue Swirl     case MSR_FMASK:
436f7b2429fSBlue Swirl         val = env->fmask;
437f7b2429fSBlue Swirl         break;
438f7b2429fSBlue Swirl     case MSR_FSBASE:
439f7b2429fSBlue Swirl         val = env->segs[R_FS].base;
440f7b2429fSBlue Swirl         break;
441f7b2429fSBlue Swirl     case MSR_GSBASE:
442f7b2429fSBlue Swirl         val = env->segs[R_GS].base;
443f7b2429fSBlue Swirl         break;
444f7b2429fSBlue Swirl     case MSR_KERNELGSBASE:
445f7b2429fSBlue Swirl         val = env->kernelgsbase;
446f7b2429fSBlue Swirl         break;
447f7b2429fSBlue Swirl     case MSR_TSC_AUX:
448f7b2429fSBlue Swirl         val = env->tsc_aux;
449f7b2429fSBlue Swirl         break;
450f7b2429fSBlue Swirl #endif
4511d3db6bdSPaolo Bonzini     case MSR_SMI_COUNT:
4521d3db6bdSPaolo Bonzini         val = env->msr_smi_count;
4531d3db6bdSPaolo Bonzini         break;
454f7b2429fSBlue Swirl     case MSR_MTRRphysBase(0):
455f7b2429fSBlue Swirl     case MSR_MTRRphysBase(1):
456f7b2429fSBlue Swirl     case MSR_MTRRphysBase(2):
457f7b2429fSBlue Swirl     case MSR_MTRRphysBase(3):
458f7b2429fSBlue Swirl     case MSR_MTRRphysBase(4):
459f7b2429fSBlue Swirl     case MSR_MTRRphysBase(5):
460f7b2429fSBlue Swirl     case MSR_MTRRphysBase(6):
461f7b2429fSBlue Swirl     case MSR_MTRRphysBase(7):
46290a2541bSliguang         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
46390a2541bSliguang                              MSR_MTRRphysBase(0)) / 2].base;
464f7b2429fSBlue Swirl         break;
465f7b2429fSBlue Swirl     case MSR_MTRRphysMask(0):
466f7b2429fSBlue Swirl     case MSR_MTRRphysMask(1):
467f7b2429fSBlue Swirl     case MSR_MTRRphysMask(2):
468f7b2429fSBlue Swirl     case MSR_MTRRphysMask(3):
469f7b2429fSBlue Swirl     case MSR_MTRRphysMask(4):
470f7b2429fSBlue Swirl     case MSR_MTRRphysMask(5):
471f7b2429fSBlue Swirl     case MSR_MTRRphysMask(6):
472f7b2429fSBlue Swirl     case MSR_MTRRphysMask(7):
47390a2541bSliguang         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
47490a2541bSliguang                              MSR_MTRRphysMask(0)) / 2].mask;
475f7b2429fSBlue Swirl         break;
476f7b2429fSBlue Swirl     case MSR_MTRRfix64K_00000:
477f7b2429fSBlue Swirl         val = env->mtrr_fixed[0];
478f7b2429fSBlue Swirl         break;
479f7b2429fSBlue Swirl     case MSR_MTRRfix16K_80000:
480f7b2429fSBlue Swirl     case MSR_MTRRfix16K_A0000:
48190a2541bSliguang         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
48290a2541bSliguang                               MSR_MTRRfix16K_80000 + 1];
483f7b2429fSBlue Swirl         break;
484f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C0000:
485f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C8000:
486f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D0000:
487f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D8000:
488f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E0000:
489f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E8000:
490f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F0000:
491f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F8000:
49290a2541bSliguang         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
49390a2541bSliguang                               MSR_MTRRfix4K_C0000 + 3];
494f7b2429fSBlue Swirl         break;
495f7b2429fSBlue Swirl     case MSR_MTRRdefType:
496f7b2429fSBlue Swirl         val = env->mtrr_deftype;
497f7b2429fSBlue Swirl         break;
498f7b2429fSBlue Swirl     case MSR_MTRRcap:
4990514ef2fSEduardo Habkost         if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
500f7b2429fSBlue Swirl             val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
501f7b2429fSBlue Swirl                 MSR_MTRRcap_WC_SUPPORTED;
502f7b2429fSBlue Swirl         } else {
503f7b2429fSBlue Swirl             /* XXX: exception? */
504f7b2429fSBlue Swirl             val = 0;
505f7b2429fSBlue Swirl         }
506f7b2429fSBlue Swirl         break;
507f7b2429fSBlue Swirl     case MSR_MCG_CAP:
508f7b2429fSBlue Swirl         val = env->mcg_cap;
509f7b2429fSBlue Swirl         break;
510f7b2429fSBlue Swirl     case MSR_MCG_CTL:
511f7b2429fSBlue Swirl         if (env->mcg_cap & MCG_CTL_P) {
512f7b2429fSBlue Swirl             val = env->mcg_ctl;
513f7b2429fSBlue Swirl         } else {
514f7b2429fSBlue Swirl             val = 0;
515f7b2429fSBlue Swirl         }
516f7b2429fSBlue Swirl         break;
517f7b2429fSBlue Swirl     case MSR_MCG_STATUS:
518f7b2429fSBlue Swirl         val = env->mcg_status;
519f7b2429fSBlue Swirl         break;
520f7b2429fSBlue Swirl     case MSR_IA32_MISC_ENABLE:
521f7b2429fSBlue Swirl         val = env->msr_ia32_misc_enable;
522f7b2429fSBlue Swirl         break;
523f4f1110eSRichard Henderson     case MSR_IA32_BNDCFGS:
524f4f1110eSRichard Henderson         val = env->msr_bndcfgs;
525f4f1110eSRichard Henderson         break;
5269028c75cSPaolo Bonzini      case MSR_IA32_UCODE_REV:
5279028c75cSPaolo Bonzini         val = x86_cpu->ucode_rev;
5289028c75cSPaolo Bonzini         break;
529f7b2429fSBlue Swirl     default:
530a4165610Sliguang         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
53190a2541bSliguang             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
53290a2541bSliguang             (4 * env->mcg_cap & 0xff)) {
533a4165610Sliguang             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
534f7b2429fSBlue Swirl             val = env->mce_banks[offset];
535f7b2429fSBlue Swirl             break;
536f7b2429fSBlue Swirl         }
537f7b2429fSBlue Swirl         /* XXX: exception? */
538f7b2429fSBlue Swirl         val = 0;
539f7b2429fSBlue Swirl         break;
540f7b2429fSBlue Swirl     }
5414b34e3adSliguang     env->regs[R_EAX] = (uint32_t)(val);
54200f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)(val >> 32);
543f7b2429fSBlue Swirl }
544f7b2429fSBlue Swirl #endif
545f7b2429fSBlue Swirl 
54681f3053bSPaolo Bonzini static void do_pause(X86CPU *cpu)
54781f3053bSPaolo Bonzini {
54827103424SAndreas Färber     CPUState *cs = CPU(cpu);
54981f3053bSPaolo Bonzini 
55081f3053bSPaolo Bonzini     /* Just let another CPU run.  */
55127103424SAndreas Färber     cs->exception_index = EXCP_INTERRUPT;
5525638d180SAndreas Färber     cpu_loop_exit(cs);
55381f3053bSPaolo Bonzini }
55481f3053bSPaolo Bonzini 
555259186a7SAndreas Färber static void do_hlt(X86CPU *cpu)
556f7b2429fSBlue Swirl {
557259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
558259186a7SAndreas Färber     CPUX86State *env = &cpu->env;
559259186a7SAndreas Färber 
560f7b2429fSBlue Swirl     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
561259186a7SAndreas Färber     cs->halted = 1;
56227103424SAndreas Färber     cs->exception_index = EXCP_HLT;
5635638d180SAndreas Färber     cpu_loop_exit(cs);
564f7b2429fSBlue Swirl }
565f7b2429fSBlue Swirl 
5664a7443beSBlue Swirl void helper_hlt(CPUX86State *env, int next_eip_addend)
567f7b2429fSBlue Swirl {
5686aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
569259186a7SAndreas Färber 
57065c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
571a78d0eabSliguang     env->eip += next_eip_addend;
572f7b2429fSBlue Swirl 
573259186a7SAndreas Färber     do_hlt(cpu);
574f7b2429fSBlue Swirl }
575f7b2429fSBlue Swirl 
5764a7443beSBlue Swirl void helper_monitor(CPUX86State *env, target_ulong ptr)
577f7b2429fSBlue Swirl {
578a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
5794054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
580f7b2429fSBlue Swirl     }
581f7b2429fSBlue Swirl     /* XXX: store address? */
58265c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
583f7b2429fSBlue Swirl }
584f7b2429fSBlue Swirl 
5854a7443beSBlue Swirl void helper_mwait(CPUX86State *env, int next_eip_addend)
586f7b2429fSBlue Swirl {
5876aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
5886aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
58955e5c285SAndreas Färber 
590a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
5914054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
592f7b2429fSBlue Swirl     }
59365c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
594a78d0eabSliguang     env->eip += next_eip_addend;
595f7b2429fSBlue Swirl 
596f7b2429fSBlue Swirl     /* XXX: not complete but not completely erroneous */
597bdc44640SAndreas Färber     if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
59881f3053bSPaolo Bonzini         do_pause(cpu);
599f7b2429fSBlue Swirl     } else {
600259186a7SAndreas Färber         do_hlt(cpu);
601f7b2429fSBlue Swirl     }
602f7b2429fSBlue Swirl }
603f7b2429fSBlue Swirl 
60481f3053bSPaolo Bonzini void helper_pause(CPUX86State *env, int next_eip_addend)
60581f3053bSPaolo Bonzini {
6066aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
60781f3053bSPaolo Bonzini 
60865c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
60981f3053bSPaolo Bonzini     env->eip += next_eip_addend;
61081f3053bSPaolo Bonzini 
61181f3053bSPaolo Bonzini     do_pause(cpu);
61281f3053bSPaolo Bonzini }
61381f3053bSPaolo Bonzini 
6144a7443beSBlue Swirl void helper_debug(CPUX86State *env)
615f7b2429fSBlue Swirl {
6166aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
61727103424SAndreas Färber 
61827103424SAndreas Färber     cs->exception_index = EXCP_DEBUG;
6195638d180SAndreas Färber     cpu_loop_exit(cs);
620f7b2429fSBlue Swirl }
6210f70ed47SPaolo Bonzini 
6220f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
6230f70ed47SPaolo Bonzini {
6240f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
6250f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
6260f70ed47SPaolo Bonzini     }
6270f70ed47SPaolo Bonzini     if (ecx != 0) {
6280f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
6290f70ed47SPaolo Bonzini     }
6300f70ed47SPaolo Bonzini 
6310f70ed47SPaolo Bonzini     return env->pkru;
6320f70ed47SPaolo Bonzini }
6330f70ed47SPaolo Bonzini 
6340f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
6350f70ed47SPaolo Bonzini {
6366aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
6370f70ed47SPaolo Bonzini 
6380f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
6390f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
6400f70ed47SPaolo Bonzini     }
6410f70ed47SPaolo Bonzini     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
6420f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
6430f70ed47SPaolo Bonzini     }
6440f70ed47SPaolo Bonzini 
6450f70ed47SPaolo Bonzini     env->pkru = val;
646d10eb08fSAlex Bennée     tlb_flush(cs);
6470f70ed47SPaolo Bonzini }
648