xref: /openbmc/qemu/target/i386/tcg/misc_helper.c (revision 5e437d3c)
1 /*
2  *  x86 misc helpers
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "qemu/main-loop.h"
22 #include "cpu.h"
23 #include "exec/helper-proto.h"
24 #include "exec/exec-all.h"
25 #include "exec/cpu_ldst.h"
26 #include "exec/address-spaces.h"
27 #include "helper-tcg.h"
28 
29 /*
30  * NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
31  * after generating a call to a helper that uses this.
32  */
33 void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask)
34 {
35     CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
36     CC_OP = CC_OP_EFLAGS;
37     env->df = 1 - (2 * ((eflags >> 10) & 1));
38     env->eflags = (env->eflags & ~update_mask) |
39         (eflags & update_mask) | 0x2;
40 }
41 
42 void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
43 {
44 #ifdef CONFIG_USER_ONLY
45     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data);
46 #else
47     address_space_stb(&address_space_io, port, data,
48                       cpu_get_mem_attrs(env), NULL);
49 #endif
50 }
51 
52 target_ulong helper_inb(CPUX86State *env, uint32_t port)
53 {
54 #ifdef CONFIG_USER_ONLY
55     fprintf(stderr, "inb: port=0x%04x\n", port);
56     return 0;
57 #else
58     return address_space_ldub(&address_space_io, port,
59                               cpu_get_mem_attrs(env), NULL);
60 #endif
61 }
62 
63 void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
64 {
65 #ifdef CONFIG_USER_ONLY
66     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data);
67 #else
68     address_space_stw(&address_space_io, port, data,
69                       cpu_get_mem_attrs(env), NULL);
70 #endif
71 }
72 
73 target_ulong helper_inw(CPUX86State *env, uint32_t port)
74 {
75 #ifdef CONFIG_USER_ONLY
76     fprintf(stderr, "inw: port=0x%04x\n", port);
77     return 0;
78 #else
79     return address_space_lduw(&address_space_io, port,
80                               cpu_get_mem_attrs(env), NULL);
81 #endif
82 }
83 
84 void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
85 {
86 #ifdef CONFIG_USER_ONLY
87     fprintf(stderr, "outl: port=0x%04x, data=%08x\n", port, data);
88 #else
89     address_space_stl(&address_space_io, port, data,
90                       cpu_get_mem_attrs(env), NULL);
91 #endif
92 }
93 
94 target_ulong helper_inl(CPUX86State *env, uint32_t port)
95 {
96 #ifdef CONFIG_USER_ONLY
97     fprintf(stderr, "inl: port=0x%04x\n", port);
98     return 0;
99 #else
100     return address_space_ldl(&address_space_io, port,
101                              cpu_get_mem_attrs(env), NULL);
102 #endif
103 }
104 
105 void helper_into(CPUX86State *env, int next_eip_addend)
106 {
107     int eflags;
108 
109     eflags = cpu_cc_compute_all(env, CC_OP);
110     if (eflags & CC_O) {
111         raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
112     }
113 }
114 
115 void helper_cpuid(CPUX86State *env)
116 {
117     uint32_t eax, ebx, ecx, edx;
118 
119     cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
120 
121     cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
122                   &eax, &ebx, &ecx, &edx);
123     env->regs[R_EAX] = eax;
124     env->regs[R_EBX] = ebx;
125     env->regs[R_ECX] = ecx;
126     env->regs[R_EDX] = edx;
127 }
128 
129 #if defined(CONFIG_USER_ONLY)
130 target_ulong helper_read_crN(CPUX86State *env, int reg)
131 {
132     return 0;
133 }
134 
135 void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
136 {
137 }
138 #else
139 target_ulong helper_read_crN(CPUX86State *env, int reg)
140 {
141     target_ulong val;
142 
143     cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
144     switch (reg) {
145     default:
146         val = env->cr[reg];
147         break;
148     case 8:
149         if (!(env->hflags2 & HF2_VINTR_MASK)) {
150             val = cpu_get_apic_tpr(env_archcpu(env)->apic_state);
151         } else {
152             val = env->v_tpr;
153         }
154         break;
155     }
156     return val;
157 }
158 
159 void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
160 {
161     cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
162     switch (reg) {
163     case 0:
164         cpu_x86_update_cr0(env, t0);
165         break;
166     case 3:
167         cpu_x86_update_cr3(env, t0);
168         break;
169     case 4:
170         if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) &&
171             (env->hflags & HF_CS64_MASK)) {
172              raise_exception_ra(env, EXCP0D_GPF, GETPC());
173         }
174         cpu_x86_update_cr4(env, t0);
175         break;
176     case 8:
177         if (!(env->hflags2 & HF2_VINTR_MASK)) {
178             qemu_mutex_lock_iothread();
179             cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0);
180             qemu_mutex_unlock_iothread();
181         }
182         env->v_tpr = t0 & 0x0f;
183         break;
184     default:
185         env->cr[reg] = t0;
186         break;
187     }
188 }
189 #endif
190 
191 void helper_lmsw(CPUX86State *env, target_ulong t0)
192 {
193     /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
194        if already set to one. */
195     t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
196     helper_write_crN(env, 0, t0);
197 }
198 
199 void helper_invlpg(CPUX86State *env, target_ulong addr)
200 {
201     X86CPU *cpu = env_archcpu(env);
202 
203     cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
204     tlb_flush_page(CPU(cpu), addr);
205 }
206 
207 void helper_rdtsc(CPUX86State *env)
208 {
209     uint64_t val;
210 
211     if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
212         raise_exception_ra(env, EXCP0D_GPF, GETPC());
213     }
214     cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC());
215 
216     val = cpu_get_tsc(env) + env->tsc_offset;
217     env->regs[R_EAX] = (uint32_t)(val);
218     env->regs[R_EDX] = (uint32_t)(val >> 32);
219 }
220 
221 void helper_rdtscp(CPUX86State *env)
222 {
223     helper_rdtsc(env);
224     env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
225 }
226 
227 void helper_rdpmc(CPUX86State *env)
228 {
229     if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
230         ((env->hflags & HF_CPL_MASK) != 0)) {
231         raise_exception_ra(env, EXCP0D_GPF, GETPC());
232     }
233     cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
234 
235     /* currently unimplemented */
236     qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
237     raise_exception_err(env, EXCP06_ILLOP, 0);
238 }
239 
240 #if defined(CONFIG_USER_ONLY)
241 void helper_wrmsr(CPUX86State *env)
242 {
243 }
244 
245 void helper_rdmsr(CPUX86State *env)
246 {
247 }
248 #else
249 void helper_wrmsr(CPUX86State *env)
250 {
251     uint64_t val;
252     CPUState *cs = env_cpu(env);
253 
254     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());
255 
256     val = ((uint32_t)env->regs[R_EAX]) |
257         ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
258 
259     switch ((uint32_t)env->regs[R_ECX]) {
260     case MSR_IA32_SYSENTER_CS:
261         env->sysenter_cs = val & 0xffff;
262         break;
263     case MSR_IA32_SYSENTER_ESP:
264         env->sysenter_esp = val;
265         break;
266     case MSR_IA32_SYSENTER_EIP:
267         env->sysenter_eip = val;
268         break;
269     case MSR_IA32_APICBASE:
270         cpu_set_apic_base(env_archcpu(env)->apic_state, val);
271         break;
272     case MSR_EFER:
273         {
274             uint64_t update_mask;
275 
276             update_mask = 0;
277             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
278                 update_mask |= MSR_EFER_SCE;
279             }
280             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
281                 update_mask |= MSR_EFER_LME;
282             }
283             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
284                 update_mask |= MSR_EFER_FFXSR;
285             }
286             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
287                 update_mask |= MSR_EFER_NXE;
288             }
289             if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
290                 update_mask |= MSR_EFER_SVME;
291             }
292             if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
293                 update_mask |= MSR_EFER_FFXSR;
294             }
295             cpu_load_efer(env, (env->efer & ~update_mask) |
296                           (val & update_mask));
297         }
298         break;
299     case MSR_STAR:
300         env->star = val;
301         break;
302     case MSR_PAT:
303         env->pat = val;
304         break;
305     case MSR_IA32_PKRS:
306         if (val & 0xFFFFFFFF00000000ull) {
307             goto error;
308         }
309         env->pkrs = val;
310         tlb_flush(cs);
311         break;
312     case MSR_VM_HSAVE_PA:
313         env->vm_hsave = val;
314         break;
315 #ifdef TARGET_X86_64
316     case MSR_LSTAR:
317         env->lstar = val;
318         break;
319     case MSR_CSTAR:
320         env->cstar = val;
321         break;
322     case MSR_FMASK:
323         env->fmask = val;
324         break;
325     case MSR_FSBASE:
326         env->segs[R_FS].base = val;
327         break;
328     case MSR_GSBASE:
329         env->segs[R_GS].base = val;
330         break;
331     case MSR_KERNELGSBASE:
332         env->kernelgsbase = val;
333         break;
334 #endif
335     case MSR_MTRRphysBase(0):
336     case MSR_MTRRphysBase(1):
337     case MSR_MTRRphysBase(2):
338     case MSR_MTRRphysBase(3):
339     case MSR_MTRRphysBase(4):
340     case MSR_MTRRphysBase(5):
341     case MSR_MTRRphysBase(6):
342     case MSR_MTRRphysBase(7):
343         env->mtrr_var[((uint32_t)env->regs[R_ECX] -
344                        MSR_MTRRphysBase(0)) / 2].base = val;
345         break;
346     case MSR_MTRRphysMask(0):
347     case MSR_MTRRphysMask(1):
348     case MSR_MTRRphysMask(2):
349     case MSR_MTRRphysMask(3):
350     case MSR_MTRRphysMask(4):
351     case MSR_MTRRphysMask(5):
352     case MSR_MTRRphysMask(6):
353     case MSR_MTRRphysMask(7):
354         env->mtrr_var[((uint32_t)env->regs[R_ECX] -
355                        MSR_MTRRphysMask(0)) / 2].mask = val;
356         break;
357     case MSR_MTRRfix64K_00000:
358         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
359                         MSR_MTRRfix64K_00000] = val;
360         break;
361     case MSR_MTRRfix16K_80000:
362     case MSR_MTRRfix16K_A0000:
363         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
364                         MSR_MTRRfix16K_80000 + 1] = val;
365         break;
366     case MSR_MTRRfix4K_C0000:
367     case MSR_MTRRfix4K_C8000:
368     case MSR_MTRRfix4K_D0000:
369     case MSR_MTRRfix4K_D8000:
370     case MSR_MTRRfix4K_E0000:
371     case MSR_MTRRfix4K_E8000:
372     case MSR_MTRRfix4K_F0000:
373     case MSR_MTRRfix4K_F8000:
374         env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
375                         MSR_MTRRfix4K_C0000 + 3] = val;
376         break;
377     case MSR_MTRRdefType:
378         env->mtrr_deftype = val;
379         break;
380     case MSR_MCG_STATUS:
381         env->mcg_status = val;
382         break;
383     case MSR_MCG_CTL:
384         if ((env->mcg_cap & MCG_CTL_P)
385             && (val == 0 || val == ~(uint64_t)0)) {
386             env->mcg_ctl = val;
387         }
388         break;
389     case MSR_TSC_AUX:
390         env->tsc_aux = val;
391         break;
392     case MSR_IA32_MISC_ENABLE:
393         env->msr_ia32_misc_enable = val;
394         break;
395     case MSR_IA32_BNDCFGS:
396         /* FIXME: #GP if reserved bits are set.  */
397         /* FIXME: Extend highest implemented bit of linear address.  */
398         env->msr_bndcfgs = val;
399         cpu_sync_bndcs_hflags(env);
400         break;
401     default:
402         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
403             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
404             (4 * env->mcg_cap & 0xff)) {
405             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
406             if ((offset & 0x3) != 0
407                 || (val == 0 || val == ~(uint64_t)0)) {
408                 env->mce_banks[offset] = val;
409             }
410             break;
411         }
412         /* XXX: exception? */
413         break;
414     }
415     return;
416 error:
417     raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
418 }
419 
420 void helper_rdmsr(CPUX86State *env)
421 {
422     X86CPU *x86_cpu = env_archcpu(env);
423     uint64_t val;
424 
425     cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
426 
427     switch ((uint32_t)env->regs[R_ECX]) {
428     case MSR_IA32_SYSENTER_CS:
429         val = env->sysenter_cs;
430         break;
431     case MSR_IA32_SYSENTER_ESP:
432         val = env->sysenter_esp;
433         break;
434     case MSR_IA32_SYSENTER_EIP:
435         val = env->sysenter_eip;
436         break;
437     case MSR_IA32_APICBASE:
438         val = cpu_get_apic_base(env_archcpu(env)->apic_state);
439         break;
440     case MSR_EFER:
441         val = env->efer;
442         break;
443     case MSR_STAR:
444         val = env->star;
445         break;
446     case MSR_PAT:
447         val = env->pat;
448         break;
449     case MSR_IA32_PKRS:
450         val = env->pkrs;
451         break;
452     case MSR_VM_HSAVE_PA:
453         val = env->vm_hsave;
454         break;
455     case MSR_IA32_PERF_STATUS:
456         /* tsc_increment_by_tick */
457         val = 1000ULL;
458         /* CPU multiplier */
459         val |= (((uint64_t)4ULL) << 40);
460         break;
461 #ifdef TARGET_X86_64
462     case MSR_LSTAR:
463         val = env->lstar;
464         break;
465     case MSR_CSTAR:
466         val = env->cstar;
467         break;
468     case MSR_FMASK:
469         val = env->fmask;
470         break;
471     case MSR_FSBASE:
472         val = env->segs[R_FS].base;
473         break;
474     case MSR_GSBASE:
475         val = env->segs[R_GS].base;
476         break;
477     case MSR_KERNELGSBASE:
478         val = env->kernelgsbase;
479         break;
480     case MSR_TSC_AUX:
481         val = env->tsc_aux;
482         break;
483 #endif
484     case MSR_SMI_COUNT:
485         val = env->msr_smi_count;
486         break;
487     case MSR_MTRRphysBase(0):
488     case MSR_MTRRphysBase(1):
489     case MSR_MTRRphysBase(2):
490     case MSR_MTRRphysBase(3):
491     case MSR_MTRRphysBase(4):
492     case MSR_MTRRphysBase(5):
493     case MSR_MTRRphysBase(6):
494     case MSR_MTRRphysBase(7):
495         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
496                              MSR_MTRRphysBase(0)) / 2].base;
497         break;
498     case MSR_MTRRphysMask(0):
499     case MSR_MTRRphysMask(1):
500     case MSR_MTRRphysMask(2):
501     case MSR_MTRRphysMask(3):
502     case MSR_MTRRphysMask(4):
503     case MSR_MTRRphysMask(5):
504     case MSR_MTRRphysMask(6):
505     case MSR_MTRRphysMask(7):
506         val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
507                              MSR_MTRRphysMask(0)) / 2].mask;
508         break;
509     case MSR_MTRRfix64K_00000:
510         val = env->mtrr_fixed[0];
511         break;
512     case MSR_MTRRfix16K_80000:
513     case MSR_MTRRfix16K_A0000:
514         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
515                               MSR_MTRRfix16K_80000 + 1];
516         break;
517     case MSR_MTRRfix4K_C0000:
518     case MSR_MTRRfix4K_C8000:
519     case MSR_MTRRfix4K_D0000:
520     case MSR_MTRRfix4K_D8000:
521     case MSR_MTRRfix4K_E0000:
522     case MSR_MTRRfix4K_E8000:
523     case MSR_MTRRfix4K_F0000:
524     case MSR_MTRRfix4K_F8000:
525         val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
526                               MSR_MTRRfix4K_C0000 + 3];
527         break;
528     case MSR_MTRRdefType:
529         val = env->mtrr_deftype;
530         break;
531     case MSR_MTRRcap:
532         if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
533             val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
534                 MSR_MTRRcap_WC_SUPPORTED;
535         } else {
536             /* XXX: exception? */
537             val = 0;
538         }
539         break;
540     case MSR_MCG_CAP:
541         val = env->mcg_cap;
542         break;
543     case MSR_MCG_CTL:
544         if (env->mcg_cap & MCG_CTL_P) {
545             val = env->mcg_ctl;
546         } else {
547             val = 0;
548         }
549         break;
550     case MSR_MCG_STATUS:
551         val = env->mcg_status;
552         break;
553     case MSR_IA32_MISC_ENABLE:
554         val = env->msr_ia32_misc_enable;
555         break;
556     case MSR_IA32_BNDCFGS:
557         val = env->msr_bndcfgs;
558         break;
559      case MSR_IA32_UCODE_REV:
560         val = x86_cpu->ucode_rev;
561         break;
562     default:
563         if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
564             && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
565             (4 * env->mcg_cap & 0xff)) {
566             uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
567             val = env->mce_banks[offset];
568             break;
569         }
570         /* XXX: exception? */
571         val = 0;
572         break;
573     }
574     env->regs[R_EAX] = (uint32_t)(val);
575     env->regs[R_EDX] = (uint32_t)(val >> 32);
576 }
577 #endif
578 
579 static void do_pause(X86CPU *cpu)
580 {
581     CPUState *cs = CPU(cpu);
582 
583     /* Just let another CPU run.  */
584     cs->exception_index = EXCP_INTERRUPT;
585     cpu_loop_exit(cs);
586 }
587 
588 static void do_hlt(X86CPU *cpu)
589 {
590     CPUState *cs = CPU(cpu);
591     CPUX86State *env = &cpu->env;
592 
593     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
594     cs->halted = 1;
595     cs->exception_index = EXCP_HLT;
596     cpu_loop_exit(cs);
597 }
598 
599 void helper_hlt(CPUX86State *env, int next_eip_addend)
600 {
601     X86CPU *cpu = env_archcpu(env);
602 
603     cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
604     env->eip += next_eip_addend;
605 
606     do_hlt(cpu);
607 }
608 
609 void helper_monitor(CPUX86State *env, target_ulong ptr)
610 {
611     if ((uint32_t)env->regs[R_ECX] != 0) {
612         raise_exception_ra(env, EXCP0D_GPF, GETPC());
613     }
614     /* XXX: store address? */
615     cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
616 }
617 
618 void helper_mwait(CPUX86State *env, int next_eip_addend)
619 {
620     CPUState *cs = env_cpu(env);
621     X86CPU *cpu = env_archcpu(env);
622 
623     if ((uint32_t)env->regs[R_ECX] != 0) {
624         raise_exception_ra(env, EXCP0D_GPF, GETPC());
625     }
626     cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
627     env->eip += next_eip_addend;
628 
629     /* XXX: not complete but not completely erroneous */
630     if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
631         do_pause(cpu);
632     } else {
633         do_hlt(cpu);
634     }
635 }
636 
637 void helper_pause(CPUX86State *env, int next_eip_addend)
638 {
639     X86CPU *cpu = env_archcpu(env);
640 
641     cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
642     env->eip += next_eip_addend;
643 
644     do_pause(cpu);
645 }
646 
647 void helper_debug(CPUX86State *env)
648 {
649     CPUState *cs = env_cpu(env);
650 
651     cs->exception_index = EXCP_DEBUG;
652     cpu_loop_exit(cs);
653 }
654 
655 uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
656 {
657     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
658         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
659     }
660     if (ecx != 0) {
661         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
662     }
663 
664     return env->pkru;
665 }
666 
667 void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
668 {
669     CPUState *cs = env_cpu(env);
670 
671     if ((env->cr[4] & CR4_PKE_MASK) == 0) {
672         raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
673     }
674     if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
675         raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
676     }
677 
678     env->pkru = val;
679     tlb_flush(cs);
680 }
681