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