xref: /qemu/target/i386/cpu-dump.c (revision 61848717d639446b58b069e480739a757d74813d)
10c36af8cSClaudio Fontana /*
20c36af8cSClaudio Fontana  *  i386 CPU dump to FILE
30c36af8cSClaudio Fontana  *
40c36af8cSClaudio Fontana  *  Copyright (c) 2003 Fabrice Bellard
50c36af8cSClaudio Fontana  *
60c36af8cSClaudio Fontana  * This library is free software; you can redistribute it and/or
70c36af8cSClaudio Fontana  * modify it under the terms of the GNU Lesser General Public
80c36af8cSClaudio Fontana  * License as published by the Free Software Foundation; either
90c36af8cSClaudio Fontana  * version 2 of the License, or (at your option) any later version.
100c36af8cSClaudio Fontana  *
110c36af8cSClaudio Fontana  * This library is distributed in the hope that it will be useful,
120c36af8cSClaudio Fontana  * but WITHOUT ANY WARRANTY; without even the implied warranty of
130c36af8cSClaudio Fontana  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
140c36af8cSClaudio Fontana  * Lesser General Public License for more details.
150c36af8cSClaudio Fontana  *
160c36af8cSClaudio Fontana  * You should have received a copy of the GNU Lesser General Public
170c36af8cSClaudio Fontana  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
180c36af8cSClaudio Fontana  */
190c36af8cSClaudio Fontana 
200c36af8cSClaudio Fontana #include "qemu/osdep.h"
210c36af8cSClaudio Fontana #include "cpu.h"
220c36af8cSClaudio Fontana #include "qemu/qemu-print.h"
230c36af8cSClaudio Fontana #ifndef CONFIG_USER_ONLY
240c36af8cSClaudio Fontana #include "hw/i386/apic_internal.h"
250c36af8cSClaudio Fontana #endif
260c36af8cSClaudio Fontana 
270c36af8cSClaudio Fontana /***********************************************************/
280c36af8cSClaudio Fontana /* x86 debug */
290c36af8cSClaudio Fontana 
300c36af8cSClaudio Fontana static const char *cc_op_str[CC_OP_NB] = {
310c36af8cSClaudio Fontana     "DYNAMIC",
320c36af8cSClaudio Fontana     "EFLAGS",
330c36af8cSClaudio Fontana 
340c36af8cSClaudio Fontana     "MULB",
350c36af8cSClaudio Fontana     "MULW",
360c36af8cSClaudio Fontana     "MULL",
370c36af8cSClaudio Fontana     "MULQ",
380c36af8cSClaudio Fontana 
390c36af8cSClaudio Fontana     "ADDB",
400c36af8cSClaudio Fontana     "ADDW",
410c36af8cSClaudio Fontana     "ADDL",
420c36af8cSClaudio Fontana     "ADDQ",
430c36af8cSClaudio Fontana 
440c36af8cSClaudio Fontana     "ADCB",
450c36af8cSClaudio Fontana     "ADCW",
460c36af8cSClaudio Fontana     "ADCL",
470c36af8cSClaudio Fontana     "ADCQ",
480c36af8cSClaudio Fontana 
490c36af8cSClaudio Fontana     "SUBB",
500c36af8cSClaudio Fontana     "SUBW",
510c36af8cSClaudio Fontana     "SUBL",
520c36af8cSClaudio Fontana     "SUBQ",
530c36af8cSClaudio Fontana 
540c36af8cSClaudio Fontana     "SBBB",
550c36af8cSClaudio Fontana     "SBBW",
560c36af8cSClaudio Fontana     "SBBL",
570c36af8cSClaudio Fontana     "SBBQ",
580c36af8cSClaudio Fontana 
590c36af8cSClaudio Fontana     "LOGICB",
600c36af8cSClaudio Fontana     "LOGICW",
610c36af8cSClaudio Fontana     "LOGICL",
620c36af8cSClaudio Fontana     "LOGICQ",
630c36af8cSClaudio Fontana 
640c36af8cSClaudio Fontana     "INCB",
650c36af8cSClaudio Fontana     "INCW",
660c36af8cSClaudio Fontana     "INCL",
670c36af8cSClaudio Fontana     "INCQ",
680c36af8cSClaudio Fontana 
690c36af8cSClaudio Fontana     "DECB",
700c36af8cSClaudio Fontana     "DECW",
710c36af8cSClaudio Fontana     "DECL",
720c36af8cSClaudio Fontana     "DECQ",
730c36af8cSClaudio Fontana 
740c36af8cSClaudio Fontana     "SHLB",
750c36af8cSClaudio Fontana     "SHLW",
760c36af8cSClaudio Fontana     "SHLL",
770c36af8cSClaudio Fontana     "SHLQ",
780c36af8cSClaudio Fontana 
790c36af8cSClaudio Fontana     "SARB",
800c36af8cSClaudio Fontana     "SARW",
810c36af8cSClaudio Fontana     "SARL",
820c36af8cSClaudio Fontana     "SARQ",
830c36af8cSClaudio Fontana 
840c36af8cSClaudio Fontana     "BMILGB",
850c36af8cSClaudio Fontana     "BMILGW",
860c36af8cSClaudio Fontana     "BMILGL",
870c36af8cSClaudio Fontana     "BMILGQ",
880c36af8cSClaudio Fontana 
890c36af8cSClaudio Fontana     "ADCX",
900c36af8cSClaudio Fontana     "ADOX",
910c36af8cSClaudio Fontana     "ADCOX",
920c36af8cSClaudio Fontana 
930c36af8cSClaudio Fontana     "CLR",
940c36af8cSClaudio Fontana };
950c36af8cSClaudio Fontana 
960c36af8cSClaudio Fontana static void
970c36af8cSClaudio Fontana cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f,
980c36af8cSClaudio Fontana                        const char *name, struct SegmentCache *sc)
990c36af8cSClaudio Fontana {
1000c36af8cSClaudio Fontana #ifdef TARGET_X86_64
1010c36af8cSClaudio Fontana     if (env->hflags & HF_CS64_MASK) {
1020c36af8cSClaudio Fontana         qemu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
1030c36af8cSClaudio Fontana                      sc->selector, sc->base, sc->limit,
1040c36af8cSClaudio Fontana                      sc->flags & 0x00ffff00);
1050c36af8cSClaudio Fontana     } else
1060c36af8cSClaudio Fontana #endif
1070c36af8cSClaudio Fontana     {
1080c36af8cSClaudio Fontana         qemu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
1090c36af8cSClaudio Fontana                      (uint32_t)sc->base, sc->limit,
1100c36af8cSClaudio Fontana                      sc->flags & 0x00ffff00);
1110c36af8cSClaudio Fontana     }
1120c36af8cSClaudio Fontana 
1130c36af8cSClaudio Fontana     if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
1140c36af8cSClaudio Fontana         goto done;
1150c36af8cSClaudio Fontana 
1160c36af8cSClaudio Fontana     qemu_fprintf(f, " DPL=%d ",
1170c36af8cSClaudio Fontana                  (sc->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT);
1180c36af8cSClaudio Fontana     if (sc->flags & DESC_S_MASK) {
1190c36af8cSClaudio Fontana         if (sc->flags & DESC_CS_MASK) {
1200c36af8cSClaudio Fontana             qemu_fprintf(f, (sc->flags & DESC_L_MASK) ? "CS64" :
1210c36af8cSClaudio Fontana                          ((sc->flags & DESC_B_MASK) ? "CS32" : "CS16"));
1220c36af8cSClaudio Fontana             qemu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
1230c36af8cSClaudio Fontana                          (sc->flags & DESC_R_MASK) ? 'R' : '-');
1240c36af8cSClaudio Fontana         } else {
1250c36af8cSClaudio Fontana             qemu_fprintf(f, (sc->flags & DESC_B_MASK
1260c36af8cSClaudio Fontana                              || env->hflags & HF_LMA_MASK)
1270c36af8cSClaudio Fontana                          ? "DS  " : "DS16");
1280c36af8cSClaudio Fontana             qemu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
1290c36af8cSClaudio Fontana                          (sc->flags & DESC_W_MASK) ? 'W' : '-');
1300c36af8cSClaudio Fontana         }
1310c36af8cSClaudio Fontana         qemu_fprintf(f, "%c]", (sc->flags & DESC_A_MASK) ? 'A' : '-');
1320c36af8cSClaudio Fontana     } else {
1330c36af8cSClaudio Fontana         static const char *sys_type_name[2][16] = {
1340c36af8cSClaudio Fontana             { /* 32 bit mode */
1350c36af8cSClaudio Fontana                 "Reserved", "TSS16-avl", "LDT", "TSS16-busy",
1360c36af8cSClaudio Fontana                 "CallGate16", "TaskGate", "IntGate16", "TrapGate16",
1370c36af8cSClaudio Fontana                 "Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
1380c36af8cSClaudio Fontana                 "CallGate32", "Reserved", "IntGate32", "TrapGate32"
1390c36af8cSClaudio Fontana             },
1400c36af8cSClaudio Fontana             { /* 64 bit mode */
1410c36af8cSClaudio Fontana                 "<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
1420c36af8cSClaudio Fontana                 "Reserved", "Reserved", "Reserved", "Reserved",
1430c36af8cSClaudio Fontana                 "TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
1440c36af8cSClaudio Fontana                 "Reserved", "IntGate64", "TrapGate64"
1450c36af8cSClaudio Fontana             }
1460c36af8cSClaudio Fontana         };
1470c36af8cSClaudio Fontana         qemu_fprintf(f, "%s",
1480c36af8cSClaudio Fontana                      sys_type_name[(env->hflags & HF_LMA_MASK) ? 1 : 0]
1490c36af8cSClaudio Fontana                      [(sc->flags & DESC_TYPE_MASK) >> DESC_TYPE_SHIFT]);
1500c36af8cSClaudio Fontana     }
1510c36af8cSClaudio Fontana done:
1520c36af8cSClaudio Fontana     qemu_fprintf(f, "\n");
1530c36af8cSClaudio Fontana }
1540c36af8cSClaudio Fontana 
1550c36af8cSClaudio Fontana #ifndef CONFIG_USER_ONLY
1560c36af8cSClaudio Fontana 
1570c36af8cSClaudio Fontana /* ARRAY_SIZE check is not required because
1580c36af8cSClaudio Fontana  * DeliveryMode(dm) has a size of 3 bit.
1590c36af8cSClaudio Fontana  */
1600c36af8cSClaudio Fontana static inline const char *dm2str(uint32_t dm)
1610c36af8cSClaudio Fontana {
1620c36af8cSClaudio Fontana     static const char *str[] = {
1630c36af8cSClaudio Fontana         "Fixed",
1640c36af8cSClaudio Fontana         "...",
1650c36af8cSClaudio Fontana         "SMI",
1660c36af8cSClaudio Fontana         "...",
1670c36af8cSClaudio Fontana         "NMI",
1680c36af8cSClaudio Fontana         "INIT",
1690c36af8cSClaudio Fontana         "...",
1700c36af8cSClaudio Fontana         "ExtINT"
1710c36af8cSClaudio Fontana     };
1720c36af8cSClaudio Fontana     return str[dm];
1730c36af8cSClaudio Fontana }
1740c36af8cSClaudio Fontana 
1750c36af8cSClaudio Fontana static void dump_apic_lvt(const char *name, uint32_t lvt, bool is_timer)
1760c36af8cSClaudio Fontana {
1770c36af8cSClaudio Fontana     uint32_t dm = (lvt & APIC_LVT_DELIV_MOD) >> APIC_LVT_DELIV_MOD_SHIFT;
1780c36af8cSClaudio Fontana     qemu_printf("%s\t 0x%08x %s %-5s %-6s %-7s %-12s %-6s",
1790c36af8cSClaudio Fontana                 name, lvt,
1800c36af8cSClaudio Fontana                 lvt & APIC_LVT_INT_POLARITY ? "active-lo" : "active-hi",
1810c36af8cSClaudio Fontana                 lvt & APIC_LVT_LEVEL_TRIGGER ? "level" : "edge",
1820c36af8cSClaudio Fontana                 lvt & APIC_LVT_MASKED ? "masked" : "",
1830c36af8cSClaudio Fontana                 lvt & APIC_LVT_DELIV_STS ? "pending" : "",
1840c36af8cSClaudio Fontana                 !is_timer ?
1850c36af8cSClaudio Fontana                     "" : lvt & APIC_LVT_TIMER_PERIODIC ?
1860c36af8cSClaudio Fontana                             "periodic" : lvt & APIC_LVT_TIMER_TSCDEADLINE ?
1870c36af8cSClaudio Fontana                                             "tsc-deadline" : "one-shot",
1880c36af8cSClaudio Fontana                 dm2str(dm));
1890c36af8cSClaudio Fontana     if (dm != APIC_DM_NMI) {
1900c36af8cSClaudio Fontana         qemu_printf(" (vec %u)\n", lvt & APIC_VECTOR_MASK);
1910c36af8cSClaudio Fontana     } else {
1920c36af8cSClaudio Fontana         qemu_printf("\n");
1930c36af8cSClaudio Fontana     }
1940c36af8cSClaudio Fontana }
1950c36af8cSClaudio Fontana 
1960c36af8cSClaudio Fontana /* ARRAY_SIZE check is not required because
1970c36af8cSClaudio Fontana  * destination shorthand has a size of 2 bit.
1980c36af8cSClaudio Fontana  */
1990c36af8cSClaudio Fontana static inline const char *shorthand2str(uint32_t shorthand)
2000c36af8cSClaudio Fontana {
2010c36af8cSClaudio Fontana     const char *str[] = {
2020c36af8cSClaudio Fontana         "no-shorthand", "self", "all-self", "all"
2030c36af8cSClaudio Fontana     };
2040c36af8cSClaudio Fontana     return str[shorthand];
2050c36af8cSClaudio Fontana }
2060c36af8cSClaudio Fontana 
2070c36af8cSClaudio Fontana static inline uint8_t divider_conf(uint32_t divide_conf)
2080c36af8cSClaudio Fontana {
2090c36af8cSClaudio Fontana     uint8_t divide_val = ((divide_conf & 0x8) >> 1) | (divide_conf & 0x3);
2100c36af8cSClaudio Fontana 
2110c36af8cSClaudio Fontana     return divide_val == 7 ? 1 : 2 << divide_val;
2120c36af8cSClaudio Fontana }
2130c36af8cSClaudio Fontana 
2140c36af8cSClaudio Fontana static inline void mask2str(char *str, uint32_t val, uint8_t size)
2150c36af8cSClaudio Fontana {
2160c36af8cSClaudio Fontana     while (size--) {
2170c36af8cSClaudio Fontana         *str++ = (val >> size) & 1 ? '1' : '0';
2180c36af8cSClaudio Fontana     }
2190c36af8cSClaudio Fontana     *str = 0;
2200c36af8cSClaudio Fontana }
2210c36af8cSClaudio Fontana 
2220c36af8cSClaudio Fontana #define MAX_LOGICAL_APIC_ID_MASK_SIZE 16
2230c36af8cSClaudio Fontana 
2240c36af8cSClaudio Fontana static void dump_apic_icr(APICCommonState *s, CPUX86State *env)
2250c36af8cSClaudio Fontana {
2260c36af8cSClaudio Fontana     uint32_t icr = s->icr[0], icr2 = s->icr[1];
2270c36af8cSClaudio Fontana     uint8_t dest_shorthand = \
2280c36af8cSClaudio Fontana         (icr & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT;
2290c36af8cSClaudio Fontana     bool logical_mod = icr & APIC_ICR_DEST_MOD;
2300c36af8cSClaudio Fontana     char apic_id_str[MAX_LOGICAL_APIC_ID_MASK_SIZE + 1];
2310c36af8cSClaudio Fontana     uint32_t dest_field;
2320c36af8cSClaudio Fontana     bool x2apic;
2330c36af8cSClaudio Fontana 
2340c36af8cSClaudio Fontana     qemu_printf("ICR\t 0x%08x %s %s %s %s\n",
2350c36af8cSClaudio Fontana                 icr,
2360c36af8cSClaudio Fontana                 logical_mod ? "logical" : "physical",
2370c36af8cSClaudio Fontana                 icr & APIC_ICR_TRIGGER_MOD ? "level" : "edge",
2380c36af8cSClaudio Fontana                 icr & APIC_ICR_LEVEL ? "assert" : "de-assert",
2390c36af8cSClaudio Fontana                 shorthand2str(dest_shorthand));
2400c36af8cSClaudio Fontana 
2410c36af8cSClaudio Fontana     qemu_printf("ICR2\t 0x%08x", icr2);
2420c36af8cSClaudio Fontana     if (dest_shorthand != 0) {
2430c36af8cSClaudio Fontana         qemu_printf("\n");
2440c36af8cSClaudio Fontana         return;
2450c36af8cSClaudio Fontana     }
2460c36af8cSClaudio Fontana     x2apic = env->features[FEAT_1_ECX] & CPUID_EXT_X2APIC;
2470c36af8cSClaudio Fontana     dest_field = x2apic ? icr2 : icr2 >> APIC_ICR_DEST_SHIFT;
2480c36af8cSClaudio Fontana 
2490c36af8cSClaudio Fontana     if (!logical_mod) {
2500c36af8cSClaudio Fontana         if (x2apic) {
2510c36af8cSClaudio Fontana             qemu_printf(" cpu %u (X2APIC ID)\n", dest_field);
2520c36af8cSClaudio Fontana         } else {
2530c36af8cSClaudio Fontana             qemu_printf(" cpu %u (APIC ID)\n",
2540c36af8cSClaudio Fontana                         dest_field & APIC_LOGDEST_XAPIC_ID);
2550c36af8cSClaudio Fontana         }
2560c36af8cSClaudio Fontana         return;
2570c36af8cSClaudio Fontana     }
2580c36af8cSClaudio Fontana 
2590c36af8cSClaudio Fontana     if (s->dest_mode == 0xf) { /* flat mode */
2600c36af8cSClaudio Fontana         mask2str(apic_id_str, icr2 >> APIC_ICR_DEST_SHIFT, 8);
2610c36af8cSClaudio Fontana         qemu_printf(" mask %s (APIC ID)\n", apic_id_str);
2620c36af8cSClaudio Fontana     } else if (s->dest_mode == 0) { /* cluster mode */
2630c36af8cSClaudio Fontana         if (x2apic) {
2640c36af8cSClaudio Fontana             mask2str(apic_id_str, dest_field & APIC_LOGDEST_X2APIC_ID, 16);
2650c36af8cSClaudio Fontana             qemu_printf(" cluster %u mask %s (X2APIC ID)\n",
2660c36af8cSClaudio Fontana                         dest_field >> APIC_LOGDEST_X2APIC_SHIFT, apic_id_str);
2670c36af8cSClaudio Fontana         } else {
2680c36af8cSClaudio Fontana             mask2str(apic_id_str, dest_field & APIC_LOGDEST_XAPIC_ID, 4);
2690c36af8cSClaudio Fontana             qemu_printf(" cluster %u mask %s (APIC ID)\n",
2700c36af8cSClaudio Fontana                         dest_field >> APIC_LOGDEST_XAPIC_SHIFT, apic_id_str);
2710c36af8cSClaudio Fontana         }
2720c36af8cSClaudio Fontana     }
2730c36af8cSClaudio Fontana }
2740c36af8cSClaudio Fontana 
2750c36af8cSClaudio Fontana static void dump_apic_interrupt(const char *name, uint32_t *ireg_tab,
2760c36af8cSClaudio Fontana                                 uint32_t *tmr_tab)
2770c36af8cSClaudio Fontana {
2780c36af8cSClaudio Fontana     int i, empty = true;
2790c36af8cSClaudio Fontana 
2800c36af8cSClaudio Fontana     qemu_printf("%s\t ", name);
2810c36af8cSClaudio Fontana     for (i = 0; i < 256; i++) {
2820c36af8cSClaudio Fontana         if (apic_get_bit(ireg_tab, i)) {
2830c36af8cSClaudio Fontana             qemu_printf("%u%s ", i,
2840c36af8cSClaudio Fontana                         apic_get_bit(tmr_tab, i) ? "(level)" : "");
2850c36af8cSClaudio Fontana             empty = false;
2860c36af8cSClaudio Fontana         }
2870c36af8cSClaudio Fontana     }
2880c36af8cSClaudio Fontana     qemu_printf("%s\n", empty ? "(none)" : "");
2890c36af8cSClaudio Fontana }
2900c36af8cSClaudio Fontana 
2910c36af8cSClaudio Fontana void x86_cpu_dump_local_apic_state(CPUState *cs, int flags)
2920c36af8cSClaudio Fontana {
2930c36af8cSClaudio Fontana     X86CPU *cpu = X86_CPU(cs);
2940c36af8cSClaudio Fontana     APICCommonState *s = APIC_COMMON(cpu->apic_state);
2950c36af8cSClaudio Fontana     if (!s) {
2960c36af8cSClaudio Fontana         qemu_printf("local apic state not available\n");
2970c36af8cSClaudio Fontana         return;
2980c36af8cSClaudio Fontana     }
2990c36af8cSClaudio Fontana     uint32_t *lvt = s->lvt;
3000c36af8cSClaudio Fontana 
3010c36af8cSClaudio Fontana     qemu_printf("dumping local APIC state for CPU %-2u\n\n",
3020c36af8cSClaudio Fontana                 CPU(cpu)->cpu_index);
3030c36af8cSClaudio Fontana     dump_apic_lvt("LVT0", lvt[APIC_LVT_LINT0], false);
3040c36af8cSClaudio Fontana     dump_apic_lvt("LVT1", lvt[APIC_LVT_LINT1], false);
3050c36af8cSClaudio Fontana     dump_apic_lvt("LVTPC", lvt[APIC_LVT_PERFORM], false);
3060c36af8cSClaudio Fontana     dump_apic_lvt("LVTERR", lvt[APIC_LVT_ERROR], false);
3070c36af8cSClaudio Fontana     dump_apic_lvt("LVTTHMR", lvt[APIC_LVT_THERMAL], false);
3080c36af8cSClaudio Fontana     dump_apic_lvt("LVTT", lvt[APIC_LVT_TIMER], true);
3090c36af8cSClaudio Fontana 
3100c36af8cSClaudio Fontana     qemu_printf("Timer\t DCR=0x%x (divide by %u) initial_count = %u"
3110c36af8cSClaudio Fontana                 " current_count = %u\n",
3120c36af8cSClaudio Fontana                 s->divide_conf & APIC_DCR_MASK,
3130c36af8cSClaudio Fontana                 divider_conf(s->divide_conf),
3140c36af8cSClaudio Fontana                 s->initial_count, apic_get_current_count(s));
3150c36af8cSClaudio Fontana 
3160c36af8cSClaudio Fontana     qemu_printf("SPIV\t 0x%08x APIC %s, focus=%s, spurious vec %u\n",
3170c36af8cSClaudio Fontana                 s->spurious_vec,
3180c36af8cSClaudio Fontana                 s->spurious_vec & APIC_SPURIO_ENABLED ? "enabled" : "disabled",
3190c36af8cSClaudio Fontana                 s->spurious_vec & APIC_SPURIO_FOCUS ? "on" : "off",
3200c36af8cSClaudio Fontana                 s->spurious_vec & APIC_VECTOR_MASK);
3210c36af8cSClaudio Fontana 
3220c36af8cSClaudio Fontana     dump_apic_icr(s, &cpu->env);
3230c36af8cSClaudio Fontana 
3240c36af8cSClaudio Fontana     qemu_printf("ESR\t 0x%08x\n", s->esr);
3250c36af8cSClaudio Fontana 
3260c36af8cSClaudio Fontana     dump_apic_interrupt("ISR", s->isr, s->tmr);
3270c36af8cSClaudio Fontana     dump_apic_interrupt("IRR", s->irr, s->tmr);
3280c36af8cSClaudio Fontana 
3290c36af8cSClaudio Fontana     qemu_printf("\nAPR 0x%02x TPR 0x%02x DFR 0x%02x LDR 0x%02x",
3300c36af8cSClaudio Fontana                 s->arb_id, s->tpr, s->dest_mode, s->log_dest);
3310c36af8cSClaudio Fontana     if (s->dest_mode == 0) {
3320c36af8cSClaudio Fontana         qemu_printf("(cluster %u: id %u)",
3330c36af8cSClaudio Fontana                     s->log_dest >> APIC_LOGDEST_XAPIC_SHIFT,
3340c36af8cSClaudio Fontana                     s->log_dest & APIC_LOGDEST_XAPIC_ID);
3350c36af8cSClaudio Fontana     }
3360c36af8cSClaudio Fontana     qemu_printf(" PPR 0x%02x\n", apic_get_ppr(s));
3370c36af8cSClaudio Fontana }
3380c36af8cSClaudio Fontana #else
3390c36af8cSClaudio Fontana void x86_cpu_dump_local_apic_state(CPUState *cs, int flags)
3400c36af8cSClaudio Fontana {
3410c36af8cSClaudio Fontana }
3420c36af8cSClaudio Fontana #endif /* !CONFIG_USER_ONLY */
3430c36af8cSClaudio Fontana 
3440c36af8cSClaudio Fontana #define DUMP_CODE_BYTES_TOTAL    50
3450c36af8cSClaudio Fontana #define DUMP_CODE_BYTES_BACKWARD 20
3460c36af8cSClaudio Fontana 
3470c36af8cSClaudio Fontana void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
3480c36af8cSClaudio Fontana {
3490c36af8cSClaudio Fontana     X86CPU *cpu = X86_CPU(cs);
3500c36af8cSClaudio Fontana     CPUX86State *env = &cpu->env;
3510c36af8cSClaudio Fontana     int eflags, i, nb;
3520c36af8cSClaudio Fontana     char cc_op_name[32];
3530c36af8cSClaudio Fontana     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
3540c36af8cSClaudio Fontana 
3550c36af8cSClaudio Fontana     eflags = cpu_compute_eflags(env);
3560c36af8cSClaudio Fontana #ifdef TARGET_X86_64
3570c36af8cSClaudio Fontana     if (env->hflags & HF_CS64_MASK) {
3580c36af8cSClaudio Fontana         qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
3590c36af8cSClaudio Fontana                      "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
3600c36af8cSClaudio Fontana                      "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
3610c36af8cSClaudio Fontana                      "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
3620c36af8cSClaudio Fontana                      "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
3630c36af8cSClaudio Fontana                      env->regs[R_EAX],
3640c36af8cSClaudio Fontana                      env->regs[R_EBX],
3650c36af8cSClaudio Fontana                      env->regs[R_ECX],
3660c36af8cSClaudio Fontana                      env->regs[R_EDX],
3670c36af8cSClaudio Fontana                      env->regs[R_ESI],
3680c36af8cSClaudio Fontana                      env->regs[R_EDI],
3690c36af8cSClaudio Fontana                      env->regs[R_EBP],
3700c36af8cSClaudio Fontana                      env->regs[R_ESP],
3710c36af8cSClaudio Fontana                      env->regs[8],
3720c36af8cSClaudio Fontana                      env->regs[9],
3730c36af8cSClaudio Fontana                      env->regs[10],
3740c36af8cSClaudio Fontana                      env->regs[11],
3750c36af8cSClaudio Fontana                      env->regs[12],
3760c36af8cSClaudio Fontana                      env->regs[13],
3770c36af8cSClaudio Fontana                      env->regs[14],
3780c36af8cSClaudio Fontana                      env->regs[15],
3790c36af8cSClaudio Fontana                      env->eip, eflags,
3800c36af8cSClaudio Fontana                      eflags & DF_MASK ? 'D' : '-',
3810c36af8cSClaudio Fontana                      eflags & CC_O ? 'O' : '-',
3820c36af8cSClaudio Fontana                      eflags & CC_S ? 'S' : '-',
3830c36af8cSClaudio Fontana                      eflags & CC_Z ? 'Z' : '-',
3840c36af8cSClaudio Fontana                      eflags & CC_A ? 'A' : '-',
3850c36af8cSClaudio Fontana                      eflags & CC_P ? 'P' : '-',
3860c36af8cSClaudio Fontana                      eflags & CC_C ? 'C' : '-',
3870c36af8cSClaudio Fontana                      env->hflags & HF_CPL_MASK,
3880c36af8cSClaudio Fontana                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
3890c36af8cSClaudio Fontana                      (env->a20_mask >> 20) & 1,
3900c36af8cSClaudio Fontana                      (env->hflags >> HF_SMM_SHIFT) & 1,
3910c36af8cSClaudio Fontana                      cs->halted);
3920c36af8cSClaudio Fontana     } else
3930c36af8cSClaudio Fontana #endif
3940c36af8cSClaudio Fontana     {
3950c36af8cSClaudio Fontana         qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
3960c36af8cSClaudio Fontana                      "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
3970c36af8cSClaudio Fontana                      "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
3980c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EAX],
3990c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EBX],
4000c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_ECX],
4010c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EDX],
4020c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_ESI],
4030c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EDI],
4040c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EBP],
4050c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_ESP],
4060c36af8cSClaudio Fontana                      (uint32_t)env->eip, eflags,
4070c36af8cSClaudio Fontana                      eflags & DF_MASK ? 'D' : '-',
4080c36af8cSClaudio Fontana                      eflags & CC_O ? 'O' : '-',
4090c36af8cSClaudio Fontana                      eflags & CC_S ? 'S' : '-',
4100c36af8cSClaudio Fontana                      eflags & CC_Z ? 'Z' : '-',
4110c36af8cSClaudio Fontana                      eflags & CC_A ? 'A' : '-',
4120c36af8cSClaudio Fontana                      eflags & CC_P ? 'P' : '-',
4130c36af8cSClaudio Fontana                      eflags & CC_C ? 'C' : '-',
4140c36af8cSClaudio Fontana                      env->hflags & HF_CPL_MASK,
4150c36af8cSClaudio Fontana                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
4160c36af8cSClaudio Fontana                      (env->a20_mask >> 20) & 1,
4170c36af8cSClaudio Fontana                      (env->hflags >> HF_SMM_SHIFT) & 1,
4180c36af8cSClaudio Fontana                      cs->halted);
4190c36af8cSClaudio Fontana     }
4200c36af8cSClaudio Fontana 
4210c36af8cSClaudio Fontana     for(i = 0; i < 6; i++) {
4220c36af8cSClaudio Fontana         cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]);
4230c36af8cSClaudio Fontana     }
4240c36af8cSClaudio Fontana     cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt);
4250c36af8cSClaudio Fontana     cpu_x86_dump_seg_cache(env, f, "TR", &env->tr);
4260c36af8cSClaudio Fontana 
4270c36af8cSClaudio Fontana #ifdef TARGET_X86_64
4280c36af8cSClaudio Fontana     if (env->hflags & HF_LMA_MASK) {
4290c36af8cSClaudio Fontana         qemu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
4300c36af8cSClaudio Fontana                      env->gdt.base, env->gdt.limit);
4310c36af8cSClaudio Fontana         qemu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
4320c36af8cSClaudio Fontana                      env->idt.base, env->idt.limit);
4330c36af8cSClaudio Fontana         qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
4340c36af8cSClaudio Fontana                      (uint32_t)env->cr[0],
4350c36af8cSClaudio Fontana                      env->cr[2],
4360c36af8cSClaudio Fontana                      env->cr[3],
4370c36af8cSClaudio Fontana                      (uint32_t)env->cr[4]);
4380c36af8cSClaudio Fontana         for(i = 0; i < 4; i++)
4390c36af8cSClaudio Fontana             qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
4400c36af8cSClaudio Fontana         qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
4410c36af8cSClaudio Fontana                      env->dr[6], env->dr[7]);
4420c36af8cSClaudio Fontana     } else
4430c36af8cSClaudio Fontana #endif
4440c36af8cSClaudio Fontana     {
4450c36af8cSClaudio Fontana         qemu_fprintf(f, "GDT=     %08x %08x\n",
4460c36af8cSClaudio Fontana                      (uint32_t)env->gdt.base, env->gdt.limit);
4470c36af8cSClaudio Fontana         qemu_fprintf(f, "IDT=     %08x %08x\n",
4480c36af8cSClaudio Fontana                      (uint32_t)env->idt.base, env->idt.limit);
4490c36af8cSClaudio Fontana         qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
4500c36af8cSClaudio Fontana                      (uint32_t)env->cr[0],
4510c36af8cSClaudio Fontana                      (uint32_t)env->cr[2],
4520c36af8cSClaudio Fontana                      (uint32_t)env->cr[3],
4530c36af8cSClaudio Fontana                      (uint32_t)env->cr[4]);
4540c36af8cSClaudio Fontana         for(i = 0; i < 4; i++) {
4550c36af8cSClaudio Fontana             qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
4560c36af8cSClaudio Fontana         }
4570c36af8cSClaudio Fontana         qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
4580c36af8cSClaudio Fontana                      env->dr[6], env->dr[7]);
4590c36af8cSClaudio Fontana     }
4600c36af8cSClaudio Fontana     if (flags & CPU_DUMP_CCOP) {
4610c36af8cSClaudio Fontana         if ((unsigned)env->cc_op < CC_OP_NB)
4620c36af8cSClaudio Fontana             snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
4630c36af8cSClaudio Fontana         else
4640c36af8cSClaudio Fontana             snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
4650c36af8cSClaudio Fontana #ifdef TARGET_X86_64
4660c36af8cSClaudio Fontana         if (env->hflags & HF_CS64_MASK) {
467*61848717SMarkus Armbruster             qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
4680c36af8cSClaudio Fontana                          env->cc_src, env->cc_dst,
4690c36af8cSClaudio Fontana                          cc_op_name);
4700c36af8cSClaudio Fontana         } else
4710c36af8cSClaudio Fontana #endif
4720c36af8cSClaudio Fontana         {
473*61848717SMarkus Armbruster             qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%s\n",
4740c36af8cSClaudio Fontana                          (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
4750c36af8cSClaudio Fontana                          cc_op_name);
4760c36af8cSClaudio Fontana         }
4770c36af8cSClaudio Fontana     }
4780c36af8cSClaudio Fontana     qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
4790c36af8cSClaudio Fontana     if (flags & CPU_DUMP_FPU) {
4800c36af8cSClaudio Fontana         int fptag;
481f9c0322aSRobert Hoo         const uint64_t avx512_mask = XSTATE_OPMASK_MASK | \
482f9c0322aSRobert Hoo                                      XSTATE_ZMM_Hi256_MASK | \
483f9c0322aSRobert Hoo                                      XSTATE_Hi16_ZMM_MASK | \
484f9c0322aSRobert Hoo                                      XSTATE_YMM_MASK | XSTATE_SSE_MASK,
485f9c0322aSRobert Hoo                        avx_mask = XSTATE_YMM_MASK | XSTATE_SSE_MASK;
4860c36af8cSClaudio Fontana         fptag = 0;
4870c36af8cSClaudio Fontana         for(i = 0; i < 8; i++) {
4880c36af8cSClaudio Fontana             fptag |= ((!env->fptags[i]) << i);
4890c36af8cSClaudio Fontana         }
4900c36af8cSClaudio Fontana         update_mxcsr_from_sse_status(env);
4910c36af8cSClaudio Fontana         qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
4920c36af8cSClaudio Fontana                      env->fpuc,
4930c36af8cSClaudio Fontana                      (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
4940c36af8cSClaudio Fontana                      env->fpstt,
4950c36af8cSClaudio Fontana                      fptag,
4960c36af8cSClaudio Fontana                      env->mxcsr);
4970c36af8cSClaudio Fontana         for(i=0;i<8;i++) {
4980c36af8cSClaudio Fontana             CPU_LDoubleU u;
4990c36af8cSClaudio Fontana             u.d = env->fpregs[i].d;
5000c36af8cSClaudio Fontana             qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
5010c36af8cSClaudio Fontana                          i, u.l.lower, u.l.upper);
5020c36af8cSClaudio Fontana             if ((i & 1) == 1)
5030c36af8cSClaudio Fontana                 qemu_fprintf(f, "\n");
5040c36af8cSClaudio Fontana             else
5050c36af8cSClaudio Fontana                 qemu_fprintf(f, " ");
5060c36af8cSClaudio Fontana         }
507f9c0322aSRobert Hoo 
508f9c0322aSRobert Hoo         if ((env->xcr0 & avx512_mask) == avx512_mask) {
509f9c0322aSRobert Hoo             /* XSAVE enabled AVX512 */
510f9c0322aSRobert Hoo             for (i = 0; i < NB_OPMASK_REGS; i++) {
511f9c0322aSRobert Hoo                 qemu_fprintf(f, "Opmask%02d=%016"PRIx64"%s", i,
512f9c0322aSRobert Hoo                              env->opmask_regs[i], ((i & 3) == 3) ? "\n" : " ");
513f9c0322aSRobert Hoo             }
514f9c0322aSRobert Hoo 
515f9c0322aSRobert Hoo             nb = (env->hflags & HF_CS64_MASK) ? 32 : 8;
5160c36af8cSClaudio Fontana             for (i = 0; i < nb; i++) {
517f9c0322aSRobert Hoo                 qemu_fprintf(f, "ZMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
518f9c0322aSRobert Hoo                              " %016"PRIx64" %016"PRIx64" %016"PRIx64
519f9c0322aSRobert Hoo                              " %016"PRIx64" %016"PRIx64"\n",
5200c36af8cSClaudio Fontana                              i,
521f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(7),
522f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(6),
523f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(5),
524f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(4),
525f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(3),
526f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(2),
527f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(1),
528f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(0));
529f9c0322aSRobert Hoo             }
530f9c0322aSRobert Hoo         } else if ((env->xcr0 & avx_mask)  == avx_mask) {
531f9c0322aSRobert Hoo             /* XSAVE enabled AVX */
532f9c0322aSRobert Hoo             nb = env->hflags & HF_CS64_MASK ? 16 : 8;
533f9c0322aSRobert Hoo             for (i = 0; i < nb; i++) {
534f9c0322aSRobert Hoo                 qemu_fprintf(f, "YMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
535f9c0322aSRobert Hoo                              " %016"PRIx64"\n", i,
536f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(3),
537f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(2),
538f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(1),
539f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(0));
540f9c0322aSRobert Hoo             }
541f9c0322aSRobert Hoo         } else { /* SSE and below cases */
542f9c0322aSRobert Hoo             nb = env->hflags & HF_CS64_MASK ? 16 : 8;
543f9c0322aSRobert Hoo             for (i = 0; i < nb; i++) {
544f9c0322aSRobert Hoo                 qemu_fprintf(f, "XMM%02d=%016"PRIx64" %016"PRIx64"%s",
545f9c0322aSRobert Hoo                              i,
546f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(1),
547f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(0),
548f9c0322aSRobert Hoo                              (i & 1) ? "\n" : " ");
549f9c0322aSRobert Hoo             }
5500c36af8cSClaudio Fontana         }
5510c36af8cSClaudio Fontana     }
5520c36af8cSClaudio Fontana     if (flags & CPU_DUMP_CODE) {
5530c36af8cSClaudio Fontana         target_ulong base = env->segs[R_CS].base + env->eip;
5540c36af8cSClaudio Fontana         target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
5550c36af8cSClaudio Fontana         uint8_t code;
5560c36af8cSClaudio Fontana         char codestr[3];
5570c36af8cSClaudio Fontana 
5580c36af8cSClaudio Fontana         qemu_fprintf(f, "Code=");
5590c36af8cSClaudio Fontana         for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
5600c36af8cSClaudio Fontana             if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
5610c36af8cSClaudio Fontana                 snprintf(codestr, sizeof(codestr), "%02x", code);
5620c36af8cSClaudio Fontana             } else {
5630c36af8cSClaudio Fontana                 snprintf(codestr, sizeof(codestr), "??");
5640c36af8cSClaudio Fontana             }
5650c36af8cSClaudio Fontana             qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
5660c36af8cSClaudio Fontana                          i == offs ? "<" : "", codestr, i == offs ? ">" : "");
5670c36af8cSClaudio Fontana         }
5680c36af8cSClaudio Fontana         qemu_fprintf(f, "\n");
5690c36af8cSClaudio Fontana     }
5700c36af8cSClaudio Fontana }
571