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
30*c2954745SRichard Henderson static const char * const cc_op_str[] = {
31e36b976dSPaolo Bonzini [CC_OP_DYNAMIC] = "DYNAMIC",
320c36af8cSClaudio Fontana
33e36b976dSPaolo Bonzini [CC_OP_EFLAGS] = "EFLAGS",
34e36b976dSPaolo Bonzini [CC_OP_ADCX] = "ADCX",
35e36b976dSPaolo Bonzini [CC_OP_ADOX] = "ADOX",
36e36b976dSPaolo Bonzini [CC_OP_ADCOX] = "ADCOX",
370c36af8cSClaudio Fontana
38e36b976dSPaolo Bonzini [CC_OP_MULB] = "MULB",
39e36b976dSPaolo Bonzini [CC_OP_MULW] = "MULW",
40e36b976dSPaolo Bonzini [CC_OP_MULL] = "MULL",
41e36b976dSPaolo Bonzini [CC_OP_MULQ] = "MULQ",
420c36af8cSClaudio Fontana
43e36b976dSPaolo Bonzini [CC_OP_ADDB] = "ADDB",
44e36b976dSPaolo Bonzini [CC_OP_ADDW] = "ADDW",
45e36b976dSPaolo Bonzini [CC_OP_ADDL] = "ADDL",
46e36b976dSPaolo Bonzini [CC_OP_ADDQ] = "ADDQ",
470c36af8cSClaudio Fontana
48e36b976dSPaolo Bonzini [CC_OP_ADCB] = "ADCB",
49e36b976dSPaolo Bonzini [CC_OP_ADCW] = "ADCW",
50e36b976dSPaolo Bonzini [CC_OP_ADCL] = "ADCL",
51e36b976dSPaolo Bonzini [CC_OP_ADCQ] = "ADCQ",
520c36af8cSClaudio Fontana
53e36b976dSPaolo Bonzini [CC_OP_SUBB] = "SUBB",
54e36b976dSPaolo Bonzini [CC_OP_SUBW] = "SUBW",
55e36b976dSPaolo Bonzini [CC_OP_SUBL] = "SUBL",
56e36b976dSPaolo Bonzini [CC_OP_SUBQ] = "SUBQ",
570c36af8cSClaudio Fontana
58e36b976dSPaolo Bonzini [CC_OP_SBBB] = "SBBB",
59e36b976dSPaolo Bonzini [CC_OP_SBBW] = "SBBW",
60e36b976dSPaolo Bonzini [CC_OP_SBBL] = "SBBL",
61e36b976dSPaolo Bonzini [CC_OP_SBBQ] = "SBBQ",
620c36af8cSClaudio Fontana
63e36b976dSPaolo Bonzini [CC_OP_LOGICB] = "LOGICB",
64e36b976dSPaolo Bonzini [CC_OP_LOGICW] = "LOGICW",
65e36b976dSPaolo Bonzini [CC_OP_LOGICL] = "LOGICL",
66e36b976dSPaolo Bonzini [CC_OP_LOGICQ] = "LOGICQ",
670c36af8cSClaudio Fontana
68e36b976dSPaolo Bonzini [CC_OP_INCB] = "INCB",
69e36b976dSPaolo Bonzini [CC_OP_INCW] = "INCW",
70e36b976dSPaolo Bonzini [CC_OP_INCL] = "INCL",
71e36b976dSPaolo Bonzini [CC_OP_INCQ] = "INCQ",
720c36af8cSClaudio Fontana
73e36b976dSPaolo Bonzini [CC_OP_DECB] = "DECB",
74e36b976dSPaolo Bonzini [CC_OP_DECW] = "DECW",
75e36b976dSPaolo Bonzini [CC_OP_DECL] = "DECL",
76e36b976dSPaolo Bonzini [CC_OP_DECQ] = "DECQ",
770c36af8cSClaudio Fontana
78e36b976dSPaolo Bonzini [CC_OP_SHLB] = "SHLB",
79e36b976dSPaolo Bonzini [CC_OP_SHLW] = "SHLW",
80e36b976dSPaolo Bonzini [CC_OP_SHLL] = "SHLL",
81e36b976dSPaolo Bonzini [CC_OP_SHLQ] = "SHLQ",
820c36af8cSClaudio Fontana
83e36b976dSPaolo Bonzini [CC_OP_SARB] = "SARB",
84e36b976dSPaolo Bonzini [CC_OP_SARW] = "SARW",
85e36b976dSPaolo Bonzini [CC_OP_SARL] = "SARL",
86e36b976dSPaolo Bonzini [CC_OP_SARQ] = "SARQ",
870c36af8cSClaudio Fontana
88e36b976dSPaolo Bonzini [CC_OP_BMILGB] = "BMILGB",
89e36b976dSPaolo Bonzini [CC_OP_BMILGW] = "BMILGW",
90e36b976dSPaolo Bonzini [CC_OP_BMILGL] = "BMILGL",
91e36b976dSPaolo Bonzini [CC_OP_BMILGQ] = "BMILGQ",
920c36af8cSClaudio Fontana
93e36b976dSPaolo Bonzini [CC_OP_POPCNT] = "POPCNT",
940c36af8cSClaudio Fontana };
950c36af8cSClaudio Fontana
960c36af8cSClaudio Fontana static void
cpu_x86_dump_seg_cache(CPUX86State * env,FILE * f,const char * name,struct SegmentCache * sc)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 */
dm2str(uint32_t dm)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
dump_apic_lvt(const char * name,uint32_t lvt,bool is_timer)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 */
shorthand2str(uint32_t shorthand)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
divider_conf(uint32_t divide_conf)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
mask2str(char * str,uint32_t val,uint8_t size)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
dump_apic_icr(APICCommonState * s,CPUX86State * env)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
dump_apic_interrupt(const char * name,uint32_t * ireg_tab,uint32_t * tmr_tab)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
x86_cpu_dump_local_apic_state(CPUState * cs,int flags)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 }
338b5c6a3c1SPhilippe 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
x86_cpu_dump_state(CPUState * cs,FILE * f,int flags)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 static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
3500c36af8cSClaudio Fontana
3510c36af8cSClaudio Fontana eflags = cpu_compute_eflags(env);
3520c36af8cSClaudio Fontana #ifdef TARGET_X86_64
3530c36af8cSClaudio Fontana if (env->hflags & HF_CS64_MASK) {
3540c36af8cSClaudio Fontana qemu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
3550c36af8cSClaudio Fontana "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
3560c36af8cSClaudio Fontana "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
3570c36af8cSClaudio Fontana "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
3580c36af8cSClaudio Fontana "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
3590c36af8cSClaudio Fontana env->regs[R_EAX],
3600c36af8cSClaudio Fontana env->regs[R_EBX],
3610c36af8cSClaudio Fontana env->regs[R_ECX],
3620c36af8cSClaudio Fontana env->regs[R_EDX],
3630c36af8cSClaudio Fontana env->regs[R_ESI],
3640c36af8cSClaudio Fontana env->regs[R_EDI],
3650c36af8cSClaudio Fontana env->regs[R_EBP],
3660c36af8cSClaudio Fontana env->regs[R_ESP],
3670c36af8cSClaudio Fontana env->regs[8],
3680c36af8cSClaudio Fontana env->regs[9],
3690c36af8cSClaudio Fontana env->regs[10],
3700c36af8cSClaudio Fontana env->regs[11],
3710c36af8cSClaudio Fontana env->regs[12],
3720c36af8cSClaudio Fontana env->regs[13],
3730c36af8cSClaudio Fontana env->regs[14],
3740c36af8cSClaudio Fontana env->regs[15],
3750c36af8cSClaudio Fontana env->eip, eflags,
3760c36af8cSClaudio Fontana eflags & DF_MASK ? 'D' : '-',
3770c36af8cSClaudio Fontana eflags & CC_O ? 'O' : '-',
3780c36af8cSClaudio Fontana eflags & CC_S ? 'S' : '-',
3790c36af8cSClaudio Fontana eflags & CC_Z ? 'Z' : '-',
3800c36af8cSClaudio Fontana eflags & CC_A ? 'A' : '-',
3810c36af8cSClaudio Fontana eflags & CC_P ? 'P' : '-',
3820c36af8cSClaudio Fontana eflags & CC_C ? 'C' : '-',
3830c36af8cSClaudio Fontana env->hflags & HF_CPL_MASK,
3840c36af8cSClaudio Fontana (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
3850c36af8cSClaudio Fontana (env->a20_mask >> 20) & 1,
3860c36af8cSClaudio Fontana (env->hflags >> HF_SMM_SHIFT) & 1,
3870c36af8cSClaudio Fontana cs->halted);
3880c36af8cSClaudio Fontana } else
3890c36af8cSClaudio Fontana #endif
3900c36af8cSClaudio Fontana {
3910c36af8cSClaudio Fontana qemu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
3920c36af8cSClaudio Fontana "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
3930c36af8cSClaudio Fontana "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
3940c36af8cSClaudio Fontana (uint32_t)env->regs[R_EAX],
3950c36af8cSClaudio Fontana (uint32_t)env->regs[R_EBX],
3960c36af8cSClaudio Fontana (uint32_t)env->regs[R_ECX],
3970c36af8cSClaudio Fontana (uint32_t)env->regs[R_EDX],
3980c36af8cSClaudio Fontana (uint32_t)env->regs[R_ESI],
3990c36af8cSClaudio Fontana (uint32_t)env->regs[R_EDI],
4000c36af8cSClaudio Fontana (uint32_t)env->regs[R_EBP],
4010c36af8cSClaudio Fontana (uint32_t)env->regs[R_ESP],
4020c36af8cSClaudio Fontana (uint32_t)env->eip, eflags,
4030c36af8cSClaudio Fontana eflags & DF_MASK ? 'D' : '-',
4040c36af8cSClaudio Fontana eflags & CC_O ? 'O' : '-',
4050c36af8cSClaudio Fontana eflags & CC_S ? 'S' : '-',
4060c36af8cSClaudio Fontana eflags & CC_Z ? 'Z' : '-',
4070c36af8cSClaudio Fontana eflags & CC_A ? 'A' : '-',
4080c36af8cSClaudio Fontana eflags & CC_P ? 'P' : '-',
4090c36af8cSClaudio Fontana eflags & CC_C ? 'C' : '-',
4100c36af8cSClaudio Fontana env->hflags & HF_CPL_MASK,
4110c36af8cSClaudio Fontana (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
4120c36af8cSClaudio Fontana (env->a20_mask >> 20) & 1,
4130c36af8cSClaudio Fontana (env->hflags >> HF_SMM_SHIFT) & 1,
4140c36af8cSClaudio Fontana cs->halted);
4150c36af8cSClaudio Fontana }
4160c36af8cSClaudio Fontana
4170c36af8cSClaudio Fontana for(i = 0; i < 6; i++) {
4180c36af8cSClaudio Fontana cpu_x86_dump_seg_cache(env, f, seg_name[i], &env->segs[i]);
4190c36af8cSClaudio Fontana }
4200c36af8cSClaudio Fontana cpu_x86_dump_seg_cache(env, f, "LDT", &env->ldt);
4210c36af8cSClaudio Fontana cpu_x86_dump_seg_cache(env, f, "TR", &env->tr);
4220c36af8cSClaudio Fontana
4230c36af8cSClaudio Fontana #ifdef TARGET_X86_64
4240c36af8cSClaudio Fontana if (env->hflags & HF_LMA_MASK) {
4250c36af8cSClaudio Fontana qemu_fprintf(f, "GDT= %016" PRIx64 " %08x\n",
4260c36af8cSClaudio Fontana env->gdt.base, env->gdt.limit);
4270c36af8cSClaudio Fontana qemu_fprintf(f, "IDT= %016" PRIx64 " %08x\n",
4280c36af8cSClaudio Fontana env->idt.base, env->idt.limit);
4290c36af8cSClaudio Fontana qemu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
4300c36af8cSClaudio Fontana (uint32_t)env->cr[0],
4310c36af8cSClaudio Fontana env->cr[2],
4320c36af8cSClaudio Fontana env->cr[3],
4330c36af8cSClaudio Fontana (uint32_t)env->cr[4]);
4340c36af8cSClaudio Fontana for(i = 0; i < 4; i++)
4350c36af8cSClaudio Fontana qemu_fprintf(f, "DR%d=%016" PRIx64 " ", i, env->dr[i]);
4360c36af8cSClaudio Fontana qemu_fprintf(f, "\nDR6=%016" PRIx64 " DR7=%016" PRIx64 "\n",
4370c36af8cSClaudio Fontana env->dr[6], env->dr[7]);
4380c36af8cSClaudio Fontana } else
4390c36af8cSClaudio Fontana #endif
4400c36af8cSClaudio Fontana {
4410c36af8cSClaudio Fontana qemu_fprintf(f, "GDT= %08x %08x\n",
4420c36af8cSClaudio Fontana (uint32_t)env->gdt.base, env->gdt.limit);
4430c36af8cSClaudio Fontana qemu_fprintf(f, "IDT= %08x %08x\n",
4440c36af8cSClaudio Fontana (uint32_t)env->idt.base, env->idt.limit);
4450c36af8cSClaudio Fontana qemu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
4460c36af8cSClaudio Fontana (uint32_t)env->cr[0],
4470c36af8cSClaudio Fontana (uint32_t)env->cr[2],
4480c36af8cSClaudio Fontana (uint32_t)env->cr[3],
4490c36af8cSClaudio Fontana (uint32_t)env->cr[4]);
4500c36af8cSClaudio Fontana for(i = 0; i < 4; i++) {
4510c36af8cSClaudio Fontana qemu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]);
4520c36af8cSClaudio Fontana }
4530c36af8cSClaudio Fontana qemu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n",
4540c36af8cSClaudio Fontana env->dr[6], env->dr[7]);
4550c36af8cSClaudio Fontana }
4560c36af8cSClaudio Fontana if (flags & CPU_DUMP_CCOP) {
457*c2954745SRichard Henderson const char *cc_op_name = NULL;
458*c2954745SRichard Henderson char cc_op_buf[32];
459*c2954745SRichard Henderson
460*c2954745SRichard Henderson if ((unsigned)env->cc_op < ARRAY_SIZE(cc_op_str)) {
461*c2954745SRichard Henderson cc_op_name = cc_op_str[env->cc_op];
462*c2954745SRichard Henderson }
463*c2954745SRichard Henderson if (cc_op_name == NULL) {
464*c2954745SRichard Henderson snprintf(cc_op_buf, sizeof(cc_op_buf), "[%d]", env->cc_op);
465*c2954745SRichard Henderson cc_op_name = cc_op_buf;
466*c2954745SRichard Henderson }
4670c36af8cSClaudio Fontana #ifdef TARGET_X86_64
4680c36af8cSClaudio Fontana if (env->hflags & HF_CS64_MASK) {
46961848717SMarkus Armbruster qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
4700c36af8cSClaudio Fontana env->cc_src, env->cc_dst,
4710c36af8cSClaudio Fontana cc_op_name);
4720c36af8cSClaudio Fontana } else
4730c36af8cSClaudio Fontana #endif
4740c36af8cSClaudio Fontana {
47561848717SMarkus Armbruster qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%s\n",
4760c36af8cSClaudio Fontana (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
4770c36af8cSClaudio Fontana cc_op_name);
4780c36af8cSClaudio Fontana }
4790c36af8cSClaudio Fontana }
4800c36af8cSClaudio Fontana qemu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
4810c36af8cSClaudio Fontana if (flags & CPU_DUMP_FPU) {
4820c36af8cSClaudio Fontana int fptag;
483f9c0322aSRobert Hoo const uint64_t avx512_mask = XSTATE_OPMASK_MASK | \
484f9c0322aSRobert Hoo XSTATE_ZMM_Hi256_MASK | \
485f9c0322aSRobert Hoo XSTATE_Hi16_ZMM_MASK | \
486f9c0322aSRobert Hoo XSTATE_YMM_MASK | XSTATE_SSE_MASK,
487f9c0322aSRobert Hoo avx_mask = XSTATE_YMM_MASK | XSTATE_SSE_MASK;
4880c36af8cSClaudio Fontana fptag = 0;
4890c36af8cSClaudio Fontana for(i = 0; i < 8; i++) {
4900c36af8cSClaudio Fontana fptag |= ((!env->fptags[i]) << i);
4910c36af8cSClaudio Fontana }
4920c36af8cSClaudio Fontana update_mxcsr_from_sse_status(env);
4930c36af8cSClaudio Fontana qemu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
4940c36af8cSClaudio Fontana env->fpuc,
4950c36af8cSClaudio Fontana (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
4960c36af8cSClaudio Fontana env->fpstt,
4970c36af8cSClaudio Fontana fptag,
4980c36af8cSClaudio Fontana env->mxcsr);
4990c36af8cSClaudio Fontana for(i=0;i<8;i++) {
5000c36af8cSClaudio Fontana CPU_LDoubleU u;
5010c36af8cSClaudio Fontana u.d = env->fpregs[i].d;
5020c36af8cSClaudio Fontana qemu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
5030c36af8cSClaudio Fontana i, u.l.lower, u.l.upper);
5040c36af8cSClaudio Fontana if ((i & 1) == 1)
5050c36af8cSClaudio Fontana qemu_fprintf(f, "\n");
5060c36af8cSClaudio Fontana else
5070c36af8cSClaudio Fontana qemu_fprintf(f, " ");
5080c36af8cSClaudio Fontana }
509f9c0322aSRobert Hoo
510f9c0322aSRobert Hoo if ((env->xcr0 & avx512_mask) == avx512_mask) {
511f9c0322aSRobert Hoo /* XSAVE enabled AVX512 */
512f9c0322aSRobert Hoo for (i = 0; i < NB_OPMASK_REGS; i++) {
513f9c0322aSRobert Hoo qemu_fprintf(f, "Opmask%02d=%016"PRIx64"%s", i,
514f9c0322aSRobert Hoo env->opmask_regs[i], ((i & 3) == 3) ? "\n" : " ");
515f9c0322aSRobert Hoo }
516f9c0322aSRobert Hoo
517f9c0322aSRobert Hoo nb = (env->hflags & HF_CS64_MASK) ? 32 : 8;
5180c36af8cSClaudio Fontana for (i = 0; i < nb; i++) {
519f9c0322aSRobert Hoo qemu_fprintf(f, "ZMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
520f9c0322aSRobert Hoo " %016"PRIx64" %016"PRIx64" %016"PRIx64
521f9c0322aSRobert Hoo " %016"PRIx64" %016"PRIx64"\n",
5220c36af8cSClaudio Fontana i,
523f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(7),
524f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(6),
525f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(5),
526f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(4),
527f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(3),
528f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(2),
529f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(1),
530f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(0));
531f9c0322aSRobert Hoo }
532f9c0322aSRobert Hoo } else if ((env->xcr0 & avx_mask) == avx_mask) {
533f9c0322aSRobert Hoo /* XSAVE enabled AVX */
534f9c0322aSRobert Hoo nb = env->hflags & HF_CS64_MASK ? 16 : 8;
535f9c0322aSRobert Hoo for (i = 0; i < nb; i++) {
536f9c0322aSRobert Hoo qemu_fprintf(f, "YMM%02d=%016"PRIx64" %016"PRIx64" %016"PRIx64
537f9c0322aSRobert Hoo " %016"PRIx64"\n", i,
538f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(3),
539f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(2),
540f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(1),
541f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(0));
542f9c0322aSRobert Hoo }
543f9c0322aSRobert Hoo } else { /* SSE and below cases */
544f9c0322aSRobert Hoo nb = env->hflags & HF_CS64_MASK ? 16 : 8;
545f9c0322aSRobert Hoo for (i = 0; i < nb; i++) {
546f9c0322aSRobert Hoo qemu_fprintf(f, "XMM%02d=%016"PRIx64" %016"PRIx64"%s",
547f9c0322aSRobert Hoo i,
548f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(1),
549f9c0322aSRobert Hoo env->xmm_regs[i].ZMM_Q(0),
550f9c0322aSRobert Hoo (i & 1) ? "\n" : " ");
551f9c0322aSRobert Hoo }
5520c36af8cSClaudio Fontana }
5530c36af8cSClaudio Fontana }
5540c36af8cSClaudio Fontana if (flags & CPU_DUMP_CODE) {
5550c36af8cSClaudio Fontana target_ulong base = env->segs[R_CS].base + env->eip;
5560c36af8cSClaudio Fontana target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
5570c36af8cSClaudio Fontana uint8_t code;
5580c36af8cSClaudio Fontana char codestr[3];
5590c36af8cSClaudio Fontana
5600c36af8cSClaudio Fontana qemu_fprintf(f, "Code=");
5610c36af8cSClaudio Fontana for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
5620c36af8cSClaudio Fontana if (cpu_memory_rw_debug(cs, base - offs + i, &code, 1, 0) == 0) {
5630c36af8cSClaudio Fontana snprintf(codestr, sizeof(codestr), "%02x", code);
5640c36af8cSClaudio Fontana } else {
5650c36af8cSClaudio Fontana snprintf(codestr, sizeof(codestr), "??");
5660c36af8cSClaudio Fontana }
5670c36af8cSClaudio Fontana qemu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
5680c36af8cSClaudio Fontana i == offs ? "<" : "", codestr, i == offs ? ">" : "");
5690c36af8cSClaudio Fontana }
5700c36af8cSClaudio Fontana qemu_fprintf(f, "\n");
5710c36af8cSClaudio Fontana }
5720c36af8cSClaudio Fontana }
573