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