xref: /qemu/target/i386/tcg/misc_helper.c (revision 6aa9e42f27331be34e06d4d66f92f2272868f96a)
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 {
392f7b2429fSBlue Swirl     uint64_t val;
393f7b2429fSBlue Swirl 
39465c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
395f7b2429fSBlue Swirl 
396a4165610Sliguang     switch ((uint32_t)env->regs[R_ECX]) {
397f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_CS:
398f7b2429fSBlue Swirl         val = env->sysenter_cs;
399f7b2429fSBlue Swirl         break;
400f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_ESP:
401f7b2429fSBlue Swirl         val = env->sysenter_esp;
402f7b2429fSBlue Swirl         break;
403f7b2429fSBlue Swirl     case MSR_IA32_SYSENTER_EIP:
404f7b2429fSBlue Swirl         val = env->sysenter_eip;
405f7b2429fSBlue Swirl         break;
406f7b2429fSBlue Swirl     case MSR_IA32_APICBASE:
4076aa9e42fSRichard Henderson         val = cpu_get_apic_base(env_archcpu(env)->apic_state);
408f7b2429fSBlue Swirl         break;
409f7b2429fSBlue Swirl     case MSR_EFER:
410f7b2429fSBlue Swirl         val = env->efer;
411f7b2429fSBlue Swirl         break;
412f7b2429fSBlue Swirl     case MSR_STAR:
413f7b2429fSBlue Swirl         val = env->star;
414f7b2429fSBlue Swirl         break;
415f7b2429fSBlue Swirl     case MSR_PAT:
416f7b2429fSBlue Swirl         val = env->pat;
417f7b2429fSBlue Swirl         break;
418f7b2429fSBlue Swirl     case MSR_VM_HSAVE_PA:
419f7b2429fSBlue Swirl         val = env->vm_hsave;
420f7b2429fSBlue Swirl         break;
421f7b2429fSBlue Swirl     case MSR_IA32_PERF_STATUS:
422f7b2429fSBlue Swirl         /* tsc_increment_by_tick */
423f7b2429fSBlue Swirl         val = 1000ULL;
424f7b2429fSBlue Swirl         /* CPU multiplier */
425f7b2429fSBlue Swirl         val |= (((uint64_t)4ULL) << 40);
426f7b2429fSBlue Swirl         break;
427f7b2429fSBlue Swirl #ifdef TARGET_X86_64
428f7b2429fSBlue Swirl     case MSR_LSTAR:
429f7b2429fSBlue Swirl         val = env->lstar;
430f7b2429fSBlue Swirl         break;
431f7b2429fSBlue Swirl     case MSR_CSTAR:
432f7b2429fSBlue Swirl         val = env->cstar;
433f7b2429fSBlue Swirl         break;
434f7b2429fSBlue Swirl     case MSR_FMASK:
435f7b2429fSBlue Swirl         val = env->fmask;
436f7b2429fSBlue Swirl         break;
437f7b2429fSBlue Swirl     case MSR_FSBASE:
438f7b2429fSBlue Swirl         val = env->segs[R_FS].base;
439f7b2429fSBlue Swirl         break;
440f7b2429fSBlue Swirl     case MSR_GSBASE:
441f7b2429fSBlue Swirl         val = env->segs[R_GS].base;
442f7b2429fSBlue Swirl         break;
443f7b2429fSBlue Swirl     case MSR_KERNELGSBASE:
444f7b2429fSBlue Swirl         val = env->kernelgsbase;
445f7b2429fSBlue Swirl         break;
446f7b2429fSBlue Swirl     case MSR_TSC_AUX:
447f7b2429fSBlue Swirl         val = env->tsc_aux;
448f7b2429fSBlue Swirl         break;
449f7b2429fSBlue Swirl #endif
4501d3db6bdSPaolo Bonzini     case MSR_SMI_COUNT:
4511d3db6bdSPaolo Bonzini         val = env->msr_smi_count;
4521d3db6bdSPaolo Bonzini         break;
453f7b2429fSBlue Swirl     case MSR_MTRRphysBase(0):
454f7b2429fSBlue Swirl     case MSR_MTRRphysBase(1):
455f7b2429fSBlue Swirl     case MSR_MTRRphysBase(2):
456f7b2429fSBlue Swirl     case MSR_MTRRphysBase(3):
457f7b2429fSBlue Swirl     case MSR_MTRRphysBase(4):
458f7b2429fSBlue Swirl     case MSR_MTRRphysBase(5):
459f7b2429fSBlue Swirl     case MSR_MTRRphysBase(6):
460f7b2429fSBlue Swirl     case MSR_MTRRphysBase(7):
46190a2541bSliguang         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
46290a2541bSliguang                              MSR_MTRRphysBase(0)) / 2].base;
463f7b2429fSBlue Swirl         break;
464f7b2429fSBlue Swirl     case MSR_MTRRphysMask(0):
465f7b2429fSBlue Swirl     case MSR_MTRRphysMask(1):
466f7b2429fSBlue Swirl     case MSR_MTRRphysMask(2):
467f7b2429fSBlue Swirl     case MSR_MTRRphysMask(3):
468f7b2429fSBlue Swirl     case MSR_MTRRphysMask(4):
469f7b2429fSBlue Swirl     case MSR_MTRRphysMask(5):
470f7b2429fSBlue Swirl     case MSR_MTRRphysMask(6):
471f7b2429fSBlue Swirl     case MSR_MTRRphysMask(7):
47290a2541bSliguang         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
47390a2541bSliguang                              MSR_MTRRphysMask(0)) / 2].mask;
474f7b2429fSBlue Swirl         break;
475f7b2429fSBlue Swirl     case MSR_MTRRfix64K_00000:
476f7b2429fSBlue Swirl         val = env->mtrr_fixed[0];
477f7b2429fSBlue Swirl         break;
478f7b2429fSBlue Swirl     case MSR_MTRRfix16K_80000:
479f7b2429fSBlue Swirl     case MSR_MTRRfix16K_A0000:
48090a2541bSliguang         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
48190a2541bSliguang                               MSR_MTRRfix16K_80000 + 1];
482f7b2429fSBlue Swirl         break;
483f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C0000:
484f7b2429fSBlue Swirl     case MSR_MTRRfix4K_C8000:
485f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D0000:
486f7b2429fSBlue Swirl     case MSR_MTRRfix4K_D8000:
487f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E0000:
488f7b2429fSBlue Swirl     case MSR_MTRRfix4K_E8000:
489f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F0000:
490f7b2429fSBlue Swirl     case MSR_MTRRfix4K_F8000:
49190a2541bSliguang         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
49290a2541bSliguang                               MSR_MTRRfix4K_C0000 + 3];
493f7b2429fSBlue Swirl         break;
494f7b2429fSBlue Swirl     case MSR_MTRRdefType:
495f7b2429fSBlue Swirl         val = env->mtrr_deftype;
496f7b2429fSBlue Swirl         break;
497f7b2429fSBlue Swirl     case MSR_MTRRcap:
4980514ef2fSEduardo Habkost         if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
499f7b2429fSBlue Swirl             val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
500f7b2429fSBlue Swirl                 MSR_MTRRcap_WC_SUPPORTED;
501f7b2429fSBlue Swirl         } else {
502f7b2429fSBlue Swirl             /* XXX: exception? */
503f7b2429fSBlue Swirl             val = 0;
504f7b2429fSBlue Swirl         }
505f7b2429fSBlue Swirl         break;
506f7b2429fSBlue Swirl     case MSR_MCG_CAP:
507f7b2429fSBlue Swirl         val = env->mcg_cap;
508f7b2429fSBlue Swirl         break;
509f7b2429fSBlue Swirl     case MSR_MCG_CTL:
510f7b2429fSBlue Swirl         if (env->mcg_cap & MCG_CTL_P) {
511f7b2429fSBlue Swirl             val = env->mcg_ctl;
512f7b2429fSBlue Swirl         } else {
513f7b2429fSBlue Swirl             val = 0;
514f7b2429fSBlue Swirl         }
515f7b2429fSBlue Swirl         break;
516f7b2429fSBlue Swirl     case MSR_MCG_STATUS:
517f7b2429fSBlue Swirl         val = env->mcg_status;
518f7b2429fSBlue Swirl         break;
519f7b2429fSBlue Swirl     case MSR_IA32_MISC_ENABLE:
520f7b2429fSBlue Swirl         val = env->msr_ia32_misc_enable;
521f7b2429fSBlue Swirl         break;
522f4f1110eSRichard Henderson     case MSR_IA32_BNDCFGS:
523f4f1110eSRichard Henderson         val = env->msr_bndcfgs;
524f4f1110eSRichard Henderson         break;
525f7b2429fSBlue Swirl     default:
526a4165610Sliguang         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
52790a2541bSliguang             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
52890a2541bSliguang             (4 * env->mcg_cap & 0xff)) {
529a4165610Sliguang             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
530f7b2429fSBlue Swirl             val = env->mce_banks[offset];
531f7b2429fSBlue Swirl             break;
532f7b2429fSBlue Swirl         }
533f7b2429fSBlue Swirl         /* XXX: exception? */
534f7b2429fSBlue Swirl         val = 0;
535f7b2429fSBlue Swirl         break;
536f7b2429fSBlue Swirl     }
5374b34e3adSliguang     env->regs[R_EAX] = (uint32_t)(val);
53800f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)(val >> 32);
539f7b2429fSBlue Swirl }
540f7b2429fSBlue Swirl #endif
541f7b2429fSBlue Swirl 
54281f3053bSPaolo Bonzini static void do_pause(X86CPU *cpu)
54381f3053bSPaolo Bonzini {
54427103424SAndreas Färber     CPUState *cs = CPU(cpu);
54581f3053bSPaolo Bonzini 
54681f3053bSPaolo Bonzini     /* Just let another CPU run.  */
54727103424SAndreas Färber     cs->exception_index = EXCP_INTERRUPT;
5485638d180SAndreas Färber     cpu_loop_exit(cs);
54981f3053bSPaolo Bonzini }
55081f3053bSPaolo Bonzini 
551259186a7SAndreas Färber static void do_hlt(X86CPU *cpu)
552f7b2429fSBlue Swirl {
553259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
554259186a7SAndreas Färber     CPUX86State *env = &cpu->env;
555259186a7SAndreas Färber 
556f7b2429fSBlue Swirl     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
557259186a7SAndreas Färber     cs->halted = 1;
55827103424SAndreas Färber     cs->exception_index = EXCP_HLT;
5595638d180SAndreas Färber     cpu_loop_exit(cs);
560f7b2429fSBlue Swirl }
561f7b2429fSBlue Swirl 
5624a7443beSBlue Swirl void helper_hlt(CPUX86State *env, int next_eip_addend)
563f7b2429fSBlue Swirl {
5646aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
565259186a7SAndreas Färber 
56665c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
567a78d0eabSliguang     env->eip += next_eip_addend;
568f7b2429fSBlue Swirl 
569259186a7SAndreas Färber     do_hlt(cpu);
570f7b2429fSBlue Swirl }
571f7b2429fSBlue Swirl 
5724a7443beSBlue Swirl void helper_monitor(CPUX86State *env, target_ulong ptr)
573f7b2429fSBlue Swirl {
574a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
5754054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
576f7b2429fSBlue Swirl     }
577f7b2429fSBlue Swirl     /* XXX: store address? */
57865c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
579f7b2429fSBlue Swirl }
580f7b2429fSBlue Swirl 
5814a7443beSBlue Swirl void helper_mwait(CPUX86State *env, int next_eip_addend)
582f7b2429fSBlue Swirl {
5836aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
5846aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
58555e5c285SAndreas Färber 
586a4165610Sliguang     if ((uint32_t)env->regs[R_ECX] != 0) {
5874054cdecSPavel Dovgalyuk         raise_exception_ra(env, EXCP0D_GPF, GETPC());
588f7b2429fSBlue Swirl     }
58965c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
590a78d0eabSliguang     env->eip += next_eip_addend;
591f7b2429fSBlue Swirl 
592f7b2429fSBlue Swirl     /* XXX: not complete but not completely erroneous */
593bdc44640SAndreas Färber     if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
59481f3053bSPaolo Bonzini         do_pause(cpu);
595f7b2429fSBlue Swirl     } else {
596259186a7SAndreas Färber         do_hlt(cpu);
597f7b2429fSBlue Swirl     }
598f7b2429fSBlue Swirl }
599f7b2429fSBlue Swirl 
60081f3053bSPaolo Bonzini void helper_pause(CPUX86State *env, int next_eip_addend)
60181f3053bSPaolo Bonzini {
6026aa9e42fSRichard Henderson     X86CPU *cpu = env_archcpu(env);
60381f3053bSPaolo Bonzini 
60465c9d60aSPaolo Bonzini     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
60581f3053bSPaolo Bonzini     env->eip += next_eip_addend;
60681f3053bSPaolo Bonzini 
60781f3053bSPaolo Bonzini     do_pause(cpu);
60881f3053bSPaolo Bonzini }
60981f3053bSPaolo Bonzini 
6104a7443beSBlue Swirl void helper_debug(CPUX86State *env)
611f7b2429fSBlue Swirl {
6126aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
61327103424SAndreas Färber 
61427103424SAndreas Färber     cs->exception_index = EXCP_DEBUG;
6155638d180SAndreas Färber     cpu_loop_exit(cs);
616f7b2429fSBlue Swirl }
6170f70ed47SPaolo Bonzini 
6180f70ed47SPaolo Bonzini uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
6190f70ed47SPaolo Bonzini {
6200f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
6210f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
6220f70ed47SPaolo Bonzini     }
6230f70ed47SPaolo Bonzini     if (ecx != 0) {
6240f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
6250f70ed47SPaolo Bonzini     }
6260f70ed47SPaolo Bonzini 
6270f70ed47SPaolo Bonzini     return env->pkru;
6280f70ed47SPaolo Bonzini }
6290f70ed47SPaolo Bonzini 
6300f70ed47SPaolo Bonzini void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
6310f70ed47SPaolo Bonzini {
6326aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
6330f70ed47SPaolo Bonzini 
6340f70ed47SPaolo Bonzini     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
6350f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
6360f70ed47SPaolo Bonzini     }
6370f70ed47SPaolo Bonzini     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
6380f70ed47SPaolo Bonzini         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
6390f70ed47SPaolo Bonzini     }
6400f70ed47SPaolo Bonzini 
6410f70ed47SPaolo Bonzini     env->pkru = val;
642d10eb08fSAlex Bennée     tlb_flush(cs);
6430f70ed47SPaolo Bonzini }
644