xref: /qemu/target/i386/cpu-dump.c (revision b5c6a3c1df17c444b6ab587d363a758a54212be0)
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 }
338*b5c6a3c1SPhilippe Mathieu-Daudé 
3390c36af8cSClaudio Fontana #endif /* !CONFIG_USER_ONLY */
3400c36af8cSClaudio Fontana 
3410c36af8cSClaudio Fontana #define DUMP_CODE_BYTES_TOTAL    50
3420c36af8cSClaudio Fontana #define DUMP_CODE_BYTES_BACKWARD 20
3430c36af8cSClaudio Fontana 
3440c36af8cSClaudio Fontana void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
3450c36af8cSClaudio Fontana {
3460c36af8cSClaudio Fontana     X86CPU *cpu = X86_CPU(cs);
3470c36af8cSClaudio Fontana     CPUX86State *env = &cpu->env;
3480c36af8cSClaudio Fontana     int eflags, i, nb;
3490c36af8cSClaudio Fontana     char cc_op_name[32];
3500c36af8cSClaudio Fontana     static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
3510c36af8cSClaudio Fontana 
3520c36af8cSClaudio Fontana     eflags = cpu_compute_eflags(env);
3530c36af8cSClaudio Fontana #ifdef TARGET_X86_64
3540c36af8cSClaudio Fontana     if (env->hflags & HF_CS64_MASK) {
3550c36af8cSClaudio Fontana         qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
3560c36af8cSClaudio Fontana                      "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
3570c36af8cSClaudio Fontana                      "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
3580c36af8cSClaudio Fontana                      "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
3590c36af8cSClaudio Fontana                      "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
3600c36af8cSClaudio Fontana                      env->regs[R_EAX],
3610c36af8cSClaudio Fontana                      env->regs[R_EBX],
3620c36af8cSClaudio Fontana                      env->regs[R_ECX],
3630c36af8cSClaudio Fontana                      env->regs[R_EDX],
3640c36af8cSClaudio Fontana                      env->regs[R_ESI],
3650c36af8cSClaudio Fontana                      env->regs[R_EDI],
3660c36af8cSClaudio Fontana                      env->regs[R_EBP],
3670c36af8cSClaudio Fontana                      env->regs[R_ESP],
3680c36af8cSClaudio Fontana                      env->regs[8],
3690c36af8cSClaudio Fontana                      env->regs[9],
3700c36af8cSClaudio Fontana                      env->regs[10],
3710c36af8cSClaudio Fontana                      env->regs[11],
3720c36af8cSClaudio Fontana                      env->regs[12],
3730c36af8cSClaudio Fontana                      env->regs[13],
3740c36af8cSClaudio Fontana                      env->regs[14],
3750c36af8cSClaudio Fontana                      env->regs[15],
3760c36af8cSClaudio Fontana                      env->eip, eflags,
3770c36af8cSClaudio Fontana                      eflags & DF_MASK ? 'D' : '-',
3780c36af8cSClaudio Fontana                      eflags & CC_O ? 'O' : '-',
3790c36af8cSClaudio Fontana                      eflags & CC_S ? 'S' : '-',
3800c36af8cSClaudio Fontana                      eflags & CC_Z ? 'Z' : '-',
3810c36af8cSClaudio Fontana                      eflags & CC_A ? 'A' : '-',
3820c36af8cSClaudio Fontana                      eflags & CC_P ? 'P' : '-',
3830c36af8cSClaudio Fontana                      eflags & CC_C ? 'C' : '-',
3840c36af8cSClaudio Fontana                      env->hflags & HF_CPL_MASK,
3850c36af8cSClaudio Fontana                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
3860c36af8cSClaudio Fontana                      (env->a20_mask >> 20) & 1,
3870c36af8cSClaudio Fontana                      (env->hflags >> HF_SMM_SHIFT) & 1,
3880c36af8cSClaudio Fontana                      cs->halted);
3890c36af8cSClaudio Fontana     } else
3900c36af8cSClaudio Fontana #endif
3910c36af8cSClaudio Fontana     {
3920c36af8cSClaudio Fontana         qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
3930c36af8cSClaudio Fontana                      "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
3940c36af8cSClaudio Fontana                      "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
3950c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EAX],
3960c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EBX],
3970c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_ECX],
3980c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EDX],
3990c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_ESI],
4000c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EDI],
4010c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_EBP],
4020c36af8cSClaudio Fontana                      (uint32_t)env->regs[R_ESP],
4030c36af8cSClaudio Fontana                      (uint32_t)env->eip, eflags,
4040c36af8cSClaudio Fontana                      eflags & DF_MASK ? 'D' : '-',
4050c36af8cSClaudio Fontana                      eflags & CC_O ? 'O' : '-',
4060c36af8cSClaudio Fontana                      eflags & CC_S ? 'S' : '-',
4070c36af8cSClaudio Fontana                      eflags & CC_Z ? 'Z' : '-',
4080c36af8cSClaudio Fontana                      eflags & CC_A ? 'A' : '-',
4090c36af8cSClaudio Fontana                      eflags & CC_P ? 'P' : '-',
4100c36af8cSClaudio Fontana                      eflags & CC_C ? 'C' : '-',
4110c36af8cSClaudio Fontana                      env->hflags & HF_CPL_MASK,
4120c36af8cSClaudio Fontana                      (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
4130c36af8cSClaudio Fontana                      (env->a20_mask >> 20) & 1,
4140c36af8cSClaudio Fontana                      (env->hflags >> HF_SMM_SHIFT) & 1,
4150c36af8cSClaudio Fontana                      cs->halted);
4160c36af8cSClaudio Fontana     }
4170c36af8cSClaudio Fontana 
4180c36af8cSClaudio Fontana     for(i = 0; i < 6; i++) {
4190c36af8cSClaudio Fontana         cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]);
4200c36af8cSClaudio Fontana     }
4210c36af8cSClaudio Fontana     cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt);
4220c36af8cSClaudio Fontana     cpu_x86_dump_seg_cache(env, f, "TR", &env->tr);
4230c36af8cSClaudio Fontana 
4240c36af8cSClaudio Fontana #ifdef TARGET_X86_64
4250c36af8cSClaudio Fontana     if (env->hflags & HF_LMA_MASK) {
4260c36af8cSClaudio Fontana         qemu_fprintf(f, "GDT=     %016" PRIx64 " %08x\n",
4270c36af8cSClaudio Fontana                      env->gdt.base, env->gdt.limit);
4280c36af8cSClaudio Fontana         qemu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
4290c36af8cSClaudio Fontana                      env->idt.base, env->idt.limit);
4300c36af8cSClaudio Fontana         qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
4310c36af8cSClaudio Fontana                      (uint32_t)env->cr[0],
4320c36af8cSClaudio Fontana                      env->cr[2],
4330c36af8cSClaudio Fontana                      env->cr[3],
4340c36af8cSClaudio Fontana                      (uint32_t)env->cr[4]);
4350c36af8cSClaudio Fontana         for(i = 0; i < 4; i++)
4360c36af8cSClaudio Fontana             qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
4370c36af8cSClaudio Fontana         qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
4380c36af8cSClaudio Fontana                      env->dr[6], env->dr[7]);
4390c36af8cSClaudio Fontana     } else
4400c36af8cSClaudio Fontana #endif
4410c36af8cSClaudio Fontana     {
4420c36af8cSClaudio Fontana         qemu_fprintf(f, "GDT=     %08x %08x\n",
4430c36af8cSClaudio Fontana                      (uint32_t)env->gdt.base, env->gdt.limit);
4440c36af8cSClaudio Fontana         qemu_fprintf(f, "IDT=     %08x %08x\n",
4450c36af8cSClaudio Fontana                      (uint32_t)env->idt.base, env->idt.limit);
4460c36af8cSClaudio Fontana         qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
4470c36af8cSClaudio Fontana                      (uint32_t)env->cr[0],
4480c36af8cSClaudio Fontana                      (uint32_t)env->cr[2],
4490c36af8cSClaudio Fontana                      (uint32_t)env->cr[3],
4500c36af8cSClaudio Fontana                      (uint32_t)env->cr[4]);
4510c36af8cSClaudio Fontana         for(i = 0; i < 4; i++) {
4520c36af8cSClaudio Fontana             qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
4530c36af8cSClaudio Fontana         }
4540c36af8cSClaudio Fontana         qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
4550c36af8cSClaudio Fontana                      env->dr[6], env->dr[7]);
4560c36af8cSClaudio Fontana     }
4570c36af8cSClaudio Fontana     if (flags & CPU_DUMP_CCOP) {
4580c36af8cSClaudio Fontana         if ((unsigned)env->cc_op < CC_OP_NB)
4590c36af8cSClaudio Fontana             snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
4600c36af8cSClaudio Fontana         else
4610c36af8cSClaudio Fontana             snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
4620c36af8cSClaudio Fontana #ifdef TARGET_X86_64
4630c36af8cSClaudio Fontana         if (env->hflags & HF_CS64_MASK) {
46461848717SMarkus Armbruster             qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
4650c36af8cSClaudio Fontana                          env->cc_src, env->cc_dst,
4660c36af8cSClaudio Fontana                          cc_op_name);
4670c36af8cSClaudio Fontana         } else
4680c36af8cSClaudio Fontana #endif
4690c36af8cSClaudio Fontana         {
47061848717SMarkus Armbruster             qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%s\n",
4710c36af8cSClaudio Fontana                          (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
4720c36af8cSClaudio Fontana                          cc_op_name);
4730c36af8cSClaudio Fontana         }
4740c36af8cSClaudio Fontana     }
4750c36af8cSClaudio Fontana     qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
4760c36af8cSClaudio Fontana     if (flags & CPU_DUMP_FPU) {
4770c36af8cSClaudio Fontana         int fptag;
478f9c0322aSRobert Hoo         const uint64_t avx512_mask = XSTATE_OPMASK_MASK | \
479f9c0322aSRobert Hoo                                      XSTATE_ZMM_Hi256_MASK | \
480f9c0322aSRobert Hoo                                      XSTATE_Hi16_ZMM_MASK | \
481f9c0322aSRobert Hoo                                      XSTATE_YMM_MASK | XSTATE_SSE_MASK,
482f9c0322aSRobert Hoo                        avx_mask = XSTATE_YMM_MASK | XSTATE_SSE_MASK;
4830c36af8cSClaudio Fontana         fptag = 0;
4840c36af8cSClaudio Fontana         for(i = 0; i < 8; i++) {
4850c36af8cSClaudio Fontana             fptag |= ((!env->fptags[i]) << i);
4860c36af8cSClaudio Fontana         }
4870c36af8cSClaudio Fontana         update_mxcsr_from_sse_status(env);
4880c36af8cSClaudio Fontana         qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
4890c36af8cSClaudio Fontana                      env->fpuc,
4900c36af8cSClaudio Fontana                      (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
4910c36af8cSClaudio Fontana                      env->fpstt,
4920c36af8cSClaudio Fontana                      fptag,
4930c36af8cSClaudio Fontana                      env->mxcsr);
4940c36af8cSClaudio Fontana         for(i=0;i<8;i++) {
4950c36af8cSClaudio Fontana             CPU_LDoubleU u;
4960c36af8cSClaudio Fontana             u.d = env->fpregs[i].d;
4970c36af8cSClaudio Fontana             qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
4980c36af8cSClaudio Fontana                          i, u.l.lower, u.l.upper);
4990c36af8cSClaudio Fontana             if ((i & 1) == 1)
5000c36af8cSClaudio Fontana                 qemu_fprintf(f, "\n");
5010c36af8cSClaudio Fontana             else
5020c36af8cSClaudio Fontana                 qemu_fprintf(f, " ");
5030c36af8cSClaudio Fontana         }
504f9c0322aSRobert Hoo 
505f9c0322aSRobert Hoo         if ((env->xcr0 & avx512_mask) == avx512_mask) {
506f9c0322aSRobert Hoo             /* XSAVE enabled AVX512 */
507f9c0322aSRobert Hoo             for (i = 0; i < NB_OPMASK_REGS; i++) {
508f9c0322aSRobert Hoo                 qemu_fprintf(f, "Opmask%02d=%016"PRIx64"%s", i,
509f9c0322aSRobert Hoo                              env->opmask_regs[i], ((i & 3) == 3) ? "\n" : " ");
510f9c0322aSRobert Hoo             }
511f9c0322aSRobert Hoo 
512f9c0322aSRobert Hoo             nb = (env->hflags & HF_CS64_MASK) ? 32 : 8;
5130c36af8cSClaudio Fontana             for (i = 0; i < nb; i++) {
514f9c0322aSRobert Hoo                 qemu_fprintf(f, "ZMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
515f9c0322aSRobert Hoo                              " %016"PRIx64" %016"PRIx64" %016"PRIx64
516f9c0322aSRobert Hoo                              " %016"PRIx64" %016"PRIx64"\n",
5170c36af8cSClaudio Fontana                              i,
518f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(7),
519f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(6),
520f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(5),
521f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(4),
522f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(3),
523f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(2),
524f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(1),
525f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(0));
526f9c0322aSRobert Hoo             }
527f9c0322aSRobert Hoo         } else if ((env->xcr0 & avx_mask)  == avx_mask) {
528f9c0322aSRobert Hoo             /* XSAVE enabled AVX */
529f9c0322aSRobert Hoo             nb = env->hflags & HF_CS64_MASK ? 16 : 8;
530f9c0322aSRobert Hoo             for (i = 0; i < nb; i++) {
531f9c0322aSRobert Hoo                 qemu_fprintf(f, "YMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
532f9c0322aSRobert Hoo                              " %016"PRIx64"\n", i,
533f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(3),
534f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(2),
535f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(1),
536f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(0));
537f9c0322aSRobert Hoo             }
538f9c0322aSRobert Hoo         } else { /* SSE and below cases */
539f9c0322aSRobert Hoo             nb = env->hflags & HF_CS64_MASK ? 16 : 8;
540f9c0322aSRobert Hoo             for (i = 0; i < nb; i++) {
541f9c0322aSRobert Hoo                 qemu_fprintf(f, "XMM%02d=%016"PRIx64" %016"PRIx64"%s",
542f9c0322aSRobert Hoo                              i,
543f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(1),
544f9c0322aSRobert Hoo                              env->xmm_regs[i].ZMM_Q(0),
545f9c0322aSRobert Hoo                              (i & 1) ? "\n" : " ");
546f9c0322aSRobert Hoo             }
5470c36af8cSClaudio Fontana         }
5480c36af8cSClaudio Fontana     }
5490c36af8cSClaudio Fontana     if (flags & CPU_DUMP_CODE) {
5500c36af8cSClaudio Fontana         target_ulong base = env->segs[R_CS].base + env->eip;
5510c36af8cSClaudio Fontana         target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
5520c36af8cSClaudio Fontana         uint8_t code;
5530c36af8cSClaudio Fontana         char codestr[3];
5540c36af8cSClaudio Fontana 
5550c36af8cSClaudio Fontana         qemu_fprintf(f, "Code=");
5560c36af8cSClaudio Fontana         for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
5570c36af8cSClaudio Fontana             if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
5580c36af8cSClaudio Fontana                 snprintf(codestr, sizeof(codestr), "%02x", code);
5590c36af8cSClaudio Fontana             } else {
5600c36af8cSClaudio Fontana                 snprintf(codestr, sizeof(codestr), "??");
5610c36af8cSClaudio Fontana             }
5620c36af8cSClaudio Fontana             qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
5630c36af8cSClaudio Fontana                          i == offs ? "<" : "", codestr, i == offs ? ">" : "");
5640c36af8cSClaudio Fontana         }
5650c36af8cSClaudio Fontana         qemu_fprintf(f, "\n");
5660c36af8cSClaudio Fontana     }
5670c36af8cSClaudio Fontana }
568