xref: /openbmc/qemu/target/i386/helper.c (revision 7acafcfa)
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"
374                 " current_count = %u\n",
375                 s->divide_conf & APIC_DCR_MASK,
376                 divider_conf(s->divide_conf),
377                 s->initial_count, apic_get_current_count(s));
378 
379     qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n",
380                 s->spurious_vec,
381                 s->spurious_vec & APIC_SPURIO_ENABLED ? "enabled" : "disabled",
382                 s->spurious_vec & APIC_SPURIO_FOCUS ? "on" : "off",
383                 s->spurious_vec & APIC_VECTOR_MASK);
384 
385     dump_apic_icr(s, &cpu->env);
386 
387     qemu_printf("ESR\t 0x%08x\n", s->esr);
388 
389     dump_apic_interrupt("ISR", s->isr, s->tmr);
390     dump_apic_interrupt("IRR", s->irr, s->tmr);
391 
392     qemu_printf("\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x",
393                 s->arb_id, s->tpr, s->dest_mode, s->log_dest);
394     if (s->dest_mode == 0) {
395         qemu_printf("(cluster %u: id %u)",
396                     s->log_dest >> APIC_LOGDEST_XAPIC_SHIFT,
397                     s->log_dest & APIC_LOGDEST_XAPIC_ID);
398     }
399     qemu_printf(" PPR 0x%02x\n", apic_get_ppr(s));
400 }
401 #else
402 void x86_cpu_dump_local_apic_state(CPUState *cs, int flags)
403 {
404 }
405 #endif /* !CONFIG_USER_ONLY */
406 
407 #define DUMP_CODE_BYTES_TOTAL    50
408 #define DUMP_CODE_BYTES_BACKWARD 20
409 
410 void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
411 {
412     X86CPU *cpu = X86_CPU(cs);
413     CPUX86State *env = &cpu->env;
414     int eflags, i, nb;
415     char cc_op_name[32];
416     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
417 
418     eflags = cpu_compute_eflags(env);
419 #ifdef TARGET_X86_64
420     if (env->hflags & HF_CS64_MASK) {
421         qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
422                      "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
423                      "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
424                      "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
425                      "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
426                      env->regs[R_EAX],
427                      env->regs[R_EBX],
428                      env->regs[R_ECX],
429                      env->regs[R_EDX],
430                      env->regs[R_ESI],
431                      env->regs[R_EDI],
432                      env->regs[R_EBP],
433                      env->regs[R_ESP],
434                      env->regs[8],
435                      env->regs[9],
436                      env->regs[10],
437                      env->regs[11],
438                      env->regs[12],
439                      env->regs[13],
440                      env->regs[14],
441                      env->regs[15],
442                      env->eip, eflags,
443                      eflags & DF_MASK ? 'D' : '-',
444                      eflags & CC_O ? 'O' : '-',
445                      eflags & CC_S ? 'S' : '-',
446                      eflags & CC_Z ? 'Z' : '-',
447                      eflags & CC_A ? 'A' : '-',
448                      eflags & CC_P ? 'P' : '-',
449                      eflags & CC_C ? 'C' : '-',
450                      env->hflags & HF_CPL_MASK,
451                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
452                      (env->a20_mask >> 20) & 1,
453                      (env->hflags >> HF_SMM_SHIFT) & 1,
454                      cs->halted);
455     } else
456 #endif
457     {
458         qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
459                      "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
460                      "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
461                      (uint32_t)env->regs[R_EAX],
462                      (uint32_t)env->regs[R_EBX],
463                      (uint32_t)env->regs[R_ECX],
464                      (uint32_t)env->regs[R_EDX],
465                      (uint32_t)env->regs[R_ESI],
466                      (uint32_t)env->regs[R_EDI],
467                      (uint32_t)env->regs[R_EBP],
468                      (uint32_t)env->regs[R_ESP],
469                      (uint32_t)env->eip, eflags,
470                      eflags & DF_MASK ? 'D' : '-',
471                      eflags & CC_O ? 'O' : '-',
472                      eflags & CC_S ? 'S' : '-',
473                      eflags & CC_Z ? 'Z' : '-',
474                      eflags & CC_A ? 'A' : '-',
475                      eflags & CC_P ? 'P' : '-',
476                      eflags & CC_C ? 'C' : '-',
477                      env->hflags & HF_CPL_MASK,
478                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
479                      (env->a20_mask >> 20) & 1,
480                      (env->hflags >> HF_SMM_SHIFT) & 1,
481                      cs->halted);
482     }
483 
484     for(i = 0; i < 6; i++) {
485         cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]);
486     }
487     cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt);
488     cpu_x86_dump_seg_cache(env, f, "TR", &env->tr);
489 
490 #ifdef TARGET_X86_64
491     if (env->hflags & HF_LMA_MASK) {
492         qemu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
493                      env->gdt.base, env->gdt.limit);
494         qemu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
495                      env->idt.base, env->idt.limit);
496         qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
497                      (uint32_t)env->cr[0],
498                      env->cr[2],
499                      env->cr[3],
500                      (uint32_t)env->cr[4]);
501         for(i = 0; i < 4; i++)
502             qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
503         qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
504                      env->dr[6], env->dr[7]);
505     } else
506 #endif
507     {
508         qemu_fprintf(f, "GDT=     %08x %08x\n",
509                      (uint32_t)env->gdt.base, env->gdt.limit);
510         qemu_fprintf(f, "IDT=     %08x %08x\n",
511                      (uint32_t)env->idt.base, env->idt.limit);
512         qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
513                      (uint32_t)env->cr[0],
514                      (uint32_t)env->cr[2],
515                      (uint32_t)env->cr[3],
516                      (uint32_t)env->cr[4]);
517         for(i = 0; i < 4; i++) {
518             qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
519         }
520         qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
521                      env->dr[6], env->dr[7]);
522     }
523     if (flags & CPU_DUMP_CCOP) {
524         if ((unsigned)env->cc_op < CC_OP_NB)
525             snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
526         else
527             snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
528 #ifdef TARGET_X86_64
529         if (env->hflags & HF_CS64_MASK) {
530             qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
531                          env->cc_src, env->cc_dst,
532                          cc_op_name);
533         } else
534 #endif
535         {
536             qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
537                          (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
538                          cc_op_name);
539         }
540     }
541     qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
542     if (flags & CPU_DUMP_FPU) {
543         int fptag;
544         fptag = 0;
545         for(i = 0; i < 8; i++) {
546             fptag |= ((!env->fptags[i]) << i);
547         }
548         update_mxcsr_from_sse_status(env);
549         qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
550                      env->fpuc,
551                      (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
552                      env->fpstt,
553                      fptag,
554                      env->mxcsr);
555         for(i=0;i<8;i++) {
556             CPU_LDoubleU u;
557             u.d = env->fpregs[i].d;
558             qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
559                          i, u.l.lower, u.l.upper);
560             if ((i & 1) == 1)
561                 qemu_fprintf(f, "\n");
562             else
563                 qemu_fprintf(f, " ");
564         }
565         if (env->hflags & HF_CS64_MASK)
566             nb = 16;
567         else
568             nb = 8;
569         for(i=0;i<nb;i++) {
570             qemu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
571                          i,
572                          env->xmm_regs[i].ZMM_L(3),
573                          env->xmm_regs[i].ZMM_L(2),
574                          env->xmm_regs[i].ZMM_L(1),
575                          env->xmm_regs[i].ZMM_L(0));
576             if ((i & 1) == 1)
577                 qemu_fprintf(f, "\n");
578             else
579                 qemu_fprintf(f, " ");
580         }
581     }
582     if (flags & CPU_DUMP_CODE) {
583         target_ulong base = env->segs[R_CS].base + env->eip;
584         target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
585         uint8_t code;
586         char codestr[3];
587 
588         qemu_fprintf(f, "Code=");
589         for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
590             if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
591                 snprintf(codestr, sizeof(codestr), "%02x", code);
592             } else {
593                 snprintf(codestr, sizeof(codestr), "??");
594             }
595             qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
596                          i == offs ? "<" : "", codestr, i == offs ? ">" : "");
597         }
598         qemu_fprintf(f, "\n");
599     }
600 }
601 
602 /***********************************************************/
603 /* x86 mmu */
604 /* XXX: add PGE support */
605 
606 void x86_cpu_set_a20(X86CPU *cpu, int a20_state)
607 {
608     CPUX86State *env = &cpu->env;
609 
610     a20_state = (a20_state != 0);
611     if (a20_state != ((env->a20_mask >> 20) & 1)) {
612         CPUState *cs = CPU(cpu);
613 
614         qemu_log_mask(CPU_LOG_MMU, "A20 update: a20=%d\n", a20_state);
615         /* if the cpu is currently executing code, we must unlink it and
616            all the potentially executing TB */
617         cpu_interrupt(cs, CPU_INTERRUPT_EXITTB);
618 
619         /* when a20 is changed, all the MMU mappings are invalid, so
620            we must flush everything */
621         tlb_flush(cs);
622         env->a20_mask = ~(1 << 20) | (a20_state << 20);
623     }
624 }
625 
626 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
627 {
628     X86CPU *cpu = env_archcpu(env);
629     int pe_state;
630 
631     qemu_log_mask(CPU_LOG_MMU, "CR0 update: CR0=0x%08x\n", new_cr0);
632     if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
633         (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
634         tlb_flush(CPU(cpu));
635     }
636 
637 #ifdef TARGET_X86_64
638     if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
639         (env->efer & MSR_EFER_LME)) {
640         /* enter in long mode */
641         /* XXX: generate an exception */
642         if (!(env->cr[4] & CR4_PAE_MASK))
643             return;
644         env->efer |= MSR_EFER_LMA;
645         env->hflags |= HF_LMA_MASK;
646     } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
647                (env->efer & MSR_EFER_LMA)) {
648         /* exit long mode */
649         env->efer &= ~MSR_EFER_LMA;
650         env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
651         env->eip &= 0xffffffff;
652     }
653 #endif
654     env->cr[0] = new_cr0 | CR0_ET_MASK;
655 
656     /* update PE flag in hidden flags */
657     pe_state = (env->cr[0] & CR0_PE_MASK);
658     env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
659     /* ensure that ADDSEG is always set in real mode */
660     env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
661     /* update FPU flags */
662     env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
663         ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
664 }
665 
666 /* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
667    the PDPT */
668 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
669 {
670     env->cr[3] = new_cr3;
671     if (env->cr[0] & CR0_PG_MASK) {
672         qemu_log_mask(CPU_LOG_MMU,
673                         "CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
674         tlb_flush(env_cpu(env));
675     }
676 }
677 
678 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
679 {
680     uint32_t hflags;
681 
682 #if defined(DEBUG_MMU)
683     printf("CR4 update: %08x -> %08x\n", (uint32_t)env->cr[4], new_cr4);
684 #endif
685     if ((new_cr4 ^ env->cr[4]) &
686         (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK |
687          CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_LA57_MASK)) {
688         tlb_flush(env_cpu(env));
689     }
690 
691     /* Clear bits we're going to recompute.  */
692     hflags = env->hflags & ~(HF_OSFXSR_MASK | HF_SMAP_MASK);
693 
694     /* SSE handling */
695     if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
696         new_cr4 &= ~CR4_OSFXSR_MASK;
697     }
698     if (new_cr4 & CR4_OSFXSR_MASK) {
699         hflags |= HF_OSFXSR_MASK;
700     }
701 
702     if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) {
703         new_cr4 &= ~CR4_SMAP_MASK;
704     }
705     if (new_cr4 & CR4_SMAP_MASK) {
706         hflags |= HF_SMAP_MASK;
707     }
708 
709     if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) {
710         new_cr4 &= ~CR4_PKE_MASK;
711     }
712 
713     env->cr[4] = new_cr4;
714     env->hflags = hflags;
715 
716     cpu_sync_bndcs_hflags(env);
717 }
718 
719 #if !defined(CONFIG_USER_ONLY)
720 hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
721                                          MemTxAttrs *attrs)
722 {
723     X86CPU *cpu = X86_CPU(cs);
724     CPUX86State *env = &cpu->env;
725     target_ulong pde_addr, pte_addr;
726     uint64_t pte;
727     int32_t a20_mask;
728     uint32_t page_offset;
729     int page_size;
730 
731     *attrs = cpu_get_mem_attrs(env);
732 
733     a20_mask = x86_get_a20_mask(env);
734     if (!(env->cr[0] & CR0_PG_MASK)) {
735         pte = addr & a20_mask;
736         page_size = 4096;
737     } else if (env->cr[4] & CR4_PAE_MASK) {
738         target_ulong pdpe_addr;
739         uint64_t pde, pdpe;
740 
741 #ifdef TARGET_X86_64
742         if (env->hflags & HF_LMA_MASK) {
743             bool la57 = env->cr[4] & CR4_LA57_MASK;
744             uint64_t pml5e_addr, pml5e;
745             uint64_t pml4e_addr, pml4e;
746             int32_t sext;
747 
748             /* test virtual address sign extension */
749             sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47;
750             if (sext != 0 && sext != -1) {
751                 return -1;
752             }
753 
754             if (la57) {
755                 pml5e_addr = ((env->cr[3] & ~0xfff) +
756                         (((addr >> 48) & 0x1ff) << 3)) & a20_mask;
757                 pml5e = x86_ldq_phys(cs, pml5e_addr);
758                 if (!(pml5e & PG_PRESENT_MASK)) {
759                     return -1;
760                 }
761             } else {
762                 pml5e = env->cr[3];
763             }
764 
765             pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
766                     (((addr >> 39) & 0x1ff) << 3)) & a20_mask;
767             pml4e = x86_ldq_phys(cs, pml4e_addr);
768             if (!(pml4e & PG_PRESENT_MASK)) {
769                 return -1;
770             }
771             pdpe_addr = ((pml4e & PG_ADDRESS_MASK) +
772                          (((addr >> 30) & 0x1ff) << 3)) & a20_mask;
773             pdpe = x86_ldq_phys(cs, pdpe_addr);
774             if (!(pdpe & PG_PRESENT_MASK)) {
775                 return -1;
776             }
777             if (pdpe & PG_PSE_MASK) {
778                 page_size = 1024 * 1024 * 1024;
779                 pte = pdpe;
780                 goto out;
781             }
782 
783         } else
784 #endif
785         {
786             pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
787                 a20_mask;
788             pdpe = x86_ldq_phys(cs, pdpe_addr);
789             if (!(pdpe & PG_PRESENT_MASK))
790                 return -1;
791         }
792 
793         pde_addr = ((pdpe & PG_ADDRESS_MASK) +
794                     (((addr >> 21) & 0x1ff) << 3)) & a20_mask;
795         pde = x86_ldq_phys(cs, pde_addr);
796         if (!(pde & PG_PRESENT_MASK)) {
797             return -1;
798         }
799         if (pde & PG_PSE_MASK) {
800             /* 2 MB page */
801             page_size = 2048 * 1024;
802             pte = pde;
803         } else {
804             /* 4 KB page */
805             pte_addr = ((pde & PG_ADDRESS_MASK) +
806                         (((addr >> 12) & 0x1ff) << 3)) & a20_mask;
807             page_size = 4096;
808             pte = x86_ldq_phys(cs, pte_addr);
809         }
810         if (!(pte & PG_PRESENT_MASK)) {
811             return -1;
812         }
813     } else {
814         uint32_t pde;
815 
816         /* page directory entry */
817         pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask;
818         pde = x86_ldl_phys(cs, pde_addr);
819         if (!(pde & PG_PRESENT_MASK))
820             return -1;
821         if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
822             pte = pde | ((pde & 0x1fe000LL) << (32 - 13));
823             page_size = 4096 * 1024;
824         } else {
825             /* page directory entry */
826             pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask;
827             pte = x86_ldl_phys(cs, pte_addr);
828             if (!(pte & PG_PRESENT_MASK)) {
829                 return -1;
830             }
831             page_size = 4096;
832         }
833         pte = pte & a20_mask;
834     }
835 
836 #ifdef TARGET_X86_64
837 out:
838 #endif
839     pte &= PG_ADDRESS_MASK & ~(page_size - 1);
840     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
841     return pte | page_offset;
842 }
843 
844 typedef struct MCEInjectionParams {
845     Monitor *mon;
846     int bank;
847     uint64_t status;
848     uint64_t mcg_status;
849     uint64_t addr;
850     uint64_t misc;
851     int flags;
852 } MCEInjectionParams;
853 
854 static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data)
855 {
856     MCEInjectionParams *params = data.host_ptr;
857     X86CPU *cpu = X86_CPU(cs);
858     CPUX86State *cenv = &cpu->env;
859     uint64_t *banks = cenv->mce_banks + 4 * params->bank;
860 
861     cpu_synchronize_state(cs);
862 
863     /*
864      * If there is an MCE exception being processed, ignore this SRAO MCE
865      * unless unconditional injection was requested.
866      */
867     if (!(params->flags & MCE_INJECT_UNCOND_AO)
868         && !(params->status & MCI_STATUS_AR)
869         && (cenv->mcg_status & MCG_STATUS_MCIP)) {
870         return;
871     }
872 
873     if (params->status & MCI_STATUS_UC) {
874         /*
875          * if MSR_MCG_CTL is not all 1s, the uncorrected error
876          * reporting is disabled
877          */
878         if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
879             monitor_printf(params->mon,
880                            "CPU %d: Uncorrected error reporting disabled\n",
881                            cs->cpu_index);
882             return;
883         }
884 
885         /*
886          * if MSR_MCi_CTL is not all 1s, the uncorrected error
887          * reporting is disabled for the bank
888          */
889         if (banks[0] != ~(uint64_t)0) {
890             monitor_printf(params->mon,
891                            "CPU %d: Uncorrected error reporting disabled for"
892                            " bank %d\n",
893                            cs->cpu_index, params->bank);
894             return;
895         }
896 
897         if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
898             !(cenv->cr[4] & CR4_MCE_MASK)) {
899             monitor_printf(params->mon,
900                            "CPU %d: Previous MCE still in progress, raising"
901                            " triple fault\n",
902                            cs->cpu_index);
903             qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
904             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
905             return;
906         }
907         if (banks[1] & MCI_STATUS_VAL) {
908             params->status |= MCI_STATUS_OVER;
909         }
910         banks[2] = params->addr;
911         banks[3] = params->misc;
912         cenv->mcg_status = params->mcg_status;
913         banks[1] = params->status;
914         cpu_interrupt(cs, CPU_INTERRUPT_MCE);
915     } else if (!(banks[1] & MCI_STATUS_VAL)
916                || !(banks[1] & MCI_STATUS_UC)) {
917         if (banks[1] & MCI_STATUS_VAL) {
918             params->status |= MCI_STATUS_OVER;
919         }
920         banks[2] = params->addr;
921         banks[3] = params->misc;
922         banks[1] = params->status;
923     } else {
924         banks[1] |= MCI_STATUS_OVER;
925     }
926 }
927 
928 void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
929                         uint64_t status, uint64_t mcg_status, uint64_t addr,
930                         uint64_t misc, int flags)
931 {
932     CPUState *cs = CPU(cpu);
933     CPUX86State *cenv = &cpu->env;
934     MCEInjectionParams params = {
935         .mon = mon,
936         .bank = bank,
937         .status = status,
938         .mcg_status = mcg_status,
939         .addr = addr,
940         .misc = misc,
941         .flags = flags,
942     };
943     unsigned bank_num = cenv->mcg_cap & 0xff;
944 
945     if (!cenv->mcg_cap) {
946         monitor_printf(mon, "MCE injection not supported\n");
947         return;
948     }
949     if (bank >= bank_num) {
950         monitor_printf(mon, "Invalid MCE bank number\n");
951         return;
952     }
953     if (!(status & MCI_STATUS_VAL)) {
954         monitor_printf(mon, "Invalid MCE status code\n");
955         return;
956     }
957     if ((flags & MCE_INJECT_BROADCAST)
958         && !cpu_x86_support_mca_broadcast(cenv)) {
959         monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
960         return;
961     }
962 
963     run_on_cpu(cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
964     if (flags & MCE_INJECT_BROADCAST) {
965         CPUState *other_cs;
966 
967         params.bank = 1;
968         params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
969         params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
970         params.addr = 0;
971         params.misc = 0;
972         CPU_FOREACH(other_cs) {
973             if (other_cs == cs) {
974                 continue;
975             }
976             run_on_cpu(other_cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
977         }
978     }
979 }
980 
981 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access)
982 {
983     X86CPU *cpu = env_archcpu(env);
984     CPUState *cs = env_cpu(env);
985 
986     if (kvm_enabled() || whpx_enabled()) {
987         env->tpr_access_type = access;
988 
989         cpu_interrupt(cs, CPU_INTERRUPT_TPR);
990     } else if (tcg_enabled()) {
991         cpu_restore_state(cs, cs->mem_io_pc, false);
992 
993         apic_handle_tpr_access_report(cpu->apic_state, env->eip, access);
994     }
995 }
996 #endif /* !CONFIG_USER_ONLY */
997 
998 int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
999                             target_ulong *base, unsigned int *limit,
1000                             unsigned int *flags)
1001 {
1002     CPUState *cs = env_cpu(env);
1003     SegmentCache *dt;
1004     target_ulong ptr;
1005     uint32_t e1, e2;
1006     int index;
1007 
1008     if (selector & 0x4)
1009         dt = &env->ldt;
1010     else
1011         dt = &env->gdt;
1012     index = selector & ~7;
1013     ptr = dt->base + index;
1014     if ((index + 7) > dt->limit
1015         || cpu_memory_rw_debug(cs, ptr, (uint8_t *)&e1, sizeof(e1), 0) != 0
1016         || cpu_memory_rw_debug(cs, ptr+4, (uint8_t *)&e2, sizeof(e2), 0) != 0)
1017         return 0;
1018 
1019     *base = ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
1020     *limit = (e1 & 0xffff) | (e2 & 0x000f0000);
1021     if (e2 & DESC_G_MASK)
1022         *limit = (*limit << 12) | 0xfff;
1023     *flags = e2;
1024 
1025     return 1;
1026 }
1027 
1028 #if !defined(CONFIG_USER_ONLY)
1029 void do_cpu_init(X86CPU *cpu)
1030 {
1031     CPUState *cs = CPU(cpu);
1032     CPUX86State *env = &cpu->env;
1033     CPUX86State *save = g_new(CPUX86State, 1);
1034     int sipi = cs->interrupt_request & CPU_INTERRUPT_SIPI;
1035 
1036     *save = *env;
1037 
1038     cpu_reset(cs);
1039     cs->interrupt_request = sipi;
1040     memcpy(&env->start_init_save, &save->start_init_save,
1041            offsetof(CPUX86State, end_init_save) -
1042            offsetof(CPUX86State, start_init_save));
1043     g_free(save);
1044 
1045     if (kvm_enabled()) {
1046         kvm_arch_do_init_vcpu(cpu);
1047     }
1048     apic_init_reset(cpu->apic_state);
1049 }
1050 
1051 void do_cpu_sipi(X86CPU *cpu)
1052 {
1053     apic_sipi(cpu->apic_state);
1054 }
1055 #else
1056 void do_cpu_init(X86CPU *cpu)
1057 {
1058 }
1059 void do_cpu_sipi(X86CPU *cpu)
1060 {
1061 }
1062 #endif
1063 
1064 /* Frob eflags into and out of the CPU temporary format.  */
1065 
1066 void x86_cpu_exec_enter(CPUState *cs)
1067 {
1068     X86CPU *cpu = X86_CPU(cs);
1069     CPUX86State *env = &cpu->env;
1070 
1071     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1072     env->df = 1 - (2 * ((env->eflags >> 10) & 1));
1073     CC_OP = CC_OP_EFLAGS;
1074     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1075 }
1076 
1077 void x86_cpu_exec_exit(CPUState *cs)
1078 {
1079     X86CPU *cpu = X86_CPU(cs);
1080     CPUX86State *env = &cpu->env;
1081 
1082     env->eflags = cpu_compute_eflags(env);
1083 }
1084 
1085 #ifndef CONFIG_USER_ONLY
1086 uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr)
1087 {
1088     X86CPU *cpu = X86_CPU(cs);
1089     CPUX86State *env = &cpu->env;
1090     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1091     AddressSpace *as = cpu_addressspace(cs, attrs);
1092 
1093     return address_space_ldub(as, addr, attrs, NULL);
1094 }
1095 
1096 uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr)
1097 {
1098     X86CPU *cpu = X86_CPU(cs);
1099     CPUX86State *env = &cpu->env;
1100     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1101     AddressSpace *as = cpu_addressspace(cs, attrs);
1102 
1103     return address_space_lduw(as, addr, attrs, NULL);
1104 }
1105 
1106 uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr)
1107 {
1108     X86CPU *cpu = X86_CPU(cs);
1109     CPUX86State *env = &cpu->env;
1110     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1111     AddressSpace *as = cpu_addressspace(cs, attrs);
1112 
1113     return address_space_ldl(as, addr, attrs, NULL);
1114 }
1115 
1116 uint64_t x86_ldq_phys(CPUState *cs, hwaddr addr)
1117 {
1118     X86CPU *cpu = X86_CPU(cs);
1119     CPUX86State *env = &cpu->env;
1120     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1121     AddressSpace *as = cpu_addressspace(cs, attrs);
1122 
1123     return address_space_ldq(as, addr, attrs, NULL);
1124 }
1125 
1126 void x86_stb_phys(CPUState *cs, hwaddr addr, uint8_t val)
1127 {
1128     X86CPU *cpu = X86_CPU(cs);
1129     CPUX86State *env = &cpu->env;
1130     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1131     AddressSpace *as = cpu_addressspace(cs, attrs);
1132 
1133     address_space_stb(as, addr, val, attrs, NULL);
1134 }
1135 
1136 void x86_stl_phys_notdirty(CPUState *cs, hwaddr addr, uint32_t val)
1137 {
1138     X86CPU *cpu = X86_CPU(cs);
1139     CPUX86State *env = &cpu->env;
1140     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1141     AddressSpace *as = cpu_addressspace(cs, attrs);
1142 
1143     address_space_stl_notdirty(as, addr, val, attrs, NULL);
1144 }
1145 
1146 void x86_stw_phys(CPUState *cs, hwaddr addr, uint32_t val)
1147 {
1148     X86CPU *cpu = X86_CPU(cs);
1149     CPUX86State *env = &cpu->env;
1150     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1151     AddressSpace *as = cpu_addressspace(cs, attrs);
1152 
1153     address_space_stw(as, addr, val, attrs, NULL);
1154 }
1155 
1156 void x86_stl_phys(CPUState *cs, hwaddr addr, uint32_t val)
1157 {
1158     X86CPU *cpu = X86_CPU(cs);
1159     CPUX86State *env = &cpu->env;
1160     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1161     AddressSpace *as = cpu_addressspace(cs, attrs);
1162 
1163     address_space_stl(as, addr, val, attrs, NULL);
1164 }
1165 
1166 void x86_stq_phys(CPUState *cs, hwaddr addr, uint64_t val)
1167 {
1168     X86CPU *cpu = X86_CPU(cs);
1169     CPUX86State *env = &cpu->env;
1170     MemTxAttrs attrs = cpu_get_mem_attrs(env);
1171     AddressSpace *as = cpu_addressspace(cs, attrs);
1172 
1173     address_space_stq(as, addr, val, attrs, NULL);
1174 }
1175 #endif
1176