4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2013 by Delphix. All rights reserved.
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_ks.h>
31 #include <mdb/mdb_ctf.h>
32 #include <sys/evtchn_impl.h>
34 #include <sys/xc_levels.h>
36 #include "intr_common.h"
38 typedef struct mdb_shared_info
{
39 unsigned long evtchn_pending
[sizeof (unsigned long) * NBBY
];
40 unsigned long evtchn_mask
[sizeof (unsigned long) * NBBY
];
43 static mdb_shared_info_t shared_info
;
44 static int have_shared_info
;
45 static uintptr_t evtchn_cpus_addr
;
46 static struct av_head avec_tbl
[NR_IRQS
];
47 static irq_info_t irq_tbl
[NR_IRQS
];
48 static mec_info_t ipi_tbl
[MAXIPL
];
49 static mec_info_t virq_tbl
[NR_VIRQS
];
50 static short evtchn_tbl
[NR_EVENT_CHANNELS
];
51 static apic_irq_t
*apic_irq_tbl
[APIC_MAX_VECTOR
+1];
52 static char level_tbl
[APIC_MAX_VECTOR
+1];
58 uintptr_t shared_info_addr
;
60 if (mdb_readvar(&irq_tbl
, "irq_info") == -1) {
61 mdb_warn("failed to read irq_info");
65 if (mdb_readvar(&ipi_tbl
, "ipi_info") == -1) {
66 mdb_warn("failed to read ipi_info");
70 if (mdb_readvar(&avec_tbl
, "autovect") == -1) {
71 mdb_warn("failed to read autovect");
75 if (mdb_readvar(&irq_tbl
, "irq_info") == -1) {
76 mdb_warn("failed to read irq_info");
80 if (mdb_readvar(&ipi_tbl
, "ipi_info") == -1) {
81 mdb_warn("failed to read ipi_info");
85 if (mdb_readvar(&virq_tbl
, "virq_info") == -1) {
86 mdb_warn("failed to read virq_info");
90 if (mdb_readvar(&evtchn_tbl
, "evtchn_to_irq") == -1) {
91 mdb_warn("failed to read evtchn_to_irq");
95 if (mdb_readvar(&apic_irq_tbl
, "apic_irq_table") == -1) {
96 mdb_warn("failed to read apic_irq_table");
100 if (mdb_readvar(&level_tbl
, "apic_level_intr") == -1) {
101 mdb_warn("failed to read apic_level_intr");
105 if (mdb_lookup_by_name("evtchn_cpus", &sym
) == -1) {
106 mdb_warn("failed to lookup evtchn_cpus");
110 evtchn_cpus_addr
= sym
.st_value
;
112 if (mdb_readvar(&shared_info_addr
, "HYPERVISOR_shared_info") == -1) {
113 mdb_warn("failed to read HYPERVISOR_shared_info");
118 * It's normal for this to fail with a domain dump.
120 if (mdb_ctf_vread(&shared_info
, "shared_info_t", "mdb_shared_info_t",
121 shared_info_addr
, MDB_CTF_VREAD_QUIET
) != -1)
122 have_shared_info
= 1;
132 for (i
= 0; i
< NR_VIRQS
; i
++) {
133 if (virq_tbl
[i
].mi_irq
== irq
)
139 return ("virq:timer");
141 return ("virq:debug");
143 return ("virq:console");
145 return ("virq:dom exc");
147 return ("virq:debugger");
158 irq_type(int irq
, int extended
)
160 switch (irq_tbl
[irq
].ii_type
) {
167 return (virq_type(irq
));
173 case IRQT_DEV_EVTCHN
:
181 * We need a non-trivial IPL lookup as the CPU poke's IRQ doesn't have ii_ipl
182 * set -- see evtchn.h.
189 if (irq_tbl
[irq
].ii_u2
.ipl
!= 0)
190 return (irq_tbl
[irq
].ii_u2
.ipl
);
192 for (i
= 0; i
< MAXIPL
; i
++) {
193 if (ipi_tbl
[i
].mi_irq
== irq
) {
202 print_cpu(irq_info_t
*irqp
, int evtchn
)
204 size_t cpuset_size
= BT_BITOUL(NCPU
) * sizeof (ulong_t
);
208 switch (irqp
->ii_type
) {
214 case IRQT_DEV_EVTCHN
:
223 if (evtchn
>= NR_EVENT_CHANNELS
|| evtchn
== 0) {
228 cpu
= mdb_cpuset_find(evtchn_cpus_addr
+
229 (cpuset_size
* evtchn
));
232 * XXPV: we should verify this against the CPU's mask and show
233 * something if they don't match.
235 mdb_printf("%-4d", cpu
);
241 if (avec_tbl
[i
].avh_link
!= NULL
) {
244 (void) mdb_vread(&avhp
, sizeof (struct autovec
),
245 (uintptr_t)avec_tbl
[i
].avh_link
);
247 interrupt_print_isr((uintptr_t)avhp
.av_vector
,
248 (uintptr_t)avhp
.av_intarg1
, (uintptr_t)avhp
.av_dip
);
249 } else if (irq_ipl(i
) == XC_CPUPOKE_PIL
) {
250 mdb_printf("poke_cpu");
257 return (!!TEST_EVTCHN_BIT(i
, &shared_info
.evtchn_mask
[0]));
261 evtchn_pending(int i
)
263 return (!!TEST_EVTCHN_BIT(i
, &shared_info
.evtchn_pending
[0]));
266 typedef struct mdb_xpv_psm_autovec
{
268 } mdb_xpv_psm_autovec_t
;
275 struct dev_info dev_info
;
276 mdb_xpv_psm_autovec_t avhp
;
278 if (mdb_ctf_vread(&avhp
, "struct autovec", "mdb_xpv_psm_autovec_t",
279 (uintptr_t)avec_tbl
[irq
].avh_link
, MDB_CTF_VREAD_QUIET
) == -1)
282 dip_addr
= (uintptr_t)avhp
.av_dip
;
284 if (dip_addr
== (uintptr_t)NULL
)
288 * Sigh. As a result of the perennial confusion of how you do opaque
289 * handles, dev_info_t has a funny old type, which means we can't use
290 * mdb_ctf_vread() here.
293 if (mdb_vread(&dev_info
, sizeof (struct dev_info
), dip_addr
) == -1)
296 dip_addr
= (uintptr_t)dev_info
.devi_parent
;
298 if (mdb_vread(&dev_info
, sizeof (struct dev_info
), dip_addr
) == -1)
301 if (mdb_readstr(parent
, 7, (uintptr_t)dev_info
.devi_node_name
) == -1)
304 mdb_printf("%-6s ", parent
);
312 ec_interrupt_dump(int i
)
314 irq_info_t
*irqp
= &irq_tbl
[i
];
317 if (irqp
->ii_type
== IRQT_UNBOUND
)
320 if (option_flags
& INTR_DISPLAY_INTRSTAT
) {
321 print_cpu(irqp
, irqp
->ii_u
.evtchn
);
327 switch (irqp
->ii_type
) {
330 if (irqp
->ii_u
.index
== VIRQ_TIMER
) {
333 mdb_snprintf(evtchn
, sizeof (evtchn
), "%-7d",
340 case IRQT_DEV_EVTCHN
:
346 mdb_printf("%3d ", i
);
350 mdb_printf("%-7s", evtchn
);
352 mdb_printf("%-4d", irq_ipl(i
));
356 mdb_printf("%-4s", "Edg");
358 mdb_printf("%-7s", irq_type(i
, 0));
360 print_cpu(irqp
, irqp
->ii_u
.evtchn
);
373 interrupts_dump(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
378 if (mdb_getopts(argc
, argv
,
379 'd', MDB_OPT_SETBITS
, INTR_DISPLAY_DRVR_INST
, &option_flags
,
380 'i', MDB_OPT_SETBITS
, INTR_DISPLAY_INTRSTAT
, &option_flags
,
384 if (!update_tables())
387 if (option_flags
& INTR_DISPLAY_INTRSTAT
) {
388 mdb_printf("%<u>CPU ");
390 mdb_printf("%<u>IRQ Vect Evtchn IPL Bus Trg Type "
391 "CPU Share APIC/INT# ");
393 mdb_printf("%s %</u>\n", option_flags
& INTR_DISPLAY_DRVR_INST
?
394 "Driver Name(s)" : "ISR(s)");
396 for (i
= 0; i
< NR_IRQS
; i
++) {
397 if (irq_tbl
[i
].ii_type
== IRQT_PIRQ
) {
400 if (irq_tbl
[i
].ii_u
.evtchn
== 0)
403 if (mdb_vread(&airq
, sizeof (apic_irq_t
),
404 (uintptr_t)apic_irq_tbl
[i
]) == -1)
407 apic_interrupt_dump(&airq
, &avec_tbl
[i
], i
,
408 &irq_tbl
[i
].ii_u
.evtchn
, level_tbl
[i
]);
412 ec_interrupt_dump(i
);
421 int irq
= evtchn_tbl
[i
];
423 if (irq
== INVALID_IRQ
) {
424 mdb_printf("%-14s%-7d%-4s%-4s", "unassigned", i
, "-", "-");
426 if (have_shared_info
) {
427 mdb_printf("%-7d", evtchn_masked(i
));
428 mdb_printf("%-8d", evtchn_pending(i
));
435 mdb_printf("%-14s", irq_type(irq
, 1));
437 mdb_printf("%-7d", i
);
439 mdb_printf("%-4d", irq
);
441 mdb_printf("%-4d", irq_ipl(irq
));
444 if (have_shared_info
) {
446 mdb_printf("%-7d", evtchn_masked(i
));
447 mdb_printf("%-8d", evtchn_pending(i
));
457 evtchns_dump(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
462 if (mdb_getopts(argc
, argv
,
463 'd', MDB_OPT_SETBITS
, INTR_DISPLAY_DRVR_INST
, &option_flags
,
467 if (!update_tables())
470 if (flags
& DCMD_ADDRSPEC
) {
472 * Note: we allow the invalid evtchn 0, as it can help catch if
473 * we incorrectly try to configure it.
475 if ((int)addr
>= NR_EVENT_CHANNELS
) {
476 mdb_warn("Invalid event channel %d.\n", (int)addr
);
481 mdb_printf("%<u>Type Evtchn IRQ IPL CPU ");
482 if (have_shared_info
)
483 mdb_printf("Masked Pending ");
485 mdb_printf("%s %</u>\n", option_flags
& INTR_DISPLAY_DRVR_INST
?
486 "Driver Name(s)" : "ISR(s)");
488 if (flags
& DCMD_ADDRSPEC
) {
489 evtchn_dump((int)addr
);
493 for (i
= 0; i
< NR_EVENT_CHANNELS
; i
++) {
494 if (evtchn_tbl
[i
] == INVALID_IRQ
)
506 mdb_printf("Print valid event channels\n"
507 "If %<u>addr%</u> is given, interpret it as an evtchn to print "
509 "By default, only interrupt service routine names are printed.\n\n"
511 " -d instead of ISR, print <driver_name><instance#>\n");
514 static const mdb_dcmd_t dcmds
[] = {
515 { "interrupts", "?[-di]", "print interrupts", interrupts_dump
,
517 { "evtchns", "?[-d]", "print event channels", evtchns_dump
,
519 { "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump
,
520 soft_interrupt_help
},
524 static const mdb_modinfo_t modinfo
= { MDB_API_VERSION
, dcmds
, NULL
};
526 const mdb_modinfo_t
*
531 if (mdb_lookup_by_name("gld_intr", &sym
) != -1)
532 if (GELF_ST_TYPE(sym
.st_info
) == STT_FUNC
)
533 gld_intr_addr
= (uintptr_t)sym
.st_value
;