obpsym.c revision 5493:e4ed5a40720a
1272343Sngie/*
2272343Sngie * CDDL HEADER START
3272343Sngie *
4272343Sngie * The contents of this file are subject to the terms of the
5272343Sngie * Common Development and Distribution License (the "License").
6272343Sngie * You may not use this file except in compliance with the License.
7272343Sngie *
8272343Sngie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9272343Sngie * or http://www.opensolaris.org/os/licensing.
10272343Sngie * See the License for the specific language governing permissions
11272343Sngie * and limitations under the License.
12272343Sngie *
13272343Sngie * When distributing Covered Code, include this CDDL HEADER in each
14272343Sngie * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15272343Sngie * If applicable, add the following below this CDDL HEADER, with the
16272343Sngie * fields enclosed by brackets "[]" replaced with your own identifying
17272343Sngie * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2007 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.  The module is loaded automatically
39 * on cobp systems and is replaced by forthdebug on all other systems.
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
59int 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
65int obpheld = 1;		/* Prevents unloading when set */
66
67/*
68 * name_to_value - translate a string into an address
69 *
70 * The string may be one of two forms - 'symname' or 'modname:symname'.
71 * (We also accept 'unix:symname' as a synonymn for 'symname'.)
72 * The latter form causes a kobj_lookup() to occur only in the given module,
73 * the former causes a kobj_getsymvalue() on the entire kernel symbol table.
74 *
75 * mod_lock locking is not needed for the &modules list because
76 * modctl structures are never unlinked from the &modules list.
77 */
78int
79name_to_value(char *name, uintptr_t *value)
80{
81	register char *symname = name;
82	register char *modname = "";
83	char *p;
84	int retval = 0;
85	uintptr_t symvalue = 0;
86	char c = (char)0;
87
88	/*
89	 * we take names of the form: "modname:symbol", "unix:symbol", "symbol"
90	 */
91	if ((p = strchr(name, ':')) != NULL && p[1] != (char)0) {
92		symname = p + 1;
93		modname = name;
94		c = *p;
95		*p = (char)0;
96	}
97
98	if (*modname == (char)0) {
99		symvalue = kobj_getsymvalue(symname, 0);
100	} else  {
101		struct modctl *mp = &modules;
102
103		do {
104			if (strcmp(modname, mp->mod_modname) == 0) {
105				symvalue = kobj_lookup(mp->mod_mp, symname);
106				break;
107			}
108		} while ((mp = mp->mod_next) != &modules);
109	}
110
111	if (symvalue == 0)
112		retval = -1;
113	if (c != (char)0)		/* Restore incoming cstr */
114		*p = c;
115
116	*value = symvalue;
117	return (retval);
118}
119
120/*
121 * value_to_name - translate an address into a string + offset
122 *
123 * mod_lock locking is not needed fro the modules list because
124 * modctl structures are never unlinked from the &modules list.
125 */
126ulong_t
127value_to_name(uintptr_t value, char *symbol)
128{
129	struct modctl *modp = &modules;
130	ulong_t offset;
131	char *name;
132
133	DPRINTF1("value_to_name: Looking for %p\n", (void *)value);
134
135	do {
136		if (modp->mod_mp &&
137		    (name = kobj_searchsym(modp->mod_mp, value, &offset))) {
138			(void) strcpy(symbol, modp->mod_modname);
139			(void) strcat(symbol, ":");
140			(void) strcat(symbol, name);
141			return (offset);
142		}
143	} while ((modp = modp->mod_next) != &modules);
144
145	*symbol = (char)0;
146	return ((ulong_t)-1l);
147}
148
149/*
150 * loadable module wrapper
151 */
152static struct modlmisc modlmisc = {
153	&mod_miscops, "OBP symbol callbacks %I%"
154};
155
156static struct modlinkage modlinkage = {
157	MODREV_1, (void *)&modlmisc, NULL
158};
159
160/*ARGSUSED*/
161static boolean_t
162reset_callbacks(void *arg, int code)
163{
164	extern void set_sym_callbacks();
165
166	if (code == CB_CODE_CPR_RESUME)
167		set_sym_callbacks();
168	return (B_TRUE);
169}
170
171int
172_init(void)
173{
174	int retval;
175	extern int install_callbacks(void);
176	extern void remove_callbacks(void);
177
178	if (install_callbacks() != 0)
179		return (ENXIO);
180
181	if (boothowto & RB_HALT)
182		debug_enter("obpsym: halt flag (-h) is set.\n");
183
184	retval = mod_install(&modlinkage);
185
186	/*
187	 * if load fails remove callback and unlock symbols
188	 */
189	if (retval) {
190		printf("obpsym: Error %d installing OBP syms module\n", retval);
191		remove_callbacks();
192	}
193	else
194		(void) callb_add(reset_callbacks, 0, CB_CL_CPR_OBP, "obpsym");
195
196	return (retval);
197}
198
199int
200_fini(void)
201{
202	int retval;
203	extern void remove_callbacks(void);
204
205	if (obpheld != 0)
206		return (EBUSY);
207
208	retval = mod_remove(&modlinkage);
209
210	/*
211	 * if unload succeeds remove callback and unlock symbols
212	 */
213	if (retval == 0) {
214		remove_callbacks();
215	}
216	return (retval);
217}
218
219int
220_info(struct modinfo *modinfop)
221{
222	return (mod_info(&modlinkage, modinfop));
223}
224