xref: /illumos-gate/usr/src/cmd/mdb/i86pc/modules/apix/apix.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2018 Joyent, Inc.
24  */
25 
26 #include "intr_common.h"
27 
28 /*
29  * Globals
30  */
31 static apic_irq_t	*irq_tbl[APIC_MAX_VECTOR+1];
32 static char		level_tbl[APIC_MAX_VECTOR+1];
33 static apix_impl_t *d_apixs[NCPU];
34 static int d_ncpus = NCPU;
35 
36 
37 /*
38  * Dump interrupt information for apix PSM.
39  */
40 /* ARGSUSED */
41 int
42 interrupt_dump_apix(uintptr_t addr, uint_t flags, int argc,
43     const mdb_arg_t *argv)
44 {
45 	int i, j;
46 	apix_impl_t apix;
47 	apix_vector_t apix_vector;
48 	struct autovec av;
49 	apic_irq_t apic_irq;
50 
51 	option_flags = 0;
52 	if (mdb_getopts(argc, argv,
53 	    'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags,
54 	    'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags,
55 	    NULL) != argc)
56 		return (DCMD_USAGE);
57 
58 	if (mdb_readvar(&d_apixs, "apixs") == -1) {
59 		mdb_warn("failed to read apixs");
60 		return (DCMD_ERR);
61 	}
62 
63 	if (mdb_readvar(&d_ncpus, "apic_nproc") == -1) {
64 		mdb_warn("failed to read apic_nproc");
65 		d_ncpus = NCPU;
66 	}
67 	if (d_ncpus == 0 || d_ncpus > NCPU)
68 		d_ncpus = NCPU;
69 
70 	if (mdb_readvar(&irq_tbl, "apic_irq_table") == -1) {
71 		mdb_warn("failed to read apic_irq_table");
72 		return (DCMD_ERR);
73 	}
74 
75 	if (mdb_readvar(&level_tbl, "apic_level_intr") == -1) {
76 		mdb_warn("failed to read apic_level_intr");
77 		return (DCMD_ERR);
78 	}
79 
80 	/* Print the header first */
81 	if (option_flags & INTR_DISPLAY_INTRSTAT)
82 		mdb_printf("%<u>CPU ");
83 	else
84 		mdb_printf("%<u>CPU/Vect  IRQ IPL Bus    Trg Type   "
85 		    "Share APIC/INT# ");
86 	mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ?
87 	    "Driver Name(s)" : "ISR");
88 
89 	/* Walk all the entries */
90 	for (i = 0; i < d_ncpus; i++) {
91 		/* Read the per CPU apix entry */
92 		if (mdb_vread(&apix, sizeof (apix_impl_t),
93 		    (uintptr_t)d_apixs[i]) == -1)
94 			continue;
95 		for (j = 0; j < APIX_NVECTOR; j++) {
96 			/* Read the vector entry */
97 			if (mdb_vread(&apix_vector, sizeof (apix_vector_t),
98 			    (uintptr_t)apix.x_vectbl[j]) == -1)
99 				continue;
100 			/* If invalid vector state; continue */
101 			if (apix_vector.v_state == APIX_STATE_FREED ||
102 			    apix_vector.v_state == APIX_STATE_OBSOLETED)
103 				continue;
104 			if (apix_vector.v_type == APIX_TYPE_IPI)
105 				continue;
106 			if (mdb_vread(&av, sizeof (struct autovec),
107 			    (uintptr_t)(apix_vector.v_autovect)) == -1)
108 				continue;
109 			if ((apix_vector.v_type == APIX_TYPE_FIXED) &&
110 			    (mdb_vread(&apic_irq, sizeof (apic_irq_t),
111 			    (uintptr_t)irq_tbl[apix_vector.v_inum]) == -1))
112 				continue;
113 
114 			apix_interrupt_dump(&apix_vector, &apic_irq, &av,
115 			    NULL, level_tbl[apix_vector.v_inum]);
116 		}
117 	}
118 	/* print IPIs */
119 	if (mdb_vread(&apix, sizeof (apix_impl_t),
120 	    (uintptr_t)d_apixs[0]) != -1) {
121 		for (j = 0; j < APIX_NVECTOR; j++) {
122 			/* Read the vector entry */
123 			if (mdb_vread(&apix_vector, sizeof (apix_vector_t),
124 			    (uintptr_t)apix.x_vectbl[j]) == -1)
125 				continue;
126 			/* If invalid vector state; continue */
127 			if (apix_vector.v_state == APIX_STATE_FREED ||
128 			    apix_vector.v_state == APIX_STATE_OBSOLETED)
129 				continue;
130 			if (apix_vector.v_type != APIX_TYPE_IPI)
131 				continue;
132 			if (mdb_vread(&av, sizeof (struct autovec),
133 			    (uintptr_t)(apix_vector.v_autovect)) == -1) {
134 				/* v_share for poke_cpu is 0 */
135 				if (apix_vector.v_share != 0)
136 					continue;
137 			}
138 			apix_interrupt_ipi_dump(&apix_vector, &av, NULL);
139 		}
140 	}
141 
142 	return (DCMD_OK);
143 }
144 
145 /*
146  * MDB module linkage information:
147  *
148  * We declare a list of structures describing our dcmds, and a function
149  * named _mdb_init to return a pointer to our module information.
150  */
151 static const mdb_dcmd_t dcmds[] = {
152 	{ "interrupts", "?[-di]", "print interrupts", interrupt_dump_apix,
153 	    interrupt_help},
154 	{ "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump,
155 	    soft_interrupt_help},
156 #ifdef _KMDB
157 	{ "apic", NULL, "print apic register contents", apic },
158 	{ "ioapic", NULL, "print ioapic register contents", ioapic },
159 #endif /* _KMDB */
160 	{ NULL }
161 };
162 
163 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL };
164 
165 const mdb_modinfo_t *
166 _mdb_init(void)
167 {
168 	GElf_Sym	sym;
169 
170 	if (mdb_lookup_by_name("gld_intr", &sym) != -1)
171 		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
172 			gld_intr_addr = (uintptr_t)sym.st_value;
173 
174 	if (mdb_readvar(&apic_pir_vect, "apic_pir_vect") == -1) {
175 		apic_pir_vect = -1;
176 	}
177 
178 	return (&modinfo);
179 }
180