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