10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*1048Sraf 230Sstevel@tonic-gate /* 24*1048Sraf * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * This module supports callbacks from the firmware 320Sstevel@tonic-gate * such that address and name lookups can work and use kernel symbol names. 330Sstevel@tonic-gate * For example "ctrace" will provide symbolic names, if they are available. 340Sstevel@tonic-gate * Also, normal firmware name to address lookups should work, though be 350Sstevel@tonic-gate * careful with clashing kernel names, such as "startup" and "reset" which 360Sstevel@tonic-gate * may be the firmware names and *not* the kernel names. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * The module locks the symbol tables in memory, when it's installed, 390Sstevel@tonic-gate * and unlocks them when it is removed. To install the module, you 400Sstevel@tonic-gate * may either add "set obpdebug=1" to /etc/system or just modload it. 410Sstevel@tonic-gate * 420Sstevel@tonic-gate * This file contains the actual code the does the lookups, and interfaces 430Sstevel@tonic-gate * with the kernel kobj stuff. The transfer of data and control to/from 440Sstevel@tonic-gate * the firmware is handled in prom-dependent code. 450Sstevel@tonic-gate */ 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <sys/types.h> 480Sstevel@tonic-gate #include <sys/param.h> 490Sstevel@tonic-gate #include <sys/systm.h> 500Sstevel@tonic-gate #include <sys/debug.h> 510Sstevel@tonic-gate #include <sys/errno.h> 520Sstevel@tonic-gate #include <sys/modctl.h> 530Sstevel@tonic-gate #include <sys/kobj.h> 540Sstevel@tonic-gate #include <sys/promif.h> 550Sstevel@tonic-gate #include <sys/ddi.h> 560Sstevel@tonic-gate #include <sys/sunddi.h> 570Sstevel@tonic-gate #include <sys/reboot.h> 580Sstevel@tonic-gate #include <sys/callb.h> 590Sstevel@tonic-gate 600Sstevel@tonic-gate int obpsym_debug = 0; 610Sstevel@tonic-gate #define DPRINTF(str) if (obpsym_debug) prom_printf(str) 620Sstevel@tonic-gate #define DPRINTF1(str, a) if (obpsym_debug) prom_printf(str, a); 630Sstevel@tonic-gate #define DPRINTF2(str, a, b) if (obpsym_debug) prom_printf(str, a, b); 640Sstevel@tonic-gate #define DXPRINTF if (obpsym_debug > 1) prom_printf 650Sstevel@tonic-gate 660Sstevel@tonic-gate int obpheld = 1; /* Prevents unloading when set */ 670Sstevel@tonic-gate extern int obpdebug; 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * name_to_value - translate a string into an address 710Sstevel@tonic-gate * 720Sstevel@tonic-gate * The string may be one of two forms - 'symname' or 'modname:symname'. 730Sstevel@tonic-gate * (We also accept 'unix:symname' as a synonymn for 'symname'.) 740Sstevel@tonic-gate * The latter form causes a kobj_lookup() to occur only in the given module, 750Sstevel@tonic-gate * the former causes a kobj_getsymvalue() on the entire kernel symbol table. 760Sstevel@tonic-gate * 770Sstevel@tonic-gate * mod_lock locking is not needed for the &modules list because 780Sstevel@tonic-gate * modctl structures are never unlinked from the &modules list. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate int 810Sstevel@tonic-gate name_to_value(char *name, uintptr_t *value) 820Sstevel@tonic-gate { 830Sstevel@tonic-gate register char *symname = name; 840Sstevel@tonic-gate register char *modname = ""; 850Sstevel@tonic-gate char *p; 860Sstevel@tonic-gate int retval = 0; 870Sstevel@tonic-gate uintptr_t symvalue = 0; 880Sstevel@tonic-gate char c = (char)0; 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * we take names of the form: "modname:symbol", "unix:symbol", "symbol" 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate if ((p = strchr(name, ':')) != NULL && p[1] != (char)0) { 940Sstevel@tonic-gate symname = p + 1; 950Sstevel@tonic-gate modname = name; 960Sstevel@tonic-gate c = *p; 970Sstevel@tonic-gate *p = (char)0; 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate if (*modname == (char)0) { 1010Sstevel@tonic-gate symvalue = kobj_getsymvalue(symname, 0); 1020Sstevel@tonic-gate } else { 1030Sstevel@tonic-gate struct modctl *mp = &modules; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate do { 1060Sstevel@tonic-gate if (strcmp(modname, mp->mod_modname) == 0) { 1070Sstevel@tonic-gate symvalue = kobj_lookup(mp->mod_mp, symname); 1080Sstevel@tonic-gate break; 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate } while ((mp = mp->mod_next) != &modules); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate if (symvalue == 0) 1140Sstevel@tonic-gate retval = -1; 1150Sstevel@tonic-gate if (c != (char)0) /* Restore incoming cstr */ 1160Sstevel@tonic-gate *p = c; 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate *value = symvalue; 1190Sstevel@tonic-gate return (retval); 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate /* 1230Sstevel@tonic-gate * value_to_name - translate an address into a string + offset 1240Sstevel@tonic-gate * 1250Sstevel@tonic-gate * mod_lock locking is not needed fro the modules list because 1260Sstevel@tonic-gate * modctl structures are never unlinked from the &modules list. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate ulong_t 1290Sstevel@tonic-gate value_to_name(uintptr_t value, char *symbol) 1300Sstevel@tonic-gate { 1310Sstevel@tonic-gate struct modctl *modp = &modules; 1320Sstevel@tonic-gate ulong_t offset; 1330Sstevel@tonic-gate char *name; 1340Sstevel@tonic-gate 135*1048Sraf DPRINTF1("value_to_name: Looking for %p\n", (void *)value); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate do { 1380Sstevel@tonic-gate if (modp->mod_mp && 1390Sstevel@tonic-gate (name = kobj_searchsym(modp->mod_mp, value, &offset))) { 1400Sstevel@tonic-gate (void) strcpy(symbol, modp->mod_modname); 1410Sstevel@tonic-gate (void) strcat(symbol, ":"); 1420Sstevel@tonic-gate (void) strcat(symbol, name); 1430Sstevel@tonic-gate return (offset); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate *symbol = (char)0; 1480Sstevel@tonic-gate return ((ulong_t)-1l); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * loadable module wrapper 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate static struct modlmisc modlmisc = { 1550Sstevel@tonic-gate &mod_miscops, "OBP symbol callbacks %I%" 1560Sstevel@tonic-gate }; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate static struct modlinkage modlinkage = { 1590Sstevel@tonic-gate MODREV_1, (void *)&modlmisc, NULL 1600Sstevel@tonic-gate }; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /*ARGSUSED*/ 1630Sstevel@tonic-gate static boolean_t 1640Sstevel@tonic-gate reset_callbacks(void *arg, int code) 1650Sstevel@tonic-gate { 1660Sstevel@tonic-gate extern void set_sym_callbacks(); 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if (code == CB_CODE_CPR_RESUME) 1690Sstevel@tonic-gate set_sym_callbacks(); 1700Sstevel@tonic-gate return (B_TRUE); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate int 1740Sstevel@tonic-gate _init(void) 1750Sstevel@tonic-gate { 1760Sstevel@tonic-gate int retval; 1770Sstevel@tonic-gate extern int install_callbacks(void); 1780Sstevel@tonic-gate extern void remove_callbacks(void); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (install_callbacks() != 0) 1810Sstevel@tonic-gate return (ENXIO); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate obpdebug = 1; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate if (boothowto & RB_HALT) 1860Sstevel@tonic-gate debug_enter("obpsym: halt flag (-h) is set.\n"); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate retval = mod_install(&modlinkage); 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * if load fails remove callback and unlock symbols 1920Sstevel@tonic-gate */ 1930Sstevel@tonic-gate if (retval) { 1940Sstevel@tonic-gate printf("obpsym: Error %d installing OBP syms module\n", retval); 1950Sstevel@tonic-gate remove_callbacks(); 1960Sstevel@tonic-gate obpdebug = 0; 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate else 1990Sstevel@tonic-gate (void) callb_add(reset_callbacks, 0, CB_CL_CPR_OBP, "obpsym"); 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate return (retval); 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate int 2050Sstevel@tonic-gate _fini(void) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate int retval; 2080Sstevel@tonic-gate extern void remove_callbacks(void); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate if (obpheld != 0) 2110Sstevel@tonic-gate return (EBUSY); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate retval = mod_remove(&modlinkage); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * if unload succeeds remove callback and unlock symbols 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate if (retval == 0) { 2190Sstevel@tonic-gate remove_callbacks(); 2200Sstevel@tonic-gate obpdebug = 0; 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate return (retval); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate int 2260Sstevel@tonic-gate _info(struct modinfo *modinfop) 2270Sstevel@tonic-gate { 2280Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2290Sstevel@tonic-gate } 230