xref: /openbmc/qemu/target/i386/helper.c (revision b0c3cf9407e642d74d1bbd18f8846872152a92df)
1 /*
2  *  i386 helpers (without register variable usage)
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 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 "cpu.h"
22 #include "exec/exec-all.h"
23 #include "qemu/qemu-print.h"
24 #include "sysemu/kvm.h"
25 #include "sysemu/runstate.h"
26 #include "kvm_i386.h"
27 #ifndef CONFIG_USER_ONLY
28 #include "sysemu/tcg.h"
29 #include "sysemu/hw_accel.h"
30 #include "monitor/monitor.h"
31 #include "hw/i386/apic_internal.h"
32 #endif
33 
34 void cpu_sync_bndcs_hflags(CPUX86State *env)
35 {
36     uint32_t hflags = env->hflags;
37     uint32_t hflags2 = env->hflags2;
38     uint32_t bndcsr;
39 
40     if ((hflags & HF_CPL_MASK) == 3) {
41         bndcsr = env->bndcs_regs.cfgu;
42     } else {
43         bndcsr = env->msr_bndcfgs;
44     }
45 
46     if ((env->cr[4] & CR4_OSXSAVE_MASK)
47         && (env->xcr0 & XSTATE_BNDCSR_MASK)
48         && (bndcsr & BNDCFG_ENABLE)) {
49         hflags |= HF_MPX_EN_MASK;
50     } else {
51         hflags &= ~HF_MPX_EN_MASK;
52     }
53 
54     if (bndcsr & BNDCFG_BNDPRESERVE) {
55         hflags2 |= HF2_MPX_PR_MASK;
56     } else {
57         hflags2 &= ~HF2_MPX_PR_MASK;
58     }
59 
60     env->hflags = hflags;
61     env->hflags2 = hflags2;
62 }
63 
64 static void cpu_x86_version(CPUX86State *env, int *family, int *model)
65 {
66     int cpuver = env->cpuid_version;
67 
68     if (family == NULL || model == NULL) {
69         return;
70     }
71 
72     *family = (cpuver >> 8) & 0x0f;
73     *model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0x0f);
74 }
75 
76 /* Broadcast MCA signal for processor version 06H_EH and above */
77 int cpu_x86_support_mca_broadcast(CPUX86State *env)
78 {
79     int family = 0;
80     int model = 0;
81 
82     cpu_x86_version(env, &family, &model);
83     if ((family == 6 && model >= 14) || family > 6) {
84         return 1;
85     }
86 
87     return 0;
88 }
89 
90 /***********************************************************/
91 /* x86 debug */
92 
93 static const char *cc_op_str[CC_OP_NB] = {
94     "DYNAMIC",
95     "EFLAGS",
96 
97     "MULB",
98     "MULW",
99     "MULL",
100     "MULQ",
101 
102     "ADDB",
103     "ADDW",
104     "ADDL",
105     "ADDQ",
106 
107     "ADCB",
108     "ADCW",
109     "ADCL",
110     "ADCQ",
111 
112     "SUBB",
113     "SUBW",
114     "SUBL",
115     "SUBQ",
116 
117     "SBBB",
118     "SBBW",
119     "SBBL",
120     "SBBQ",
121 
122     "LOGICB",
123     "LOGICW",
124     "LOGICL",
125     "LOGICQ",
126 
127     "INCB",
128     "INCW",
129     "INCL",
130     "INCQ",
131 
132     "DECB",
133     "DECW",
134     "DECL",
135     "DECQ",
136 
137     "SHLB",
138     "SHLW",
139     "SHLL",
140     "SHLQ",
141 
142     "SARB",
143     "SARW",
144     "SARL",
145     "SARQ",
146 
147     "BMILGB",
148     "BMILGW",
149     "BMILGL",
150     "BMILGQ",
151 
152     "ADCX",
153     "ADOX",
154     "ADCOX",
155 
156     "CLR",
157 };
158 
159 static void
160 cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f,
161                        const char *name, struct SegmentCache *sc)
162 {
163 #ifdef TARGET_X86_64
164     if (env->hflags & HF_CS64_MASK) {
165         qemu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
166                      sc->selector, sc->base, sc->limit,
167                      sc->flags & 0x00ffff00);
168     } else
169 #endif
170     {
171         qemu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
172                      (uint32_t)sc->base, sc->limit,
173                      sc->flags & 0x00ffff00);
174     }
175 
176     if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
177         goto done;
178 
179     qemu_fprintf(f, " DPL=%d ",
180                  (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT);
181     if (sc->flags & DESC_S_MASK) {
182         if (sc->flags & DESC_CS_MASK) {
183             qemu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" :
184                          ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16"));
185             qemu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
186                          (sc->flags & DESC_R_MASK) ? 'R' : '-');
187         } else {
188             qemu_fprintf(f, (sc->flags & DESC_B_MASK
189                              || env->hflags & HF_LMA_MASK)
190                          ? "DS  " : "DS16");
191             qemu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
192                          (sc->flags & DESC_W_MASK) ? 'W' : '-');
193         }
194         qemu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-');
195     } else {
196         static const char *sys_type_name[2][16] = {
197             { /* 32 bit mode */
198                 "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
199                 "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
200                 "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
201                 "CallGate32", "Reserved", "IntGate32", "TrapGate32"
202             },
203             { /* 64 bit mode */
204                 "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
205                 "Reserved", "Reserved", "Reserved", "Reserved",
206                 "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
207                 "Reserved", "IntGate64", "TrapGate64"
208             }
209         };
210         qemu_fprintf(f, "%s",
211                      sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0]
212                      [(sc->flags & DESC_TYPE_MASK) >> DESC_TYPE_SHIFT]);
213     }
214 done:
215     qemu_fprintf(f, "\n");
216 }
217 
218 #ifndef CONFIG_USER_ONLY
219 
220 /* ARRAY_SIZE check is not required because
221  * DeliveryMode(dm) has a size of 3 bit.
222  */
223 static inline const char *dm2str(uint32_t dm)
224 {
225     static const char *str[] = {
226         "Fixed",
227         "...",
228         "SMI",
229         "...",
230         "NMI",
231         "INIT",
232         "...",
233         "ExtINT"
234     };
235     return str[dm];
236 }
237 
238 static void dump_apic_lvt(const char *name, uint32_t lvt, bool is_timer)
239 {
240     uint32_t dm = (lvt & APIC_LVT_DELIV_MOD) >> APIC_LVT_DELIV_MOD_SHIFT;
241     qemu_printf("%s\t 0x%08x %s %-5s %-6s %-7s %-12s %-6s",
242                 name, lvt,
243                 lvt & APIC_LVT_INT_POLARITY ? "active-lo" : "active-hi",
244                 lvt & APIC_LVT_LEVEL_TRIGGER ? "level" : "edge",
245                 lvt & APIC_LVT_MASKED ? "masked" : "",
246                 lvt & APIC_LVT_DELIV_STS ? "pending" : "",
247                 !is_timer ?
248                     "" : lvt & APIC_LVT_TIMER_PERIODIC ?
249                             "periodic" : lvt & APIC_LVT_TIMER_TSCDEADLINE ?
250                                             "tsc-deadline" : "one-shot",
251                 dm2str(dm));
252     if (dm != APIC_DM_NMI) {
253         qemu_printf(" (vec %u)\n", lvt & APIC_VECTOR_MASK);
254     } else {
255         qemu_printf("\n");
256     }
257 }
258 
259 /* ARRAY_SIZE check is not required because
260  * destination shorthand has a size of 2 bit.
261  */
262 static inline const char *shorthand2str(uint32_t shorthand)
263 {
264     const char *str[] = {
265         "no-shorthand", "self", "all-self", "all"
266     };
267     return str[shorthand];
268 }
269 
270 static inline uint8_t divider_conf(uint32_t divide_conf)
271 {
272     uint8_t divide_val = ((divide_conf & 0x8) >> 1) | (divide_conf & 0x3);
273 
274     return divide_val == 7 ? 1 : 2 << divide_val;
275 }
276 
277 static inline void mask2str(char *str, uint32_t val, uint8_t size)
278 {
279     while (size--) {
280         *str++ = (val >> size) & 1 ? '1' : '0';
281     }
282     *str = 0;
283 }
284 
285 #define MAX_LOGICAL_APIC_ID_MASK_SIZE 16
286 
287 static void dump_apic_icr(APICCommonState *s, CPUX86State *env)
288 {
289     uint32_t icr = s->icr[0], icr2 = s->icr[1];
290     uint8_t dest_shorthand = \
291         (icr & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT;
292     bool logical_mod = icr & APIC_ICR_DEST_MOD;
293     char apic_id_str[MAX_LOGICAL_APIC_ID_MASK_SIZE + 1];
294     uint32_t dest_field;
295     bool x2apic;
296 
297     qemu_printf("ICR\t 0x%08x %s %s %s %s\n",
298                 icr,
299                 logical_mod ? "logical" : "physical",
300                 icr & APIC_ICR_TRIGGER_MOD ? "level" : "edge",
301                 icr & APIC_ICR_LEVEL ? "assert" : "de-assert",
302                 shorthand2str(dest_shorthand));
303 
304     qemu_printf("ICR2\t 0x%08x", icr2);
305     if (dest_shorthand != 0) {
306         qemu_printf("\n");
307         return;
308     }
309     x2apic = env->features[FEAT_1_ECX] & CPUID_EXT_X2APIC;
310     dest_field = x2apic ? icr2 : icr2 >> APIC_ICR_DEST_SHIFT;
311 
312     if (!logical_mod) {
313         if (x2apic) {
314             qemu_printf(" cpu %u (X2APIC ID)\n", dest_field);
315         } else {
316             qemu_printf(" cpu %u (APIC ID)\n",
317                         dest_field & APIC_LOGDEST_XAPIC_ID);
318         }
319         return;
320     }
321 
322     if (s->dest_mode == 0xf) { /* flat mode */
323         mask2str(apic_id_str, icr2 >> APIC_ICR_DEST_SHIFT, 8);
324         qemu_printf(" mask %s (APIC ID)\n", apic_id_str);
325     } else if (s->dest_mode == 0) { /* cluster mode */
326         if (x2apic) {
327             mask2str(apic_id_str, dest_field & APIC_LOGDEST_X2APIC_ID, 16);
328             qemu_printf(" cluster %u mask %s (X2APIC ID)\n",
329                         dest_field >> APIC_LOGDEST_X2APIC_SHIFT, apic_id_str);
330         } else {
331             mask2str(apic_id_str, dest_field & APIC_LOGDEST_XAPIC_ID, 4);
332             qemu_printf(" cluster %u mask %s (APIC ID)\n",
333                         dest_field >> APIC_LOGDEST_XAPIC_SHIFT, apic_id_str);
334         }
335     }
336 }
337 
338 static void dump_apic_interrupt(const char *name, uint32_t *ireg_tab,
339                                 uint32_t *tmr_tab)
340 {
341     int i, empty = true;
342 
343     qemu_printf("%s\t ", name);
344     for (i = 0; i < 256; i++) {
345         if (apic_get_bit(ireg_tab, i)) {
346             qemu_printf("%u%s ", i,
347                         apic_get_bit(tmr_tab, i) ? "(level)" : "");
348             empty = false;
349         }
350     }
351     qemu_printf("%s\n", empty ? "(none)" : "");
352 }
353 
354 void x86_cpu_dump_local_apic_state(CPUState *cs, int flags)
355 {
356     X86CPU *cpu = X86_CPU(cs);
357     APICCommonState *s = APIC_COMMON(cpu->apic_state);
358     if (!s) {
359         qemu_printf("local apic state not available\n");
360         return;
361     }
362     uint32_t *lvt = s->lvt;
363 
364     qemu_printf("dumping local APIC state for CPU %-2u\n\n",
365                 CPU(cpu)->cpu_index);
366     dump_apic_lvt("LVT0", lvt[APIC_LVT_LINT0], false);
367     dump_apic_lvt("LVT1", lvt[APIC_LVT_LINT1], false);
368     dump_apic_lvt("LVTPC", lvt[APIC_LVT_PERFORM], false);
369     dump_apic_lvt("LVTERR", lvt[APIC_LVT_ERROR], false);
370     dump_apic_lvt("LVTTHMR", lvt[APIC_LVT_THERMAL], false);
371     dump_apic_lvt("LVTT", lvt[APIC_LVT_TIMER], true);
372 
373     qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u\n",
374                 s->divide_conf & APIC_DCR_MASK,
375                 divider_conf(s->divide_conf),
376                 s->initial_count);
377 
378     qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n",
379                 s->spurious_vec,
380                 s->spurious_vec & APIC_SPURIO_ENABLED ? "enabled" : "disabled",
381                 s->spurious_vec & APIC_SPURIO_FOCUS ? "on" : "off",
382                 s->spurious_vec & APIC_VECTOR_MASK);
383 
384     dump_apic_icr(s, &cpu->env);
385 
386     qemu_printf("ESR\t 0x%08x\n", s->esr);
387 
388     dump_apic_interrupt("ISR", s->isr, s->tmr);
389     dump_apic_interrupt("IRR", s->irr, s->tmr);
390 
391     qemu_printf("\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x",
392                 s->arb_id, s->tpr, s->dest_mode, s->log_dest);
393     if (s->dest_mode == 0) {
394         qemu_printf("(cluster %u: id %u)",
395                     s->log_dest >> APIC_LOGDEST_XAPIC_SHIFT,
396                     s->log_dest & APIC_LOGDEST_XAPIC_ID);
397     }
398     qemu_printf(" PPR 0x%02x\n", apic_get_ppr(s));
399 }
400 #else
401 void x86_cpu_dump_local_apic_state(CPUState *cs, int flags)
402 {
403 }
404 #endif /* !CONFIG_USER_ONLY */
405 
406 #define DUMP_CODE_BYTES_TOTAL    50
407 #define DUMP_CODE_BYTES_BACKWARD 20
408 
409 void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
410 {
411     X86CPU *cpu = X86_CPU(cs);
412     CPUX86State *env = &cpu->env;
413     int eflags, i, nb;
414     char cc_op_name[32];
415     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
416 
417     eflags = cpu_compute_eflags(env);
418 #ifdef TARGET_X86_64
419     if (env->hflags & HF_CS64_MASK) {
420         qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
421                      "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
422                      "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
423                      "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
424                      "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
425                      env->regs[R_EAX],
426                      env->regs[R_EBX],
427                      env->regs[R_ECX],
428                      env->regs[R_EDX],
429                      env->regs[R_ESI],
430                      env->regs[R_EDI],
431                      env->regs[R_EBP],
432                      env->regs[R_ESP],
433                      env->regs[8],
434                      env->regs[9],
435                      env->regs[10],
436                      env->regs[11],
437                      env->regs[12],
438                      env->regs[13],
439                      env->regs[14],
440                      env->regs[15],
441                      env->eip, eflags,
442                      eflags & DF_MASK ? 'D' : '-',
443                      eflags & CC_O ? 'O' : '-',
444                      eflags & CC_S ? 'S' : '-',
445                      eflags & CC_Z ? 'Z' : '-',
446                      eflags & CC_A ? 'A' : '-',
447                      eflags & CC_P ? 'P' : '-',
448                      eflags & CC_C ? 'C' : '-',
449                      env->hflags & HF_CPL_MASK,
450                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
451                      (env->a20_mask >> 20) & 1,
452                      (env->hflags >> HF_SMM_SHIFT) & 1,
453                      cs->halted);
454     } else
455 #endif
456     {
457         qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
458                      "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
459                      "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
460                      (uint32_t)env->regs[R_EAX],
461                      (uint32_t)env->regs[R_EBX],
462                      (uint32_t)env->regs[R_ECX],
463                      (uint32_t)env->regs[R_EDX],
464                      (uint32_t)env->regs[R_ESI],
465                      (uint32_t)env->regs[R_EDI],
466                      (uint32_t)env->regs[R_EBP],
467                      (uint32_t)env->regs[R_ESP],
468                      (uint32_t)env->eip, eflags,
469                      eflags & DF_MASK ? 'D' : '-',
470                      eflags & CC_O ? 'O' : '-',
471                      eflags & CC_S ? 'S' : '-',
472                      eflags & CC_Z ? 'Z' : '-',
473                      eflags & CC_A ? 'A' : '-',
474                      eflags & CC_P ? 'P' : '-',
475                      eflags & CC_C ? 'C' : '-',
476                      env->hflags & HF_CPL_MASK,
477                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
478                      (env->a20_mask >> 20) & 1,
479                      (env->hflags >> HF_SMM_SHIFT) & 1,
480                      cs->halted);
481     }
482 
483     for(i = 0; i < 6; i++) {
484         cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]);
485     }
486     cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt);
487     cpu_x86_dump_seg_cache(env, f, "TR", &env->tr);
488 
489 #ifdef TARGET_X86_64
490     if (env->hflags & HF_LMA_MASK) {
491         qemu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
492                      env->gdt.base, env->gdt.limit);
493         qemu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
494                      env->idt.base, env->idt.limit);
495         qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
496                      (uint32_t)env->cr[0],
497                      env->cr[2],
498                      env->cr[3],
499                      (uint32_t)env->cr[4]);
500         for(i = 0; i < 4; i++)
501             qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
502         qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
503                      env->dr[6], env->dr[7]);
504     } else
505 #endif
506     {
507         qemu_fprintf(f, "GDT=     %08x %08x\n",
508                      (uint32_t)env->gdt.base, env->gdt.limit);
509         qemu_fprintf(f, "IDT=     %08x %08x\n",
510                      (uint32_t)env->idt.base, env->idt.limit);
511         qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
512                      (uint32_t)env->cr[0],
513                      (uint32_t)env->cr[2],
514                      (uint32_t)env->cr[3],
515                      (uint32_t)env->cr[4]);
516         for(i = 0; i < 4; i++) {
517             qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
518         }
519         qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
520                      env->dr[6], env->dr[7]);
521     }
522     if (flags & CPU_DUMP_CCOP) {
523         if ((unsigned)env->cc_op < CC_OP_NB)
524             snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
525         else
526             snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
527 #ifdef TARGET_X86_64
528         if (env->hflags & HF_CS64_MASK) {
529             qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
530                          env->cc_src, env->cc_dst,
531                          cc_op_name);
532         } else
533 #endif
534         {
535             qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
536                          (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
537                          cc_op_name);
538         }
539     }
540     qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
541     if (flags & CPU_DUMP_FPU) {
542         int fptag;
543         fptag = 0;
544         for(i = 0; i < 8; i++) {
545             fptag |= ((!env->fptags[i]) << i);
546         }
547         update_mxcsr_from_sse_status(env);
548         qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
549                      env->fpuc,
550                      (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
551                      env->fpstt,
552                      fptag,
553                      env->mxcsr);
554         for(i=0;i<8;i++) {
555             CPU_LDoubleU u;
556             u.d = env->fpregs[i].d;
557             qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
558                          i, u.l.lower, u.l.upper);
559             if ((i & 1) == 1)
560                 qemu_fprintf(f, "\n");
561             else
562                 qemu_fprintf(f, " ");
563         }
564         if (env->hflags & HF_CS64_MASK)
565             nb = 16;
566         else
567             nb = 8;
568         for(i=0;i<nb;i++) {
569             qemu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
570                          i,
571                          env->xmm_regs[i].ZMM_L(3),
572                          env->xmm_regs[i].ZMM_L(2),
573                          env->xmm_regs[i].ZMM_L(1),
574                          env->xmm_regs[i].ZMM_L(0));
575             if ((i & 1) == 1)
576                 qemu_fprintf(f, "\n");
577             else
578                 qemu_fprintf(f, " ");
579         }
580     }
581     if (flags & CPU_DUMP_CODE) {
582         target_ulong base = env->segs[R_CS].base + env->eip;
583         target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
584         uint8_t code;
585         char codestr[3];
586 
587         qemu_fprintf(f, "Code=");
588         for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
589             if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
590                 snprintf(codestr, sizeof(codestr), "%02x", code);
591             } else {
592                 snprintf(codestr, sizeof(codestr), "??");
593             }
594             qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
595                          i == offs ? "<" : "", codestr, i == offs ? ">" : "");
596         }
597         qemu_fprintf(f, "\n");
598     }
599 }
600 
601 /***********************************************************/
602 /* x86 mmu */
603 /* XXX: add PGE support */
604 
605 void x86_cpu_set_a20(X86CPU *cpu, int a20_state)
606 {
607     CPUX86State *env = &cpu->env;
608 
609     a20_state = (a20_state != 0);
610     if (a20_state != ((env->a20_mask >> 20) & 1)) {
611         CPUState *cs = CPU(cpu);
612 
613         qemu_log_mask(CPU_LOG_MMU, "A20 update: a20=%d\n", a20_state);
614         /* if the cpu is currently executing code, we must unlink it and
615            all the potentially executing TB */
616         cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
617 
618         /* when a20 is changed, all the MMU mappings are invalid, so
619            we must flush everything */
620         tlb_flush(cs);
621         env->a20_mask = ~(1 << 20) | (a20_state << 20);
622     }
623 }
624 
625 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
626 {
627     X86CPU *cpu = env_archcpu(env);
628     int pe_state;
629 
630     qemu_log_mask(CPU_LOG_MMU, "CR0 update: CR0=0x%08x\n", new_cr0);
631     if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
632         (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
633         tlb_flush(CPU(cpu));
634     }
635 
636 #ifdef TARGET_X86_64
637     if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
638         (env->efer & MSR_EFER_LME)) {
639         /* enter in long mode */
640         /* XXX: generate an exception */
641         if (!(env->cr[4] & CR4_PAE_MASK))
642             return;
643         env->efer |= MSR_EFER_LMA;
644         env->hflags |= HF_LMA_MASK;
645     } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
646                (env->efer & MSR_EFER_LMA)) {
647         /* exit long mode */
648         env->efer &= ~MSR_EFER_LMA;
649         env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
650         env->eip &= 0xffffffff;
651     }
652 #endif
653     env->cr[0] = new_cr0 | CR0_ET_MASK;
654 
655     /* update PE flag in hidden flags */
656     pe_state = (env->cr[0] & CR0_PE_MASK);
657     env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
658     /* ensure that ADDSEG is always set in real mode */
659     env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
660     /* update FPU flags */
661     env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
662         ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
663 }
664 
665 /* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
666    the PDPT */
667 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
668 {
669     env->cr[3] = new_cr3;
670     if (env->cr[0] & CR0_PG_MASK) {
671         qemu_log_mask(CPU_LOG_MMU,
672                         "CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
673         tlb_flush(env_cpu(env));
674     }
675 }
676 
677 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
678 {
679     uint32_t hflags;
680 
681 #if defined(DEBUG_MMU)
682     printf("CR4 update: %08x -> %08x\n", (uint32_t)env->cr[4], new_cr4);
683 #endif
684     if ((new_cr4 ^ env->cr[4]) &
685         (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK |
686          CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_LA57_MASK)) {
687         tlb_flush(env_cpu(env));
688     }
689 
690     /* Clear bits we're going to recompute.  */
691     hflags = env->hflags & ~(HF_OSFXSR_MASK | HF_SMAP_MASK);
692 
693     /* SSE handling */
694     if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
695         new_cr4 &= ~CR4_OSFXSR_MASK;
696     }
697     if (new_cr4 & CR4_OSFXSR_MASK) {
698         hflags |= HF_OSFXSR_MASK;
699     }
700 
701     if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) {
702         new_cr4 &= ~CR4_SMAP_MASK;
703     }
704     if (new_cr4 & CR4_SMAP_MASK) {
705         hflags |= HF_SMAP_MASK;
706     }
707 
708     if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) {
709         new_cr4 &= ~CR4_PKE_MASK;
710     }
711 
712     env->cr[4] = new_cr4;
713     env->hflags = hflags;
714 
715     cpu_sync_bndcs_hflags(env);
716 }
717 
718 #if !defined(CONFIG_USER_ONLY)
719 hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
720                                          MemTxAttrs *attrs)
721 {
722     X86CPU *cpu = X86_CPU(cs);
723     CPUX86State *env = &cpu->env;
724     target_ulong pde_addr, pte_addr;
725     uint64_t pte;
726     int32_t a20_mask;
727     uint32_t page_offset;
728     int page_size;
729 
730     *attrs = cpu_get_mem_attrs(env);
731 
732     a20_mask = x86_get_a20_mask(env);
733     if (!(env->cr[0] & CR0_PG_MASK)) {
734         pte = addr & a20_mask;
735         page_size = 4096;
736     } else if (env->cr[4] & CR4_PAE_MASK) {
737         target_ulong pdpe_addr;
738         uint64_t pde, pdpe;
739 
740 #ifdef TARGET_X86_64
741         if (env->hflags & HF_LMA_MASK) {
742             bool la57 = env->cr[4] & CR4_LA57_MASK;
743             uint64_t pml5e_addr, pml5e;
744             uint64_t pml4e_addr, pml4e;
745             int32_t sext;
746 
747             /* test virtual address sign extension */
748             sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47;
749             if (sext != 0 && sext != -1) {
750                 return -1;
751             }
752 
753             if (la57) {
754                 pml5e_addr = ((env->cr[3] & ~0xfff) +
755                         (((addr >> 48) & 0x1ff) << 3)) & a20_mask;
756                 pml5e = x86_ldq_phys(cs, pml5e_addr);
757                 if (!(pml5e & PG_PRESENT_MASK)) {
758                     return -1;
759                 }
760             } else {
761                 pml5e = env->cr[3];
762             }
763 
764             pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
765                     (((addr >> 39) & 0x1ff) << 3)) & a20_mask;
766             pml4e = x86_ldq_phys(cs, pml4e_addr);
767             if (!(pml4e & PG_PRESENT_MASK)) {
768                 return -1;
769             }
770             pdpe_addr = ((pml4e & PG_ADDRESS_MASK) +
771                          (((addr >> 30) & 0x1ff) << 3)) & a20_mask;
772             pdpe = x86_ldq_phys(cs, pdpe_addr);
773             if (!(pdpe & PG_PRESENT_MASK)) {
774                 return -1;
775             }
776             if (pdpe & PG_PSE_MASK) {
777                 page_size = 1024 * 1024 * 1024;
778                 pte = pdpe;
779                 goto out;
780             }
781 
782         } else
783 #endif
784         {
785             pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
786                 a20_mask;
787             pdpe = x86_ldq_phys(cs, pdpe_addr);
788             if (!(pdpe & PG_PRESENT_MASK))
789                 return -1;
790         }
791 
792         pde_addr = ((pdpe & PG_ADDRESS_MASK) +
793                     (((addr >> 21) & 0x1ff) << 3)) & a20_mask;
794         pde = x86_ldq_phys(cs, pde_addr);
795         if (!(pde & PG_PRESENT_MASK)) {
796             return -1;
797         }
798         if (pde & PG_PSE_MASK) {
799             /* 2 MB page */
800             page_size = 2048 * 1024;
801             pte = pde;
802         } else {
803             /* 4 KB page */
804             pte_addr = ((pde & PG_ADDRESS_MASK) +
805                         (((addr >> 12) & 0x1ff) << 3)) & a20_mask;
806             page_size = 4096;
807             pte = x86_ldq_phys(cs, pte_addr);
808         }
809         if (!(pte & PG_PRESENT_MASK)) {
810             return -1;
811         }
812     } else {
813         uint32_t pde;
814 
815         /* page directory entry */
816         pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask;
817         pde = x86_ldl_phys(cs, pde_addr);
818         if (!(pde & PG_PRESENT_MASK))
819             return -1;
820         if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
821             pte = pde | ((pde & 0x1fe000LL) << (32 - 13));
822             page_size = 4096 * 1024;
823         } else {
824             /* page directory entry */
825             pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask;
826             pte = x86_ldl_phys(cs, pte_addr);
827             if (!(pte & PG_PRESENT_MASK)) {
828                 return -1;
829             }
830             page_size = 4096;
831         }
832         pte = pte & a20_mask;
833     }
834 
835 #ifdef TARGET_X86_64
836 out:
837 #endif
838     pte &= PG_ADDRESS_MASK & ~(page_size - 1);
839     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
840     return pte | page_offset;
841 }
842 
843 typedef struct MCEInjectionParams {
844     Monitor *mon;
845     int bank;
846     uint64_t status;
847     uint64_t mcg_status;
848     uint64_t addr;
849     uint64_t misc;
850     int flags;
851 } MCEInjectionParams;
852 
853 static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data)
854 {
855     MCEInjectionParams *params = data.host_ptr;
856     X86CPU *cpu = X86_CPU(cs);
857     CPUX86State *cenv = &cpu->env;
858     uint64_t *banks = cenv->mce_banks + 4 * params->bank;
859 
860     cpu_synchronize_state(cs);
861 
862     /*
863      * If there is an MCE exception being processed, ignore this SRAO MCE
864      * unless unconditional injection was requested.
865      */
866     if (!(params->flags & MCE_INJECT_UNCOND_AO)
867         && !(params->status & MCI_STATUS_AR)
868         && (cenv->mcg_status & MCG_STATUS_MCIP)) {
869         return;
870     }
871 
872     if (params->status & MCI_STATUS_UC) {
873         /*
874          * if MSR_MCG_CTL is not all 1s, the uncorrected error
875          * reporting is disabled
876          */
877         if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
878             monitor_printf(params->mon,
879                            "CPU %d: Uncorrected error reporting disabled\n",
880                            cs->cpu_index);
881             return;
882         }
883 
884         /*
885          * if MSR_MCi_CTL is not all 1s, the uncorrected error
886          * reporting is disabled for the bank
887          */
888         if (banks[0] != ~(uint64_t)0) {
889             monitor_printf(params->mon,
890                            "CPU %d: Uncorrected error reporting disabled for"
891                            " bank %d\n",
892                            cs->cpu_index, params->bank);
893             return;
894         }
895 
896         if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
897             !(cenv->cr[4] & CR4_MCE_MASK)) {
898             monitor_printf(params->mon,
899                            "CPU %d: Previous MCE still in progress, raising"
900                            " triple fault\n",
901                            cs->cpu_index);
902             qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
903             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
904             return;
905         }
906         if (banks[1] & MCI_STATUS_VAL) {
907             params->status |= MCI_STATUS_OVER;
908         }
909         banks[2] = params->addr;
910         banks[3] = params->misc;
911         cenv->mcg_status = params->mcg_status;
912         banks[1] = params->status;
913         cpu_interrupt(cs, CPU_INTERRUPT_MCE);
914     } else if (!(banks[1] & MCI_STATUS_VAL)
915                || !(banks[1] & MCI_STATUS_UC)) {
916         if (banks[1] & MCI_STATUS_VAL) {
917             params->status |= MCI_STATUS_OVER;
918         }
919         banks[2] = params->addr;
920         banks[3] = params->misc;
921         banks[1] = params->status;
922     } else {
923         banks[1] |= MCI_STATUS_OVER;
924     }
925 }
926 
927 void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
928                         uint64_t status, uint64_t mcg_status, uint64_t addr,
929                         uint64_t misc, int flags)
930 {
931     CPUState *cs = CPU(cpu);
932     CPUX86State *cenv = &cpu->env;
933     MCEInjectionParams params = {
934         .mon = mon,
935         .bank = bank,
936         .status = status,
937         .mcg_status = mcg_status,
938         .addr = addr,
939         .misc = misc,
940         .flags = flags,
941     };
942     unsigned bank_num = cenv->mcg_cap & 0xff;
943 
944     if (!cenv->mcg_cap) {
945         monitor_printf(mon, "MCE injection not supported\n");
946         return;
947     }
948     if (bank >= bank_num) {
949         monitor_printf(mon, "Invalid MCE bank number\n");
950         return;
951     }
952     if (!(status & MCI_STATUS_VAL)) {
953         monitor_printf(mon, "Invalid MCE status code\n");
954         return;
955     }
956     if ((flags & MCE_INJECT_BROADCAST)
957         && !cpu_x86_support_mca_broadcast(cenv)) {
958         monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
959         return;
960     }
961 
962     run_on_cpu(cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
963     if (flags & MCE_INJECT_BROADCAST) {
964         CPUState *other_cs;
965 
966         params.bank = 1;
967         params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
968         params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
969         params.addr = 0;
970         params.misc = 0;
971         CPU_FOREACH(other_cs) {
972             if (other_cs == cs) {
973                 continue;
974             }
975             run_on_cpu(other_cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
976         }
977     }
978 }
979 
980 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
981 {
982     X86CPU *cpu = env_archcpu(env);
983     CPUState *cs = env_cpu(env);
984 
985     if (kvm_enabled() || whpx_enabled()) {
986         env->tpr_access_type = access;
987 
988         cpu_interrupt(cs, CPU_INTERRUPT_TPR);
989     } else if (tcg_enabled()) {
990         cpu_restore_state(cs, cs->mem_io_pc, false);
991 
992         apic_handle_tpr_access_report(cpu->apic_state, env->eip, access);
993     }
994 }
995 #endif /* !CONFIG_USER_ONLY */
996 
997 int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
998                             target_ulong *base, unsigned int *limit,
999                             unsigned int *flags)
1000 {
1001     CPUState *cs = env_cpu(env);
1002     SegmentCache *dt;
1003     target_ulong ptr;
1004     uint32_t e1, e2;
1005     int index;
1006 
1007     if (selector & 0x4)
1008         dt = &env->ldt;
1009     else
1010         dt = &env->gdt;
1011     index = selector & ~7;
1012     ptr = dt->base + index;
1013     if ((index + 7) > dt->limit
1014         || cpu_memory_rw_debug(cs, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
1015         || cpu_memory_rw_debug(cs, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
1016         return 0;
1017 
1018     *base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
1019     *limit = (e1 & 0xffff) | (e2 & 0x000f0000);
1020     if (e2 & DESC_G_MASK)
1021         *limit = (*limit << 12) | 0xfff;
1022     *flags = e2;
1023 
1024     return 1;
1025 }
1026 
1027 #if !defined(CONFIG_USER_ONLY)
1028 void do_cpu_init(X86CPU *cpu)
1029 {
1030     CPUState *cs = CPU(cpu);
1031     CPUX86State *env = &cpu->env;
1032     CPUX86State *save = g_new(CPUX86State, 1);
1033     int sipi = cs->interrupt_request & CPU_INTERRUPT_SIPI;
1034 
1035     *save = *env;
1036 
1037     cpu_reset(cs);
1038     cs->interrupt_request = sipi;
1039     memcpy(&env->start_init_save, &save->start_init_save,
1040            offsetof(CPUX86State, end_init_save) -
1041            offsetof(CPUX86State, start_init_save));
1042     g_free(save);
1043 
1044     if (kvm_enabled()) {
1045         kvm_arch_do_init_vcpu(cpu);
1046     }
1047     apic_init_reset(cpu->apic_state);
1048 }
1049 
1050 void do_cpu_sipi(X86CPU *cpu)
1051 {
1052     apic_sipi(cpu->apic_state);
1053 }
1054 #else
1055 void do_cpu_init(X86CPU *cpu)
1056 {
1057 }
1058 void do_cpu_sipi(X86CPU *cpu)
1059 {
1060 }
1061 #endif
1062 
1063 /* Frob eflags into and out of the CPU temporary format.  */
1064 
1065 void x86_cpu_exec_enter(CPUState *cs)
1066 {
1067     X86CPU *cpu = X86_CPU(cs);
1068     CPUX86State *env = &cpu->env;
1069 
1070     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1071     env->df = 1 - (2 * ((env->eflags >> 10) & 1));
1072     CC_OP = CC_OP_EFLAGS;
1073     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1074 }
1075 
1076 void x86_cpu_exec_exit(CPUState *cs)
1077 {
1078     X86CPU *cpu = X86_CPU(cs);
1079     CPUX86State *env = &cpu->env;
1080 
1081     env->eflags = cpu_compute_eflags(env);
1082 }
1083 
1084 #ifndef CONFIG_USER_ONLY
1085 uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr)
1086 {
1087     X86CPU *cpu = X86_CPU(cs);
1088     CPUX86State *env = &cpu->env;
1089     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1090     AddressSpace *as = cpu_addressspace(cs, attrs);
1091 
1092     return address_space_ldub(as, addr, attrs, NULL);
1093 }
1094 
1095 uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr)
1096 {
1097     X86CPU *cpu = X86_CPU(cs);
1098     CPUX86State *env = &cpu->env;
1099     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1100     AddressSpace *as = cpu_addressspace(cs, attrs);
1101 
1102     return address_space_lduw(as, addr, attrs, NULL);
1103 }
1104 
1105 uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr)
1106 {
1107     X86CPU *cpu = X86_CPU(cs);
1108     CPUX86State *env = &cpu->env;
1109     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1110     AddressSpace *as = cpu_addressspace(cs, attrs);
1111 
1112     return address_space_ldl(as, addr, attrs, NULL);
1113 }
1114 
1115 uint64_t x86_ldq_phys(CPUState *cs, hwaddr addr)
1116 {
1117     X86CPU *cpu = X86_CPU(cs);
1118     CPUX86State *env = &cpu->env;
1119     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1120     AddressSpace *as = cpu_addressspace(cs, attrs);
1121 
1122     return address_space_ldq(as, addr, attrs, NULL);
1123 }
1124 
1125 void x86_stb_phys(CPUState *cs, hwaddr addr, uint8_t val)
1126 {
1127     X86CPU *cpu = X86_CPU(cs);
1128     CPUX86State *env = &cpu->env;
1129     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1130     AddressSpace *as = cpu_addressspace(cs, attrs);
1131 
1132     address_space_stb(as, addr, val, attrs, NULL);
1133 }
1134 
1135 void x86_stl_phys_notdirty(CPUState *cs, hwaddr addr, uint32_t val)
1136 {
1137     X86CPU *cpu = X86_CPU(cs);
1138     CPUX86State *env = &cpu->env;
1139     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1140     AddressSpace *as = cpu_addressspace(cs, attrs);
1141 
1142     address_space_stl_notdirty(as, addr, val, attrs, NULL);
1143 }
1144 
1145 void x86_stw_phys(CPUState *cs, hwaddr addr, uint32_t val)
1146 {
1147     X86CPU *cpu = X86_CPU(cs);
1148     CPUX86State *env = &cpu->env;
1149     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1150     AddressSpace *as = cpu_addressspace(cs, attrs);
1151 
1152     address_space_stw(as, addr, val, attrs, NULL);
1153 }
1154 
1155 void x86_stl_phys(CPUState *cs, hwaddr addr, uint32_t val)
1156 {
1157     X86CPU *cpu = X86_CPU(cs);
1158     CPUX86State *env = &cpu->env;
1159     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1160     AddressSpace *as = cpu_addressspace(cs, attrs);
1161 
1162     address_space_stl(as, addr, val, attrs, NULL);
1163 }
1164 
1165 void x86_stq_phys(CPUState *cs, hwaddr addr, uint64_t val)
1166 {
1167     X86CPU *cpu = X86_CPU(cs);
1168     CPUX86State *env = &cpu->env;
1169     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1170     AddressSpace *as = cpu_addressspace(cs, attrs);
1171 
1172     address_space_stq(as, addr, val, attrs, NULL);
1173 }
1174 #endif
1175