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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1991-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This module supports callbacks from the firmware 31 * such that address and name lookups can work and use kernel symbol names. 32 * For example "ctrace" will provide symbolic names, if they are available. 33 * Also, normal firmware name to address lookups should work, though be 34 * careful with clashing kernel names, such as "startup" and "reset" which 35 * may be the firmware names and *not* the kernel names. 36 * 37 * The module locks the symbol tables in memory, when it's installed, 38 * and unlocks them when it is removed. To install the module, you 39 * may either add "set obpdebug=1" to /etc/system or just modload it. 40 * 41 * This file contains the actual code the does the lookups, and interfaces 42 * with the kernel kobj stuff. The transfer of data and control to/from 43 * the firmware is handled in prom-dependent code. 44 */ 45 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/debug.h> 50 #include <sys/errno.h> 51 #include <sys/modctl.h> 52 #include <sys/kobj.h> 53 #include <sys/promif.h> 54 #include <sys/ddi.h> 55 #include <sys/sunddi.h> 56 #include <sys/reboot.h> 57 #include <sys/callb.h> 58 59 int obpsym_debug = 0; 60 #define DPRINTF(str) if (obpsym_debug) prom_printf(str) 61 #define DPRINTF1(str, a) if (obpsym_debug) prom_printf(str, a); 62 #define DPRINTF2(str, a, b) if (obpsym_debug) prom_printf(str, a, b); 63 #define DXPRINTF if (obpsym_debug > 1) prom_printf 64 65 int obpheld = 1; /* Prevents unloading when set */ 66 extern int obpdebug; 67 68 /* 69 * name_to_value - translate a string into an address 70 * 71 * The string may be one of two forms - 'symname' or 'modname:symname'. 72 * (We also accept 'unix:symname' as a synonymn for 'symname'.) 73 * The latter form causes a kobj_lookup() to occur only in the given module, 74 * the former causes a kobj_getsymvalue() on the entire kernel symbol table. 75 * 76 * mod_lock locking is not needed for the &modules list because 77 * modctl structures are never unlinked from the &modules list. 78 */ 79 int 80 name_to_value(char *name, uintptr_t *value) 81 { 82 register char *symname = name; 83 register char *modname = ""; 84 char *p; 85 int retval = 0; 86 uintptr_t symvalue = 0; 87 char c = (char)0; 88 89 /* 90 * we take names of the form: "modname:symbol", "unix:symbol", "symbol" 91 */ 92 if ((p = strchr(name, ':')) != NULL && p[1] != (char)0) { 93 symname = p + 1; 94 modname = name; 95 c = *p; 96 *p = (char)0; 97 } 98 99 if (*modname == (char)0) { 100 symvalue = kobj_getsymvalue(symname, 0); 101 } else { 102 struct modctl *mp = &modules; 103 104 do { 105 if (strcmp(modname, mp->mod_modname) == 0) { 106 symvalue = kobj_lookup(mp->mod_mp, symname); 107 break; 108 } 109 } while ((mp = mp->mod_next) != &modules); 110 } 111 112 if (symvalue == 0) 113 retval = -1; 114 if (c != (char)0) /* Restore incoming cstr */ 115 *p = c; 116 117 *value = symvalue; 118 return (retval); 119 } 120 121 /* 122 * value_to_name - translate an address into a string + offset 123 * 124 * mod_lock locking is not needed fro the modules list because 125 * modctl structures are never unlinked from the &modules list. 126 */ 127 ulong_t 128 value_to_name(uintptr_t value, char *symbol) 129 { 130 struct modctl *modp = &modules; 131 ulong_t offset; 132 char *name; 133 134 DPRINTF1("value_to_name: Looking for %p\n", value); 135 136 do { 137 if (modp->mod_mp && 138 (name = kobj_searchsym(modp->mod_mp, value, &offset))) { 139 (void) strcpy(symbol, modp->mod_modname); 140 (void) strcat(symbol, ":"); 141 (void) strcat(symbol, name); 142 return (offset); 143 } 144 } while ((modp = modp->mod_next) != &modules); 145 146 *symbol = (char)0; 147 return ((ulong_t)-1l); 148 } 149 150 /* 151 * loadable module wrapper 152 */ 153 static struct modlmisc modlmisc = { 154 &mod_miscops, "OBP symbol callbacks %I%" 155 }; 156 157 static struct modlinkage modlinkage = { 158 MODREV_1, (void *)&modlmisc, NULL 159 }; 160 161 /*ARGSUSED*/ 162 static boolean_t 163 reset_callbacks(void *arg, int code) 164 { 165 extern void set_sym_callbacks(); 166 167 if (code == CB_CODE_CPR_RESUME) 168 set_sym_callbacks(); 169 return (B_TRUE); 170 } 171 172 int 173 _init(void) 174 { 175 int retval; 176 extern int install_callbacks(void); 177 extern void remove_callbacks(void); 178 179 if (install_callbacks() != 0) 180 return (ENXIO); 181 182 obpdebug = 1; 183 184 if (boothowto & RB_HALT) 185 debug_enter("obpsym: halt flag (-h) is set.\n"); 186 187 retval = mod_install(&modlinkage); 188 189 /* 190 * if load fails remove callback and unlock symbols 191 */ 192 if (retval) { 193 printf("obpsym: Error %d installing OBP syms module\n", retval); 194 remove_callbacks(); 195 obpdebug = 0; 196 } 197 else 198 (void) callb_add(reset_callbacks, 0, CB_CL_CPR_OBP, "obpsym"); 199 200 return (retval); 201 } 202 203 int 204 _fini(void) 205 { 206 int retval; 207 extern void remove_callbacks(void); 208 209 if (obpheld != 0) 210 return (EBUSY); 211 212 retval = mod_remove(&modlinkage); 213 214 /* 215 * if unload succeeds remove callback and unlock symbols 216 */ 217 if (retval == 0) { 218 remove_callbacks(); 219 obpdebug = 0; 220 } 221 return (retval); 222 } 223 224 int 225 _info(struct modinfo *modinfop) 226 { 227 return (mod_info(&modlinkage, modinfop)); 228 } 229