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
interrupt_dump_apix(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 *
_mdb_init(void)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