On 15/09/2015 11:23, Denis V. Lunev wrote: > From: Pavel Butsykin <pbutsy...@virtuozzo.com> > > Added the hmp command to query local apic registers state, may be > usefull after guest crashes to understand IRQ routing in guest. > > For command name uses "apic-local" because it has to be grouped with > command "apic-io".
I would call them "info lapic" and "info ioapic" > > (qemu) info apic-local > apic.lvt 00-timer 000300fd int=fd .H.EMP delmod=0:Fixed > apic.lvt 00-thermal 00010000 int=00 .H.EM. delmod=0:Fixed > apic.lvt 00-perfmon 000000fe int=fe .H.E.. delmod=0:Fixed > apic.lvt 00-LINT0 0001001f int=1f .H.EM. delmod=0:Fixed > apic.lvt 00-LINT1 000004ff int=ff .H.E.. delmod=4:NMI > apic.lvt 00-Error 000000e3 int=e3 .H.E.. delmod=0:Fixed > apic.error 00 esr 00000000 S:... R:... . > apic.timer 00 DCR=0000000b(b) initial_count=1000090000 > apic.icr 00 02000000000c00d1: int=d1 delmod=0:Fixed P..E > shorthand=3:all dest=2 > apic.prio 00 apr=00(0:0) tpr=40(4:0) > apic.dest 00 dfr=f0(f) ldr=01(01) > apic.svr 00 0000011f vec=1f on focus=off > apic.interrupt 00 065:R.E This is not very readable :) What about: Dumping local APIC state for CPU 0 LVT0 0x0001001f activehi edge masked Fixed (vec 31) LVT1 0x000004ff activehi edge NMI LVTPC 0x000000fe activehi edge Fixed (vec 254) LVTERR 0x000000e3 activehi edge Fixed (vec 243) LVTTHMR 0x00010000 activehi edge masked Fixed (vec 0) LVTT 0x000300fd activehi edge masked periodic Fixed (vec 253) Timer DCR=0xb (divide by 1), initial count = 1000090000 SPIV 0x0000011f APIC enabled, focus=off, spurious vec 31 ICR 0x000c00d1 physical edge deassert all ICR2 0x02000000 ESR 0x00000000 ISR 31(level) 65 IRR 31(level) 42(level) APR 0x00 TPR 0x20 DFR 0xf0 LDR 0x01 PPR 0x40 Some notes: - no need to detail ESR, it's never used - no need to detail ICR2 if ICR uses a shorthand, otherwise could be one of these formats "cpu NN" if this APIC is in xapic flat mode "cluster NN mask BBBB" if this APIC is in xapic cluster mode "cluster NN mask BBBBBBBBBBBBBBBB" if this APIC is in x2apic mode - the empty space after "masked" is for "pending" - please add support for TSC deadline mode too Paolo > > Signed-off-by: Pavel Butsykin <pbutsy...@virtuozzo.com> > Signed-off-by: Denis V. Lunev <d...@openvz.org> > CC: Andreas Färber <andreas.faer...@web.de> > CC: Paolo Bonzini <pbonz...@redhat.com> > --- > hmp-commands-info.hx | 16 ++++ > include/monitor/monitor-common.h | 1 + > target-i386/cpu.h | 3 + > target-i386/helper.c | 155 > +++++++++++++++++++++++++++++++++++++++ > target-i386/monitor.c | 6 ++ > 5 files changed, 181 insertions(+) > > diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx > index 9f5a158..5ffc181 100644 > --- a/hmp-commands-info.hx > +++ b/hmp-commands-info.hx > @@ -112,6 +112,22 @@ STEXI > Show the cpu registers. > ETEXI > > +#if defined(TARGET_I386) > + { > + .name = "apic-local", > + .args_type = "", > + .params = "", > + .help = "show local apic state", > + .mhandler.cmd = hmp_info_apic_local, > + }, > +#endif > + > +STEXI > +@item info apic-local > +@findex apic-local > +Show local APIC state > +ETEXI > + > { > .name = "cpus", > .args_type = "", > diff --git a/include/monitor/monitor-common.h > b/include/monitor/monitor-common.h > index abd7a6c..462c35e 100644 > --- a/include/monitor/monitor-common.h > +++ b/include/monitor/monitor-common.h > @@ -42,5 +42,6 @@ CPUState *mon_get_cpu(void); > void hmp_info_mem(Monitor *mon, const QDict *qdict); > void hmp_info_tlb(Monitor *mon, const QDict *qdict); > void hmp_mce(Monitor *mon, const QDict *qdict); > +void hmp_info_apic_local(Monitor *mon, const QDict *qdict); > > #endif /* MONITOR_COMMON */ > diff --git a/target-i386/cpu.h b/target-i386/cpu.h > index af97772..f37a9c6 100644 > --- a/target-i386/cpu.h > +++ b/target-i386/cpu.h > @@ -1347,4 +1347,7 @@ void enable_compat_apic_id_mode(void); > #define APIC_DEFAULT_ADDRESS 0xfee00000 > #define APIC_SPACE_SIZE 0x100000 > > +void x86_cpu_dump_apic_local_state(CPUState *cs, FILE *f, > + fprintf_function cpu_fprintf, int flags); > + > #endif /* CPU_I386_H */ > diff --git a/target-i386/helper.c b/target-i386/helper.c > index 5480a96..8d883f5 100644 > --- a/target-i386/helper.c > +++ b/target-i386/helper.c > @@ -23,6 +23,7 @@ > #ifndef CONFIG_USER_ONLY > #include "sysemu/sysemu.h" > #include "monitor/monitor.h" > +#include "hw/i386/apic_internal.h" > #endif > > static void cpu_x86_version(CPUX86State *env, int *family, int *model) > @@ -177,6 +178,160 @@ done: > cpu_fprintf(f, "\n"); > } > > +#ifndef CONFIG_USER_ONLY > + > +/* ARRAY_SIZE check is not required because > + * DeliveryMode(dm) has a size of 3 bit. > + */ > +static inline const char *dm2str(uint32_t dm) > +{ > + static const char *str[] = { > + "Fixed", > + "...", > + "SMI", > + "...", > + "NMI", > + "INIT", > + "...", > + "ExtINT" > + }; > + return str[dm]; > +} > + > +static void dump_apic_lvt(FILE *f, fprintf_function cpu_fprintf, > + uint32_t cpu_idx, const char *name, > + uint32_t lvt, bool is_timer) > +{ > + uint32_t dm = (lvt & APIC_LVT_DELIV_MOD) >> APIC_LVT_DELIV_MOD_SHIFT; > + cpu_fprintf(f, > + "apic.lvt\t%02u-%-7s %08x int=%02x %c%c%c%c%c%c > delmod=%x:%s\n", > + cpu_idx, name, lvt, > + lvt & APIC_VECTOR_MASK, > + lvt & APIC_LVT_DELIV_STS ? 'P' : '.', > + lvt & APIC_LVT_INT_POLARITY ? 'L' : 'H', > + lvt & APIC_LVT_REMOTE_IRR ? 'R' : '.', > + lvt & APIC_LVT_LEVEL_TRIGGER ? 'L' : 'E', > + lvt & APIC_LVT_MASKED ? 'M' : '.', > + !is_timer ? '.' : (lvt & APIC_LVT_TIMER_PERIODIC ? 'P' : > 'S'), > + dm, > + dm2str(dm)); > + > +} > + > +/* ARRAY_SIZE check is not required because > + * destination shorthand has a size of 2 bit. > + */ > +static inline const char *shorthand2str(uint32_t shorthand) > +{ > + const char *str[] = { > + "no", "self", "all-self", "all" > + }; > + return str[shorthand]; > +} > + > +void x86_cpu_dump_apic_local_state(CPUState *cs, FILE *f, > + fprintf_function cpu_fprintf, int flags) > +{ > + X86CPU *cpu = X86_CPU(cs); > + APICCommonState *s = APIC_COMMON(cpu->apic_state); > + uint32_t *irr_tab = s->irr, *isr_tab = s->isr, *tmr_tab = s->tmr; > + uint32_t *lvt = s->lvt; > + uint32_t icr0 = s->icr[0], icr1 = s->icr[1]; > + uint32_t esr = s->esr; > + uint32_t cpu_idx = CPU(cpu)->cpu_index; > + int i; > + > + dump_apic_lvt(f, cpu_fprintf, cpu_idx, "timer", > + lvt[APIC_LVT_TIMER], true); > + dump_apic_lvt(f, cpu_fprintf, cpu_idx, "thermal", > + lvt[APIC_LVT_THERMAL], false); > + dump_apic_lvt(f, cpu_fprintf, cpu_idx, "perfmon", > + lvt[APIC_LVT_PERFORM], false); > + dump_apic_lvt(f, cpu_fprintf, cpu_idx, "LINT0", > + lvt[APIC_LVT_LINT0], false); > + dump_apic_lvt(f, cpu_fprintf, cpu_idx, "LINT1", > + lvt[APIC_LVT_LINT1], false); > + dump_apic_lvt(f, cpu_fprintf, cpu_idx, "Error", > + lvt[APIC_LVT_ERROR], false); > + > + cpu_fprintf(f, "apic.error\t%02u esr %08x S:%c%c%c R:%c%c%c %c\n", > + cpu_idx, esr, > + esr & APIC_ESR_SEND_CHECK_SUM ? 'C' : '.', > + esr & APIC_ESR_SEND_ACCEPT ? 'A' : '.', > + esr & APIC_ESR_SEND_ILLEGAL_VECT ? 'I' : '.', > + esr & APIC_ESR_RECV_CHECK_SUM ? 'C' : '.', > + esr & APIC_ESR_RECV_ACCEPT ? 'A' : '.', > + esr & APIC_ESR_RECV_ILLEGAL_VECT ? 'I' : '.', > + esr & APIC_ESR_ILLEGAL_ADDRESS ? 'R' : '.'); > + > + cpu_fprintf(f, "apic.timer\t%02u DCR=%08x(%x) initial_count=%d\n", > + cpu_idx, s->divide_conf, s->divide_conf & APIC_DCR_MASK, > + s->initial_count); > + > + cpu_fprintf(f, "apic.icr\t%02u %016jx: int=%02x " > + "delmod=%x:%s %c%c%c%c shorthand=%x:%s dest=%x\n", > + cpu_idx, ((uint64_t *)s->icr)[0], > + icr0 & APIC_VECTOR_MASK, > + (icr0 & APIC_ICR_DELIV_MOD) >> APIC_ICR_DELIV_MOD_SHIFT, > + dm2str((icr0 & APIC_ICR_DELIV_MOD) >> > APIC_ICR_DELIV_MOD_SHIFT), > + icr0 & APIC_ICR_DEST_MOD ? 'L' : 'P', > + icr0 & APIC_ICR_DELIV_STS ? 'P' : '.', > + icr0 & APIC_ICR_LEVEL ? 'A' : '.', > + icr0 & APIC_ICR_TRIGGER_MOD ? 'L' : 'E', > + (icr0 & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT, > + shorthand2str( > + (icr0 & APIC_ICR_DEST_SHORT) >> > APIC_ICR_DEST_SHORT_SHIFT), > + (icr1 >> APIC_ICR_DEST_SHIFT) & > + (icr0 & APIC_ICR_DEST_MOD ? 0xff : 0xf)); > + > + cpu_fprintf(f, "apic.prio\t%02u apr=%02x(%x:%x)\ttpr=%02x(%x:%x)\n", > + cpu_idx, > + s->arb_id, > + s->arb_id >> APIC_PR_CLASS_SHIFT, > + s->arb_id & APIC_PR_SUB_CLASS, > + s->tpr, > + s->tpr >> APIC_PR_CLASS_SHIFT, > + s->tpr & APIC_PR_SUB_CLASS); > + > + cpu_fprintf(f, "apic.dest\t%02u dfr=%02x(%x)\tldr=%02x", > + cpu_idx, s->dest_mode << 4, s->dest_mode, s->log_dest); > + if (s->dest_mode == 0) { > + cpu_fprintf(f, "(%x:%x)\n", > + s->log_dest & APIC_LOGDEST_APIC_ID, > + s->log_dest >> APIC_LOGDEST_ID_SHIFT); > + } else if (s->dest_mode == 0xf) { > + cpu_fprintf(f, "(%02x)\n", s->log_dest); > + } else { > + cpu_fprintf(f, "(BAD)\n"); > + } > + > + cpu_fprintf(f, "apic.svr\t%02u %08x vec=%02x %s focus=%s\n", > + cpu_idx, s->spurious_vec, > + s->spurious_vec & APIC_VECTOR_MASK, > + s->spurious_vec & APIC_SPURIO_ENABLED ? "on" : "off", > + s->spurious_vec & APIC_SPURIO_FOCUS ? "on" : "off"); > + > + for (i = 0; i < 256; i++) { > + if (irr_tab[i] || isr_tab[i]) { > + bool irr_bit = apic_get_bit(irr_tab, i); > + bool isr_bit = apic_get_bit(isr_tab, i); > + > + if (irr_bit || isr_bit) { > + cpu_fprintf(f, "apic.interrupt\t%02u %03u:%c%c%c\n", > cpu_idx, i, > + irr_bit ? 'R' : '.', > + isr_bit ? 'S' : '.', > + apic_get_bit(tmr_tab, i) ? 'L' : 'E'); > + } > + } > + } > +} > +#else > +void x86_cpu_dump_apic_local_state(CPUState *cs, FILE *f, > + fprintf_function cpu_fprintf, int flags) > +{ > +} > +#endif /* !CONFIG_USER_ONLY */ > + > #define DUMP_CODE_BYTES_TOTAL 50 > #define DUMP_CODE_BYTES_BACKWARD 20 > > diff --git a/target-i386/monitor.c b/target-i386/monitor.c > index e775561..fbc9fcd 100644 > --- a/target-i386/monitor.c > +++ b/target-i386/monitor.c > @@ -492,3 +492,9 @@ const MonitorDef *target_monitor_defs(void) > { > return monitor_defs; > } > + > +void hmp_info_apic_local(Monitor *mon, const QDict *qdict) > +{ > + x86_cpu_dump_apic_local_state(mon_get_cpu(), (FILE *)mon, > monitor_fprintf, > + CPU_DUMP_FPU); > +} >