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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "intr_common.h" 29 30 /* 31 * Globals 32 */ 33 static struct av_head avec_tbl[APIC_MAX_VECTOR+1]; 34 static apic_irq_t *irq_tbl[APIC_MAX_VECTOR+1], airq; 35 static char level_tbl[APIC_MAX_VECTOR+1]; 36 37 /* 38 * interrupt_dump: 39 * 40 * Dump interrupt information. 41 */ 42 /* ARGSUSED */ 43 int 44 interrupt_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 45 { 46 int i; 47 48 option_flags = 0; 49 if (mdb_getopts(argc, argv, 50 'd', MDB_OPT_SETBITS, INTR_DISPLAY_DRVR_INST, &option_flags, 51 'i', MDB_OPT_SETBITS, INTR_DISPLAY_INTRSTAT, &option_flags, 52 NULL) != argc) 53 return (DCMD_USAGE); 54 55 if (mdb_readvar(&irq_tbl, "apic_irq_table") == -1) { 56 mdb_warn("failed to read apic_irq_table"); 57 return (DCMD_ERR); 58 } 59 60 if (mdb_readvar(&level_tbl, "apic_level_intr") == -1) { 61 mdb_warn("failed to read apic_level_intr"); 62 return (DCMD_ERR); 63 } 64 65 if (mdb_readvar(&avec_tbl, "autovect") == -1) { 66 mdb_warn("failed to read autovect"); 67 return (DCMD_ERR); 68 } 69 70 /* Print the header first */ 71 if (option_flags & INTR_DISPLAY_INTRSTAT) 72 mdb_printf("%<u>CPU "); 73 else 74 mdb_printf( 75 "%<u>IRQ Vect IPL Bus Trg Type CPU Share APIC/INT# "); 76 mdb_printf("%s %</u>\n", option_flags & INTR_DISPLAY_DRVR_INST ? 77 "Driver Name(s)" : "ISR(s)"); 78 79 /* Walk all the entries */ 80 for (i = 0; i < APIC_MAX_VECTOR + 1; i++) { 81 /* Read the entry */ 82 if (mdb_vread(&airq, sizeof (apic_irq_t), 83 (uintptr_t)irq_tbl[i]) == -1) 84 continue; 85 86 apic_interrupt_dump(&airq, &avec_tbl[i], i, NULL, level_tbl[i]); 87 } 88 89 return (DCMD_OK); 90 } 91 92 /* Macros for reading/writing the IOAPIC RDT entries */ 93 #define READ_IOAPIC_RDT_ENTRY_LOW_DWORD(ioapic_ix, ipin) \ 94 ioapic_read(ioapic_ix, APIC_RDT_CMD + (2 * (ipin))) 95 96 #define READ_IOAPIC_RDT_ENTRY_HIGH_DWORD(ioapic_ix, ipin) \ 97 ioapic_read(ioapic_ix, APIC_RDT_CMD2 + (2 * (ipin))) 98 99 static uint32_t *ioapic_adr[MAX_IO_APIC]; 100 101 uint32_t 102 ioapic_read(int ioapic_ix, uint32_t reg) 103 { 104 volatile uint32_t *ioapic; 105 106 ioapic = ioapic_adr[ioapic_ix]; 107 ioapic[APIC_IO_REG] = reg; 108 return (ioapic[APIC_IO_DATA]); 109 } 110 111 /* 112 * ioapic dcmd - Print out the ioapic registers, nicely formatted. 113 */ 114 /*ARGSUSED*/ 115 static int 116 ioapic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 117 { 118 uint32_t apic_io_max; 119 int reg; 120 int reg_max; 121 int i; 122 123 124 if ((flags & DCMD_ADDRSPEC) || argc != 0) 125 return (DCMD_USAGE); 126 127 if (mdb_readvar(&ioapic_adr, "apicioadr") == -1) { 128 /* 129 * If the mdb_warn string does not end in a \n, mdb will 130 * automatically append the reason for the failure. 131 */ 132 mdb_warn("failed to read ioapicadr"); 133 return (DCMD_ERR); 134 } 135 136 if (mdb_readvar(&apic_io_max, "apic_io_max") == -1) { 137 /* 138 * If the mdb_warn string does not end in a \n, mdb will 139 * automatically append the reason for the failure. 140 */ 141 mdb_warn("failed to read apic_io_max"); 142 return (DCMD_ERR); 143 } 144 145 mdb_printf("ioapicadr\t%p\n", ioapic_adr); 146 147 for (i = 0; i < apic_io_max; i++) { 148 /* Bits 23-16 define the maximum redirection entries */ 149 reg_max = ioapic_read(i, APIC_VERS_CMD); 150 reg_max = (reg_max >> 16) & 0xff; 151 152 mdb_printf("%4s %8s %8s\n", "reg", "high", " low"); 153 for (reg = 0; reg <= reg_max; reg++) { 154 uint32_t high, low; 155 156 high = READ_IOAPIC_RDT_ENTRY_HIGH_DWORD(i, reg); 157 low = READ_IOAPIC_RDT_ENTRY_LOW_DWORD(i, reg); 158 159 mdb_printf("%2d %8x %8x\n", reg, high, low); 160 } 161 162 mdb_printf("\n"); 163 164 } 165 166 return (DCMD_OK); 167 } 168 169 170 /* 171 * apic dcmd - Print out the apic registers, nicely formatted. 172 */ 173 /*ARGSUSED*/ 174 static int 175 apic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 176 { 177 uint32_t *papic; 178 179 if ((flags & DCMD_ADDRSPEC) || argc != 0) 180 return (DCMD_USAGE); 181 182 if (mdb_readvar(&papic, "apicadr") == -1) { 183 /* 184 * If the mdb_warn string does not end in a \n, mdb will 185 * automatically append the reason for the failure. 186 */ 187 mdb_warn("failed to read apicadr"); 188 return (DCMD_ERR); 189 } 190 191 mdb_printf("apicadr\t%p\n", papic); 192 mdb_printf("as_task_reg\t%x\n", papic[APIC_TASK_REG]); 193 mdb_printf("as_dest_reg\t%x\n", papic[APIC_DEST_REG]); 194 mdb_printf("as_format_reg\t%x\n", papic[APIC_FORMAT_REG]); 195 mdb_printf("as_local_timer\t%x\n", papic[APIC_LOCAL_TIMER]); 196 mdb_printf("as_pcint_vect\t%x\n", papic[APIC_PCINT_VECT]); 197 mdb_printf("as_int_vect0\t%x\n", papic[APIC_INT_VECT0]); 198 mdb_printf("as_int_vect1\t%x\n", papic[APIC_INT_VECT1]); 199 mdb_printf("as_err_vect\t%x\n", papic[APIC_ERR_VECT]); 200 mdb_printf("as_init_count\t%x\n", papic[APIC_INIT_COUNT]); 201 mdb_printf("as_divide_reg\t%x\n", papic[APIC_DIVIDE_REG]); 202 mdb_printf("as_spur_int_reg\t%x\n", papic[APIC_SPUR_INT_REG]); 203 204 return (DCMD_OK); 205 } 206 207 208 /* 209 * MDB module linkage information: 210 * 211 * We declare a list of structures describing our dcmds, and a function 212 * named _mdb_init to return a pointer to our module information. 213 */ 214 static const mdb_dcmd_t dcmds[] = { 215 { "interrupts", "?[-di]", "print interrupts", interrupt_dump, 216 interrupt_help}, 217 { "softint", "?[-d]", "print soft interrupts", soft_interrupt_dump, 218 soft_interrupt_help}, 219 { "apic", NULL, "print apic register contents", apic }, 220 { "ioapic", NULL, "print ioapic register contents", ioapic }, 221 { NULL } 222 }; 223 224 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL }; 225 226 const mdb_modinfo_t * 227 _mdb_init(void) 228 { 229 GElf_Sym sym; 230 231 if (mdb_lookup_by_name("gld_intr", &sym) != -1) 232 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC) 233 gld_intr_addr = (uintptr_t)sym.st_value; 234 235 return (&modinfo); 236 } 237