xref: /illumos-gate/usr/src/uts/sparc/os/obpsym.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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