[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 6/9] hmp: added local apic dump state
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH 6/9] hmp: added local apic dump state |
Date: |
Tue, 15 Sep 2015 12:20:25 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0 |
On 15/09/2015 11:23, Denis V. Lunev wrote:
> From: Pavel Butsykin <address@hidden>
>
> 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 <address@hidden>
> Signed-off-by: Denis V. Lunev <address@hidden>
> CC: Andreas Färber <address@hidden>
> CC: Paolo Bonzini <address@hidden>
> ---
> 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
> address@hidden info apic-local
> address@hidden 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);
> +}
>
- [Qemu-devel] [PATCH v2 0/9] hmp command IO- and Local APIC dump state, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 1/9] apic_internal.h: move apic_get_bit(), apic_set_bit() to apic_internal.h, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 4/9] apic_internal.h: fix formatting and drop unused consts, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 2/9] apic_internal.h: rename ESR_ILLEGAL_ADDRESS to APIC_ESR_ILLEGAL_ADDRESS, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 7/9] ioapic_internal.h: added more constants, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 5/9] monitor: make monitor_fprintf and mon_get_cpu externally visible, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 3/9] apic_internal.h: added more constants, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 6/9] hmp: added local apic dump state, Denis V. Lunev, 2015/09/15
- Re: [Qemu-devel] [PATCH 6/9] hmp: added local apic dump state,
Paolo Bonzini <=
- [Qemu-devel] [PATCH 9/9] hmp: implemented io apic dump state for TCG, Denis V. Lunev, 2015/09/15
- [Qemu-devel] [PATCH 8/9] hmp: added io apic dump state, Denis V. Lunev, 2015/09/15