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
51544Seschrock * Common Development and Distribution License (the "License").
61544Seschrock * 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 */
210Sstevel@tonic-gate /*
22*10047SPramod.Batni@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * Kernel's linker/loader
280Sstevel@tonic-gate */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/sysmacros.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/user.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <sys/reboot.h>
370Sstevel@tonic-gate #include <sys/bootconf.h>
380Sstevel@tonic-gate #include <sys/debug.h>
390Sstevel@tonic-gate #include <sys/uio.h>
400Sstevel@tonic-gate #include <sys/file.h>
410Sstevel@tonic-gate #include <sys/vnode.h>
420Sstevel@tonic-gate #include <sys/user.h>
430Sstevel@tonic-gate #include <sys/mman.h>
440Sstevel@tonic-gate #include <vm/as.h>
450Sstevel@tonic-gate #include <vm/seg_kp.h>
460Sstevel@tonic-gate #include <vm/seg_kmem.h>
470Sstevel@tonic-gate #include <sys/elf.h>
480Sstevel@tonic-gate #include <sys/elf_notes.h>
490Sstevel@tonic-gate #include <sys/vmsystm.h>
500Sstevel@tonic-gate #include <sys/kdi.h>
510Sstevel@tonic-gate #include <sys/atomic.h>
520Sstevel@tonic-gate #include <sys/kmdb.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate #include <sys/link.h>
550Sstevel@tonic-gate #include <sys/kobj.h>
560Sstevel@tonic-gate #include <sys/ksyms.h>
570Sstevel@tonic-gate #include <sys/disp.h>
580Sstevel@tonic-gate #include <sys/modctl.h>
590Sstevel@tonic-gate #include <sys/varargs.h>
600Sstevel@tonic-gate #include <sys/kstat.h>
610Sstevel@tonic-gate #include <sys/kobj_impl.h>
625648Ssetje #include <sys/fs/decomp.h>
630Sstevel@tonic-gate #include <sys/callb.h>
640Sstevel@tonic-gate #include <sys/cmn_err.h>
650Sstevel@tonic-gate #include <sys/tnf_probe.h>
665648Ssetje #include <sys/zmod.h>
675648Ssetje
685648Ssetje #include <krtld/reloc.h>
695648Ssetje #include <krtld/kobj_kdi.h>
700Sstevel@tonic-gate #include <sys/sha1.h>
710Sstevel@tonic-gate #include <sys/crypto/elfsign.h>
720Sstevel@tonic-gate
735648Ssetje #if !defined(_OBP)
740Sstevel@tonic-gate #include <sys/bootvfs.h>
750Sstevel@tonic-gate #endif
760Sstevel@tonic-gate
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate * do_symbols() error codes
790Sstevel@tonic-gate */
800Sstevel@tonic-gate #define DOSYM_UNDEF -1 /* undefined symbol */
810Sstevel@tonic-gate #define DOSYM_UNSAFE -2 /* MT-unsafe driver symbol */
820Sstevel@tonic-gate
835648Ssetje #if !defined(_OBP)
843446Smrj static void synthetic_bootaux(char *, val_t *);
855648Ssetje #endif
865648Ssetje
873446Smrj static struct module *load_exec(val_t *, char *);
880Sstevel@tonic-gate static void load_linker(val_t *);
893446Smrj static struct modctl *add_primary(const char *filename, int);
900Sstevel@tonic-gate static int bind_primary(val_t *, int);
910Sstevel@tonic-gate static int load_primary(struct module *, int);
920Sstevel@tonic-gate static int load_kmdb(val_t *);
930Sstevel@tonic-gate static int get_progbits(struct module *, struct _buf *);
940Sstevel@tonic-gate static int get_syms(struct module *, struct _buf *);
950Sstevel@tonic-gate static int get_ctf(struct module *, struct _buf *);
960Sstevel@tonic-gate static void get_signature(struct module *, struct _buf *);
970Sstevel@tonic-gate static int do_common(struct module *);
980Sstevel@tonic-gate static void add_dependent(struct module *, struct module *);
990Sstevel@tonic-gate static int do_dependents(struct modctl *, char *, size_t);
1000Sstevel@tonic-gate static int do_symbols(struct module *, Elf64_Addr);
1010Sstevel@tonic-gate static void module_assign(struct modctl *, struct module *);
1020Sstevel@tonic-gate static void free_module_data(struct module *);
1030Sstevel@tonic-gate static char *depends_on(struct module *);
1043446Smrj static char *getmodpath(const char *);
1050Sstevel@tonic-gate static char *basename(char *);
1060Sstevel@tonic-gate static void attr_val(val_t *);
1070Sstevel@tonic-gate static char *find_libmacro(char *);
1080Sstevel@tonic-gate static char *expand_libmacro(char *, char *, char *);
1090Sstevel@tonic-gate static int read_bootflags(void);
1105648Ssetje static int kobj_comp_setup(struct _buf *, struct compinfo *);
1115648Ssetje static int kobj_uncomp_blk(struct _buf *, caddr_t, uint_t);
1125648Ssetje static int kobj_read_blks(struct _buf *, caddr_t, uint_t, uint_t);
1130Sstevel@tonic-gate static int kobj_boot_open(char *, int);
1140Sstevel@tonic-gate static int kobj_boot_close(int);
1150Sstevel@tonic-gate static int kobj_boot_seek(int, off_t, off_t);
1160Sstevel@tonic-gate static int kobj_boot_read(int, caddr_t, size_t);
1171544Seschrock static int kobj_boot_fstat(int, struct bootstat *);
1185648Ssetje static int kobj_boot_compinfo(int, struct compinfo *);
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate static Sym *lookup_one(struct module *, const char *);
1210Sstevel@tonic-gate static void sym_insert(struct module *, char *, symid_t);
1220Sstevel@tonic-gate static Sym *sym_lookup(struct module *, Sym *);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate static struct kobjopen_tctl *kobjopen_alloc(char *filename);
1250Sstevel@tonic-gate static void kobjopen_free(struct kobjopen_tctl *ltp);
1260Sstevel@tonic-gate static void kobjopen_thread(struct kobjopen_tctl *ltp);
1277858SKrishnendu.Sadhukhan@Sun.COM static int kobj_is_compressed(intptr_t);
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate extern int kcopy(const void *, void *, size_t);
1300Sstevel@tonic-gate extern int elf_mach_ok(Ehdr *);
1310Sstevel@tonic-gate extern int alloc_gottable(struct module *, caddr_t *, caddr_t *);
1320Sstevel@tonic-gate
1335648Ssetje #if !defined(_OBP)
1345648Ssetje extern int kobj_boot_mountroot(void);
1355648Ssetje #endif
1365648Ssetje
1375648Ssetje static void tnf_unsplice_probes(uint_t, struct modctl *);
1385648Ssetje extern tnf_probe_control_t *__tnf_probe_list_head;
1395648Ssetje extern tnf_tag_data_t *__tnf_tag_list_head;
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate extern int modrootloaded;
1420Sstevel@tonic-gate extern int swaploaded;
1430Sstevel@tonic-gate extern int bop_io_quiesced;
1440Sstevel@tonic-gate extern int last_module_id;
1450Sstevel@tonic-gate
1465648Ssetje extern char stubs_base[];
1475648Ssetje extern char stubs_end[];
1485648Ssetje
1490Sstevel@tonic-gate #ifdef KOBJ_DEBUG
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * Values that can be or'd in to kobj_debug and their effects:
1520Sstevel@tonic-gate *
1530Sstevel@tonic-gate * D_DEBUG - misc. debugging information.
1540Sstevel@tonic-gate * D_SYMBOLS - list symbols and their values as they are entered
1550Sstevel@tonic-gate * into the hash table
1560Sstevel@tonic-gate * D_RELOCATIONS - display relocation processing information
1570Sstevel@tonic-gate * D_LOADING - display information about each module as it
1580Sstevel@tonic-gate * is loaded.
1590Sstevel@tonic-gate */
1600Sstevel@tonic-gate int kobj_debug = 0;
1613446Smrj
1623446Smrj #define KOBJ_MARK(s) if (kobj_debug & D_DEBUG) \
1633446Smrj (_kobj_printf(ops, "%d", __LINE__), _kobj_printf(ops, ": %s\n", s))
1643446Smrj #else
1653446Smrj #define KOBJ_MARK(s) /* discard */
1660Sstevel@tonic-gate #endif
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate #define MODPATH_PROPNAME "module-path"
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
1710Sstevel@tonic-gate static char slash_moddir_suffix_slash[] = MODDIR_SUFFIX "/";
1720Sstevel@tonic-gate #else
1730Sstevel@tonic-gate #define slash_moddir_suffix_slash ""
1740Sstevel@tonic-gate #endif
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate #define _moddebug get_weakish_int(&moddebug)
1770Sstevel@tonic-gate #define _modrootloaded get_weakish_int(&modrootloaded)
1780Sstevel@tonic-gate #define _swaploaded get_weakish_int(&swaploaded)
1790Sstevel@tonic-gate #define _ioquiesced get_weakish_int(&bop_io_quiesced)
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate #define mod(X) (struct module *)((X)->modl_modp->mod_mp)
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate void *romp; /* rom vector (opaque to us) */
1840Sstevel@tonic-gate struct bootops *ops; /* bootops vector */
1850Sstevel@tonic-gate void *dbvec; /* debug vector */
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate * kobjopen thread control structure
1890Sstevel@tonic-gate */
1900Sstevel@tonic-gate struct kobjopen_tctl {
1910Sstevel@tonic-gate ksema_t sema;
1920Sstevel@tonic-gate char *name; /* name of file */
1930Sstevel@tonic-gate struct vnode *vp; /* vnode return from vn_open() */
1940Sstevel@tonic-gate int Errno; /* error return from vnopen */
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate * Structure for defining dynamically expandable library macros
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate struct lib_macro_info {
2020Sstevel@tonic-gate char *lmi_list; /* ptr to list of possible choices */
2030Sstevel@tonic-gate char *lmi_macroname; /* pointer to macro name */
2040Sstevel@tonic-gate ushort_t lmi_ba_index; /* index into bootaux vector */
2050Sstevel@tonic-gate ushort_t lmi_macrolen; /* macro length */
2060Sstevel@tonic-gate } libmacros[] = {
2070Sstevel@tonic-gate { NULL, "CPU", BA_CPU, 0 },
2080Sstevel@tonic-gate { NULL, "MMU", BA_MMU, 0 }
2090Sstevel@tonic-gate };
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate #define NLIBMACROS sizeof (libmacros) / sizeof (struct lib_macro_info)
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate char *boot_cpu_compatible_list; /* make $CPU available */
2140Sstevel@tonic-gate
2153446Smrj char *kobj_module_path; /* module search path */
2160Sstevel@tonic-gate vmem_t *text_arena; /* module text arena */
2170Sstevel@tonic-gate static vmem_t *data_arena; /* module data & bss arena */
2180Sstevel@tonic-gate static vmem_t *ctf_arena; /* CTF debug data arena */
2190Sstevel@tonic-gate static struct modctl *kobj_modules = NULL; /* modules loaded */
2200Sstevel@tonic-gate int kobj_mmu_pagesize; /* system pagesize */
2210Sstevel@tonic-gate static int lg_pagesize; /* "large" pagesize */
2220Sstevel@tonic-gate static int kobj_last_module_id = 0; /* id assignment */
2230Sstevel@tonic-gate static kmutex_t kobj_lock; /* protects mach memory list */
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate * The following functions have been implemented by the kernel.
2270Sstevel@tonic-gate * However, many 3rd party drivers provide their own implementations
2280Sstevel@tonic-gate * of these functions. When such drivers are loaded, messages
2295331Samw * indicating that these symbols have been multiply defined will be
2300Sstevel@tonic-gate * emitted to the console. To avoid alarming customers for no good
2310Sstevel@tonic-gate * reason, we simply suppress such warnings for the following set of
2320Sstevel@tonic-gate * functions.
2330Sstevel@tonic-gate */
2340Sstevel@tonic-gate static char *suppress_sym_list[] =
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate "strstr",
2370Sstevel@tonic-gate "strncat",
2380Sstevel@tonic-gate "strlcat",
2390Sstevel@tonic-gate "strlcpy",
2400Sstevel@tonic-gate "strspn",
2410Sstevel@tonic-gate "memcpy",
2420Sstevel@tonic-gate "memset",
2430Sstevel@tonic-gate "memmove",
2440Sstevel@tonic-gate "memcmp",
2450Sstevel@tonic-gate "memchr",
2460Sstevel@tonic-gate "__udivdi3",
2470Sstevel@tonic-gate "__divdi3",
2480Sstevel@tonic-gate "__umoddi3",
2490Sstevel@tonic-gate "__moddi3",
2500Sstevel@tonic-gate NULL /* This entry must exist */
2510Sstevel@tonic-gate };
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /* indexed by KOBJ_NOTIFY_* */
2540Sstevel@tonic-gate static kobj_notify_list_t *kobj_notifiers[KOBJ_NOTIFY_MAX + 1];
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate * TNF probe management globals
2580Sstevel@tonic-gate */
2590Sstevel@tonic-gate tnf_probe_control_t *__tnf_probe_list_head = NULL;
2600Sstevel@tonic-gate tnf_tag_data_t *__tnf_tag_list_head = NULL;
2610Sstevel@tonic-gate int tnf_changed_probe_list = 0;
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Prefix for statically defined tracing (SDT) DTrace probes.
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate const char *sdt_prefix = "__dtrace_probe_";
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /*
2693446Smrj * Beginning and end of the kernel's dynamic text/data segments.
2700Sstevel@tonic-gate */
2710Sstevel@tonic-gate static caddr_t _text;
2720Sstevel@tonic-gate static caddr_t _etext;
2733446Smrj static caddr_t _data;
2743446Smrj
2753446Smrj /*
2765648Ssetje * The sparc linker doesn't create a memory location
2775648Ssetje * for a variable named _edata, so _edata can only be
2785648Ssetje * referred to, not modified. krtld needs a static
2795648Ssetje * variable to modify it - within krtld, of course -
2805648Ssetje * outside of krtld, e_data is used in all kernels.
2813446Smrj */
2825648Ssetje #if defined(__sparc)
2835648Ssetje static caddr_t _edata;
2845648Ssetje #else
2855648Ssetje extern caddr_t _edata;
2863446Smrj #endif
2875648Ssetje
2885648Ssetje Addr dynseg = 0; /* load address of "dynamic" segment */
2895648Ssetje size_t dynsize; /* "dynamic" segment size */
2905648Ssetje
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate int standalone = 1; /* an unwholey kernel? */
2930Sstevel@tonic-gate int use_iflush; /* iflush after relocations */
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate * _kobj_printf()
2970Sstevel@tonic-gate *
2980Sstevel@tonic-gate * Common printf function pointer. Can handle only one conversion
2990Sstevel@tonic-gate * specification in the format string. Some of the functions invoked
3000Sstevel@tonic-gate * through this function pointer cannot handle more that one conversion
3010Sstevel@tonic-gate * specification in the format string.
3020Sstevel@tonic-gate */
3030Sstevel@tonic-gate void (*_kobj_printf)(void *, const char *, ...); /* printf routine */
3040Sstevel@tonic-gate
3055648Ssetje /*
3065648Ssetje * Standalone function pointers for use within krtld.
3075648Ssetje * Many platforms implement optimized platmod versions of
3085648Ssetje * utilities such as bcopy and any such are not yet available
3095648Ssetje * until the kernel is more completely stitched together.
3105648Ssetje * See kobj_impl.h
3115648Ssetje */
3125648Ssetje void (*kobj_bcopy)(const void *, void *, size_t);
3135648Ssetje void (*kobj_bzero)(void *, size_t);
3145648Ssetje size_t (*kobj_strlcat)(char *, const char *, size_t);
3155648Ssetje
3160Sstevel@tonic-gate static kobj_stat_t kobj_stat;
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate #define MINALIGN 8 /* at least a double-word */
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate int
get_weakish_int(int * ip)3210Sstevel@tonic-gate get_weakish_int(int *ip)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate if (standalone)
3240Sstevel@tonic-gate return (0);
3250Sstevel@tonic-gate return (ip == NULL ? 0 : *ip);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate static void *
get_weakish_pointer(void ** ptrp)3290Sstevel@tonic-gate get_weakish_pointer(void **ptrp)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate if (standalone)
3320Sstevel@tonic-gate return (0);
3330Sstevel@tonic-gate return (ptrp == NULL ? 0 : *ptrp);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate * XXX fix dependencies on "kernel"; this should work
3380Sstevel@tonic-gate * for other standalone binaries as well.
3390Sstevel@tonic-gate *
3400Sstevel@tonic-gate * XXX Fix hashing code to use one pointer to
3410Sstevel@tonic-gate * hash entries.
3420Sstevel@tonic-gate * |----------|
3430Sstevel@tonic-gate * | nbuckets |
3440Sstevel@tonic-gate * |----------|
3450Sstevel@tonic-gate * | nchains |
3460Sstevel@tonic-gate * |----------|
3470Sstevel@tonic-gate * | bucket[] |
3480Sstevel@tonic-gate * |----------|
3490Sstevel@tonic-gate * | chain[] |
3500Sstevel@tonic-gate * |----------|
3510Sstevel@tonic-gate */
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate /*
3540Sstevel@tonic-gate * Load, bind and relocate all modules that
3550Sstevel@tonic-gate * form the primary kernel. At this point, our
3560Sstevel@tonic-gate * externals have not been relocated.
3570Sstevel@tonic-gate */
3580Sstevel@tonic-gate void
kobj_init(void * romvec,void * dvec,struct bootops * bootvec,val_t * bootaux)3590Sstevel@tonic-gate kobj_init(
3600Sstevel@tonic-gate void *romvec,
3610Sstevel@tonic-gate void *dvec,
3620Sstevel@tonic-gate struct bootops *bootvec,
3630Sstevel@tonic-gate val_t *bootaux)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate struct module *mp;
3660Sstevel@tonic-gate struct modctl *modp;
3670Sstevel@tonic-gate Addr entry;
3683446Smrj char filename[MAXPATHLEN];
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate * Save these to pass on to
3720Sstevel@tonic-gate * the booted standalone.
3730Sstevel@tonic-gate */
3740Sstevel@tonic-gate romp = romvec;
3750Sstevel@tonic-gate dbvec = dvec;
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate ops = bootvec;
3785648Ssetje kobj_setup_standalone_vectors();
3795648Ssetje
3803446Smrj KOBJ_MARK("Entered kobj_init()");
3810Sstevel@tonic-gate
3823446Smrj (void) BOP_GETPROP(ops, "whoami", filename);
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate * We don't support standalone debuggers anymore. The use of kadb
3860Sstevel@tonic-gate * will interfere with the later use of kmdb. Let the user mend
3870Sstevel@tonic-gate * their ways now. Users will reach this message if they still
3880Sstevel@tonic-gate * have the kadb binary on their system (perhaps they used an old
3890Sstevel@tonic-gate * bfu, or maybe they intentionally copied it there) and have
3900Sstevel@tonic-gate * specified its use in a way that eluded our checking in the boot
3910Sstevel@tonic-gate * program.
3920Sstevel@tonic-gate */
3930Sstevel@tonic-gate if (dvec != NULL) {
3940Sstevel@tonic-gate _kobj_printf(ops, "\nWARNING: Standalone debuggers such as "
3950Sstevel@tonic-gate "kadb are no longer supported\n\n");
3960Sstevel@tonic-gate goto fail;
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3995648Ssetje #if defined(_OBP)
4005648Ssetje /*
4015648Ssetje * OBP allows us to read both the ramdisk and
4025648Ssetje * the underlying root fs when root is a disk.
4035648Ssetje * This can lower incidences of unbootable systems
4045648Ssetje * when the archive is out-of-date with the /etc
4055648Ssetje * state files.
4065648Ssetje */
4075648Ssetje if (BOP_MOUNTROOT() != BOOT_SVC_OK) {
4085648Ssetje _kobj_printf(ops, "can't mount boot fs\n");
4095648Ssetje goto fail;
4105648Ssetje }
4115648Ssetje #else
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate /* on x86, we always boot with a ramdisk */
4140Sstevel@tonic-gate (void) kobj_boot_mountroot();
4153446Smrj
4163446Smrj /*
4173446Smrj * Now that the ramdisk is mounted, finish boot property
4183446Smrj * initialization.
4193446Smrj */
4203446Smrj boot_prop_finish();
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4233446Smrj #if !defined(_UNIX_KRTLD)
4243446Smrj /*
4255648Ssetje * 'unix' is linked together with 'krtld' into one executable and
4263446Smrj * the early boot code does -not- hand us any of the dynamic metadata
4273446Smrj * about the executable. In particular, it does not read in, map or
4283446Smrj * otherwise look at the program headers. We fake all that up now.
4293446Smrj *
4303446Smrj * We do this early as DTrace static probes and tnf probes both call
4313446Smrj * undefined references. We have to process those relocations before
4323446Smrj * calling any of them.
4335648Ssetje *
4345648Ssetje * OBP tells kobj_start() where the ELF image is in memory, so it
4355648Ssetje * synthesized bootaux before kobj_init() was called
4363446Smrj */
4373446Smrj if (bootaux[BA_PHDR].ba_ptr == NULL)
4383446Smrj synthetic_bootaux(filename, bootaux);
4395648Ssetje
4405648Ssetje #endif /* !_UNIX_KRTLD */
4415648Ssetje #endif /* _OBP */
4423446Smrj
4433446Smrj /*
4443446Smrj * Save the interesting attribute-values
4453446Smrj * (scanned by kobj_boot).
4463446Smrj */
4473446Smrj attr_val(bootaux);
4483446Smrj
4490Sstevel@tonic-gate /*
4500Sstevel@tonic-gate * Set the module search path.
4510Sstevel@tonic-gate */
4523446Smrj kobj_module_path = getmodpath(filename);
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate boot_cpu_compatible_list = find_libmacro("CPU");
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate /*
4570Sstevel@tonic-gate * These two modules have actually been
4580Sstevel@tonic-gate * loaded by boot, but we finish the job
4590Sstevel@tonic-gate * by introducing them into the world of
4600Sstevel@tonic-gate * loadable modules.
4610Sstevel@tonic-gate */
4620Sstevel@tonic-gate
4633446Smrj mp = load_exec(bootaux, filename);
4640Sstevel@tonic-gate load_linker(bootaux);
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate /*
4670Sstevel@tonic-gate * Load all the primary dependent modules.
4680Sstevel@tonic-gate */
4690Sstevel@tonic-gate if (load_primary(mp, KOBJ_LM_PRIMARY) == -1)
4700Sstevel@tonic-gate goto fail;
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate /*
4730Sstevel@tonic-gate * Glue it together.
4740Sstevel@tonic-gate */
4750Sstevel@tonic-gate if (bind_primary(bootaux, KOBJ_LM_PRIMARY) == -1)
4760Sstevel@tonic-gate goto fail;
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate entry = bootaux[BA_ENTRY].ba_val;
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * Get the boot flags
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate bootflags(ops);
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate if (boothowto & RB_VERBOSE)
4860Sstevel@tonic-gate kobj_lm_dump(KOBJ_LM_PRIMARY);
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate kobj_kdi_init();
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate if (boothowto & RB_KMDB) {
4910Sstevel@tonic-gate if (load_kmdb(bootaux) < 0)
4920Sstevel@tonic-gate goto fail;
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate * Post setup.
4970Sstevel@tonic-gate */
4980Sstevel@tonic-gate s_text = _text;
4990Sstevel@tonic-gate e_text = _etext;
5000Sstevel@tonic-gate s_data = _data;
5010Sstevel@tonic-gate e_data = _edata;
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate kobj_sync_instruction_memory(s_text, e_text - s_text);
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate #ifdef KOBJ_DEBUG
5060Sstevel@tonic-gate if (kobj_debug & D_DEBUG)
5070Sstevel@tonic-gate _kobj_printf(ops,
5080Sstevel@tonic-gate "krtld: transferring control to: 0x%p\n", entry);
5090Sstevel@tonic-gate #endif
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /*
5120Sstevel@tonic-gate * Make sure the mod system knows about the modules already loaded.
5130Sstevel@tonic-gate */
5140Sstevel@tonic-gate last_module_id = kobj_last_module_id;
5150Sstevel@tonic-gate bcopy(kobj_modules, &modules, sizeof (modules));
5160Sstevel@tonic-gate modp = &modules;
5170Sstevel@tonic-gate do {
5180Sstevel@tonic-gate if (modp->mod_next == kobj_modules)
5190Sstevel@tonic-gate modp->mod_next = &modules;
5200Sstevel@tonic-gate if (modp->mod_prev == kobj_modules)
5210Sstevel@tonic-gate modp->mod_prev = &modules;
5220Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules);
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate standalone = 0;
5250Sstevel@tonic-gate
5265648Ssetje #ifdef KOBJ_DEBUG
5275648Ssetje if (kobj_debug & D_DEBUG)
5285648Ssetje _kobj_printf(ops,
5295648Ssetje "krtld: really transferring control to: 0x%p\n", entry);
5305648Ssetje #endif
5315648Ssetje
5325648Ssetje /* restore printf/bcopy/bzero vectors before returning */
5335648Ssetje kobj_restore_vectors();
5345648Ssetje
5355648Ssetje #if defined(_DBOOT)
5360Sstevel@tonic-gate /*
5375648Ssetje * krtld was called from a dboot ELF section, the embedded
5385648Ssetje * dboot code contains the real entry via bootaux
5390Sstevel@tonic-gate */
5405648Ssetje exitto((caddr_t)entry);
5415648Ssetje #else
5425648Ssetje /*
5435648Ssetje * krtld was directly called from startup
5445648Ssetje */
5455648Ssetje return;
5460Sstevel@tonic-gate #endif
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate fail:
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate _kobj_printf(ops, "krtld: error during initial load/link phase\n");
5514159Sjosephb
5524159Sjosephb #if !defined(_UNIX_KRTLD)
5534159Sjosephb _kobj_printf(ops, "\n");
5544159Sjosephb _kobj_printf(ops, "krtld could neither locate nor resolve symbols"
5554159Sjosephb " for:\n");
5564159Sjosephb _kobj_printf(ops, " %s\n", filename);
5574159Sjosephb _kobj_printf(ops, "in the boot archive. Please verify that this"
5584159Sjosephb " file\n");
5594159Sjosephb _kobj_printf(ops, "matches what is found in the boot archive.\n");
5604159Sjosephb _kobj_printf(ops, "You may need to boot using the Solaris failsafe to"
5614159Sjosephb " fix this.\n");
5624159Sjosephb bop_panic("Unable to boot");
5634159Sjosephb #endif
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate
5665648Ssetje #if !defined(_UNIX_KRTLD) && !defined(_OBP)
5673446Smrj /*
5685648Ssetje * Synthesize additional metadata that describes the executable if
5695648Ssetje * krtld's caller didn't do it.
5703446Smrj *
5713446Smrj * (When the dynamic executable has an interpreter, the boot program
5723446Smrj * does all this for us. Where we don't have an interpreter, (or a
5733446Smrj * even a boot program, perhaps) we have to do this for ourselves.)
5743446Smrj */
5753446Smrj static void
synthetic_bootaux(char * filename,val_t * bootaux)5763446Smrj synthetic_bootaux(char *filename, val_t *bootaux)
5773446Smrj {
5783446Smrj Ehdr ehdr;
5793446Smrj caddr_t phdrbase;
5803446Smrj struct _buf *file;
5813446Smrj int i, n;
5823446Smrj
5833446Smrj /*
5843446Smrj * Elf header
5853446Smrj */
5863446Smrj KOBJ_MARK("synthetic_bootaux()");
5873446Smrj KOBJ_MARK(filename);
5883446Smrj file = kobj_open_file(filename);
5893446Smrj if (file == (struct _buf *)-1) {
5903446Smrj _kobj_printf(ops, "krtld: failed to open '%s'\n", filename);
5913446Smrj return;
5923446Smrj }
5933446Smrj KOBJ_MARK("reading program headers");
5943446Smrj if (kobj_read_file(file, (char *)&ehdr, sizeof (ehdr), 0) < 0) {
5953446Smrj _kobj_printf(ops, "krtld: %s: failed to read ehder\n",
5963446Smrj filename);
5973446Smrj return;
5983446Smrj }
5993446Smrj
6003446Smrj /*
6013446Smrj * Program headers
6023446Smrj */
6033446Smrj bootaux[BA_PHNUM].ba_val = ehdr.e_phnum;
6043446Smrj bootaux[BA_PHENT].ba_val = ehdr.e_phentsize;
6053446Smrj n = ehdr.e_phentsize * ehdr.e_phnum;
6063446Smrj
6073446Smrj phdrbase = kobj_alloc(n, KM_WAIT | KM_TMP);
6083446Smrj
6093446Smrj if (kobj_read_file(file, phdrbase, n, ehdr.e_phoff) < 0) {
6103446Smrj _kobj_printf(ops, "krtld: %s: failed to read phdrs\n",
6113446Smrj filename);
6123446Smrj return;
6133446Smrj }
6143446Smrj bootaux[BA_PHDR].ba_ptr = phdrbase;
6153446Smrj kobj_close_file(file);
6163446Smrj KOBJ_MARK("closed file");
6173446Smrj
6183446Smrj /*
6193446Smrj * Find the dynamic section address
6203446Smrj */
6213446Smrj for (i = 0; i < ehdr.e_phnum; i++) {
6223446Smrj Phdr *phdr = (Phdr *)(phdrbase + ehdr.e_phentsize * i);
6233446Smrj
6243446Smrj if (phdr->p_type == PT_DYNAMIC) {
6253446Smrj bootaux[BA_DYNAMIC].ba_ptr = (void *)phdr->p_vaddr;
6263446Smrj break;
6273446Smrj }
6283446Smrj }
6293446Smrj KOBJ_MARK("synthetic_bootaux() done");
6303446Smrj }
6315648Ssetje #endif /* !_UNIX_KRTLD && !_OBP */
6323446Smrj
6330Sstevel@tonic-gate /*
6340Sstevel@tonic-gate * Set up any global information derived
6350Sstevel@tonic-gate * from attribute/values in the boot or
6360Sstevel@tonic-gate * aux vector.
6370Sstevel@tonic-gate */
6380Sstevel@tonic-gate static void
attr_val(val_t * bootaux)6390Sstevel@tonic-gate attr_val(val_t *bootaux)
6400Sstevel@tonic-gate {
6410Sstevel@tonic-gate Phdr *phdr;
6420Sstevel@tonic-gate int phnum, phsize;
6430Sstevel@tonic-gate int i;
6440Sstevel@tonic-gate
6453446Smrj KOBJ_MARK("attr_val()");
6460Sstevel@tonic-gate kobj_mmu_pagesize = bootaux[BA_PAGESZ].ba_val;
6470Sstevel@tonic-gate lg_pagesize = bootaux[BA_LPAGESZ].ba_val;
6480Sstevel@tonic-gate use_iflush = bootaux[BA_IFLUSH].ba_val;
6490Sstevel@tonic-gate
6500Sstevel@tonic-gate phdr = (Phdr *)bootaux[BA_PHDR].ba_ptr;
6510Sstevel@tonic-gate phnum = bootaux[BA_PHNUM].ba_val;
6520Sstevel@tonic-gate phsize = bootaux[BA_PHENT].ba_val;
6530Sstevel@tonic-gate for (i = 0; i < phnum; i++) {
6540Sstevel@tonic-gate phdr = (Phdr *)(bootaux[BA_PHDR].ba_val + i * phsize);
6550Sstevel@tonic-gate
6565648Ssetje if (phdr->p_type != PT_LOAD) {
6570Sstevel@tonic-gate continue;
6585648Ssetje }
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate * Bounds of the various segments.
6610Sstevel@tonic-gate */
6620Sstevel@tonic-gate if (!(phdr->p_flags & PF_X)) {
6635648Ssetje #if defined(_RELSEG)
6645648Ssetje /*
6655648Ssetje * sparc kernel puts the dynamic info
6665648Ssetje * into a separate segment, which is
6675648Ssetje * free'd in bop_fini()
6685648Ssetje */
6695648Ssetje ASSERT(phdr->p_vaddr != 0);
6700Sstevel@tonic-gate dynseg = phdr->p_vaddr;
6715648Ssetje dynsize = phdr->p_memsz;
6723446Smrj #else
6733446Smrj ASSERT(phdr->p_vaddr == 0);
6743446Smrj #endif
6750Sstevel@tonic-gate } else {
6760Sstevel@tonic-gate if (phdr->p_flags & PF_W) {
6773446Smrj _data = (caddr_t)phdr->p_vaddr;
6783446Smrj _edata = _data + phdr->p_memsz;
6790Sstevel@tonic-gate } else {
6800Sstevel@tonic-gate _text = (caddr_t)phdr->p_vaddr;
6810Sstevel@tonic-gate _etext = _text + phdr->p_memsz;
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate /* To do the kobj_alloc, _edata needs to be set. */
6870Sstevel@tonic-gate for (i = 0; i < NLIBMACROS; i++) {
6880Sstevel@tonic-gate if (bootaux[libmacros[i].lmi_ba_index].ba_ptr != NULL) {
6890Sstevel@tonic-gate libmacros[i].lmi_list = kobj_alloc(
6900Sstevel@tonic-gate strlen(bootaux[libmacros[i].lmi_ba_index].ba_ptr) +
6910Sstevel@tonic-gate 1, KM_WAIT);
6920Sstevel@tonic-gate (void) strcpy(libmacros[i].lmi_list,
6933912Slling bootaux[libmacros[i].lmi_ba_index].ba_ptr);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate libmacros[i].lmi_macrolen = strlen(libmacros[i].lmi_macroname);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate * Set up the booted executable.
7010Sstevel@tonic-gate */
7020Sstevel@tonic-gate static struct module *
load_exec(val_t * bootaux,char * filename)7033446Smrj load_exec(val_t *bootaux, char *filename)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate struct modctl *cp;
7060Sstevel@tonic-gate struct module *mp;
7070Sstevel@tonic-gate Dyn *dyn;
7080Sstevel@tonic-gate Sym *sp;
7090Sstevel@tonic-gate int i, lsize, osize, nsize, allocsize;
7100Sstevel@tonic-gate char *libname, *tmp;
7115648Ssetje char path[MAXPATHLEN];
7123446Smrj
7133446Smrj #ifdef KOBJ_DEBUG
7143446Smrj if (kobj_debug & D_DEBUG)
7153446Smrj _kobj_printf(ops, "module path '%s'\n", kobj_module_path);
7163446Smrj #endif
7173446Smrj
7183446Smrj KOBJ_MARK("add_primary");
7190Sstevel@tonic-gate cp = add_primary(filename, KOBJ_LM_PRIMARY);
7200Sstevel@tonic-gate
7213446Smrj KOBJ_MARK("struct module");
7220Sstevel@tonic-gate mp = kobj_zalloc(sizeof (struct module), KM_WAIT);
7230Sstevel@tonic-gate cp->mod_mp = mp;
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate /*
7260Sstevel@tonic-gate * We don't have the following information
7270Sstevel@tonic-gate * since this module is an executable and not
7280Sstevel@tonic-gate * a relocatable .o.
7290Sstevel@tonic-gate */
7300Sstevel@tonic-gate mp->symtbl_section = 0;
7310Sstevel@tonic-gate mp->shdrs = NULL;
7320Sstevel@tonic-gate mp->strhdr = NULL;
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate /*
7350Sstevel@tonic-gate * Since this module is the only exception,
7360Sstevel@tonic-gate * we cons up some section headers.
7370Sstevel@tonic-gate */
7383446Smrj KOBJ_MARK("symhdr");
7390Sstevel@tonic-gate mp->symhdr = kobj_zalloc(sizeof (Shdr), KM_WAIT);
7403446Smrj
7413446Smrj KOBJ_MARK("strhdr");
7420Sstevel@tonic-gate mp->strhdr = kobj_zalloc(sizeof (Shdr), KM_WAIT);
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate mp->symhdr->sh_type = SHT_SYMTAB;
7450Sstevel@tonic-gate mp->strhdr->sh_type = SHT_STRTAB;
7460Sstevel@tonic-gate /*
7470Sstevel@tonic-gate * Scan the dynamic structure.
7480Sstevel@tonic-gate */
7490Sstevel@tonic-gate for (dyn = (Dyn *) bootaux[BA_DYNAMIC].ba_ptr;
7500Sstevel@tonic-gate dyn->d_tag != DT_NULL; dyn++) {
7510Sstevel@tonic-gate switch (dyn->d_tag) {
7520Sstevel@tonic-gate case DT_SYMTAB:
7530Sstevel@tonic-gate mp->symspace = mp->symtbl = (char *)dyn->d_un.d_ptr;
7540Sstevel@tonic-gate mp->symhdr->sh_addr = dyn->d_un.d_ptr;
7550Sstevel@tonic-gate break;
7560Sstevel@tonic-gate case DT_HASH:
7570Sstevel@tonic-gate mp->nsyms = *((uint_t *)dyn->d_un.d_ptr + 1);
7580Sstevel@tonic-gate mp->hashsize = *(uint_t *)dyn->d_un.d_ptr;
7590Sstevel@tonic-gate break;
7600Sstevel@tonic-gate case DT_STRTAB:
7610Sstevel@tonic-gate mp->strings = (char *)dyn->d_un.d_ptr;
7620Sstevel@tonic-gate mp->strhdr->sh_addr = dyn->d_un.d_ptr;
7630Sstevel@tonic-gate break;
7640Sstevel@tonic-gate case DT_STRSZ:
7650Sstevel@tonic-gate mp->strhdr->sh_size = dyn->d_un.d_val;
7660Sstevel@tonic-gate break;
7670Sstevel@tonic-gate case DT_SYMENT:
7680Sstevel@tonic-gate mp->symhdr->sh_entsize = dyn->d_un.d_val;
7690Sstevel@tonic-gate break;
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate * Collapse any DT_NEEDED entries into one string.
7750Sstevel@tonic-gate */
7760Sstevel@tonic-gate nsize = osize = 0;
7770Sstevel@tonic-gate allocsize = MAXPATHLEN;
7780Sstevel@tonic-gate
7793446Smrj KOBJ_MARK("depends_on");
7800Sstevel@tonic-gate mp->depends_on = kobj_alloc(allocsize, KM_WAIT);
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate for (dyn = (Dyn *) bootaux[BA_DYNAMIC].ba_ptr;
7830Sstevel@tonic-gate dyn->d_tag != DT_NULL; dyn++)
7840Sstevel@tonic-gate if (dyn->d_tag == DT_NEEDED) {
7850Sstevel@tonic-gate char *_lib;
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate libname = mp->strings + dyn->d_un.d_val;
7880Sstevel@tonic-gate if (strchr(libname, '$') != NULL) {
7890Sstevel@tonic-gate if ((_lib = expand_libmacro(libname,
7905648Ssetje path, path)) != NULL)
7910Sstevel@tonic-gate libname = _lib;
7920Sstevel@tonic-gate else
7930Sstevel@tonic-gate _kobj_printf(ops, "krtld: "
7940Sstevel@tonic-gate "load_exec: fail to "
7950Sstevel@tonic-gate "expand %s\n", libname);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate lsize = strlen(libname);
7980Sstevel@tonic-gate nsize += lsize;
7990Sstevel@tonic-gate if (nsize + 1 > allocsize) {
8003446Smrj KOBJ_MARK("grow depends_on");
8010Sstevel@tonic-gate tmp = kobj_alloc(allocsize + MAXPATHLEN,
8020Sstevel@tonic-gate KM_WAIT);
8030Sstevel@tonic-gate bcopy(mp->depends_on, tmp, osize);
8040Sstevel@tonic-gate kobj_free(mp->depends_on, allocsize);
8050Sstevel@tonic-gate mp->depends_on = tmp;
8060Sstevel@tonic-gate allocsize += MAXPATHLEN;
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate bcopy(libname, mp->depends_on + osize, lsize);
8095331Samw *(mp->depends_on + nsize) = ' '; /* separate */
8100Sstevel@tonic-gate nsize++;
8110Sstevel@tonic-gate osize = nsize;
8120Sstevel@tonic-gate }
8130Sstevel@tonic-gate if (nsize) {
8140Sstevel@tonic-gate mp->depends_on[nsize - 1] = '\0'; /* terminate the string */
8150Sstevel@tonic-gate /*
8160Sstevel@tonic-gate * alloc with exact size and copy whatever it got over
8170Sstevel@tonic-gate */
8183446Smrj KOBJ_MARK("realloc depends_on");
8190Sstevel@tonic-gate tmp = kobj_alloc(nsize, KM_WAIT);
8200Sstevel@tonic-gate bcopy(mp->depends_on, tmp, nsize);
8210Sstevel@tonic-gate kobj_free(mp->depends_on, allocsize);
8220Sstevel@tonic-gate mp->depends_on = tmp;
8230Sstevel@tonic-gate } else {
8240Sstevel@tonic-gate kobj_free(mp->depends_on, allocsize);
8250Sstevel@tonic-gate mp->depends_on = NULL;
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate mp->flags = KOBJ_EXEC|KOBJ_PRIM; /* NOT a relocatable .o */
8290Sstevel@tonic-gate mp->symhdr->sh_size = mp->nsyms * mp->symhdr->sh_entsize;
8300Sstevel@tonic-gate /*
8310Sstevel@tonic-gate * We allocate our own table since we don't
8320Sstevel@tonic-gate * hash undefined references.
8330Sstevel@tonic-gate */
8343446Smrj KOBJ_MARK("chains");
8350Sstevel@tonic-gate mp->chains = kobj_zalloc(mp->nsyms * sizeof (symid_t), KM_WAIT);
8363446Smrj KOBJ_MARK("buckets");
8370Sstevel@tonic-gate mp->buckets = kobj_zalloc(mp->hashsize * sizeof (symid_t), KM_WAIT);
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate mp->text = _text;
8400Sstevel@tonic-gate mp->data = _data;
8413446Smrj
8423446Smrj mp->text_size = _etext - _text;
8433446Smrj mp->data_size = _edata - _data;
8443446Smrj
8450Sstevel@tonic-gate cp->mod_text = mp->text;
8460Sstevel@tonic-gate cp->mod_text_size = mp->text_size;
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate mp->filename = cp->mod_filename;
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate #ifdef KOBJ_DEBUG
8510Sstevel@tonic-gate if (kobj_debug & D_LOADING) {
8520Sstevel@tonic-gate _kobj_printf(ops, "krtld: file=%s\n", mp->filename);
8530Sstevel@tonic-gate _kobj_printf(ops, "\ttext: 0x%p", mp->text);
8540Sstevel@tonic-gate _kobj_printf(ops, " size: 0x%x\n", mp->text_size);
8550Sstevel@tonic-gate _kobj_printf(ops, "\tdata: 0x%p", mp->data);
8560Sstevel@tonic-gate _kobj_printf(ops, " dsize: 0x%x\n", mp->data_size);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate /*
8610Sstevel@tonic-gate * Insert symbols into the hash table.
8620Sstevel@tonic-gate */
8630Sstevel@tonic-gate for (i = 0; i < mp->nsyms; i++) {
8640Sstevel@tonic-gate sp = (Sym *)(mp->symtbl + i * mp->symhdr->sh_entsize);
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate if (sp->st_name == 0 || sp->st_shndx == SHN_UNDEF)
8670Sstevel@tonic-gate continue;
8685648Ssetje #if defined(__sparc)
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate * Register symbols are ignored in the kernel
8710Sstevel@tonic-gate */
8720Sstevel@tonic-gate if (ELF_ST_TYPE(sp->st_info) == STT_SPARC_REGISTER)
8730Sstevel@tonic-gate continue;
8740Sstevel@tonic-gate #endif /* __sparc */
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate sym_insert(mp, mp->strings + sp->st_name, i);
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate
8793446Smrj KOBJ_MARK("load_exec done");
8800Sstevel@tonic-gate return (mp);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate /*
8843446Smrj * Set up the linker module (if it's compiled in, LDNAME is NULL)
8850Sstevel@tonic-gate */
8860Sstevel@tonic-gate static void
load_linker(val_t * bootaux)8870Sstevel@tonic-gate load_linker(val_t *bootaux)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate struct module *kmp = (struct module *)kobj_modules->mod_mp;
8900Sstevel@tonic-gate struct module *mp;
8910Sstevel@tonic-gate struct modctl *cp;
8920Sstevel@tonic-gate int i;
8930Sstevel@tonic-gate Shdr *shp;
8940Sstevel@tonic-gate Sym *sp;
8950Sstevel@tonic-gate int shsize;
8960Sstevel@tonic-gate char *dlname = (char *)bootaux[BA_LDNAME].ba_ptr;
8970Sstevel@tonic-gate
8983446Smrj /*
8993446Smrj * On some architectures, krtld is compiled into the kernel.
9003446Smrj */
9013446Smrj if (dlname == NULL)
9023446Smrj return;
9033446Smrj
9040Sstevel@tonic-gate cp = add_primary(dlname, KOBJ_LM_PRIMARY);
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate mp = kobj_zalloc(sizeof (struct module), KM_WAIT);
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate cp->mod_mp = mp;
9090Sstevel@tonic-gate mp->hdr = *(Ehdr *)bootaux[BA_LDELF].ba_ptr;
9100Sstevel@tonic-gate shsize = mp->hdr.e_shentsize * mp->hdr.e_shnum;
9110Sstevel@tonic-gate mp->shdrs = kobj_alloc(shsize, KM_WAIT);
9120Sstevel@tonic-gate bcopy(bootaux[BA_LDSHDR].ba_ptr, mp->shdrs, shsize);
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate for (i = 1; i < (int)mp->hdr.e_shnum; i++) {
9150Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + (i * mp->hdr.e_shentsize));
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate if (shp->sh_flags & SHF_ALLOC) {
9180Sstevel@tonic-gate if (shp->sh_flags & SHF_WRITE) {
9190Sstevel@tonic-gate if (mp->data == NULL)
9200Sstevel@tonic-gate mp->data = (char *)shp->sh_addr;
9210Sstevel@tonic-gate } else if (mp->text == NULL) {
9220Sstevel@tonic-gate mp->text = (char *)shp->sh_addr;
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate if (shp->sh_type == SHT_SYMTAB) {
9260Sstevel@tonic-gate mp->symtbl_section = i;
9270Sstevel@tonic-gate mp->symhdr = shp;
9280Sstevel@tonic-gate mp->symspace = mp->symtbl = (char *)shp->sh_addr;
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate mp->nsyms = mp->symhdr->sh_size / mp->symhdr->sh_entsize;
9320Sstevel@tonic-gate mp->flags = KOBJ_INTERP|KOBJ_PRIM;
9330Sstevel@tonic-gate mp->strhdr = (Shdr *)
9343912Slling (mp->shdrs + mp->symhdr->sh_link * mp->hdr.e_shentsize);
9350Sstevel@tonic-gate mp->strings = (char *)mp->strhdr->sh_addr;
9360Sstevel@tonic-gate mp->hashsize = kobj_gethashsize(mp->nsyms);
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate mp->symsize = mp->symhdr->sh_size + mp->strhdr->sh_size + sizeof (int) +
9393912Slling (mp->hashsize + mp->nsyms) * sizeof (symid_t);
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate mp->chains = kobj_zalloc(mp->nsyms * sizeof (symid_t), KM_WAIT);
9420Sstevel@tonic-gate mp->buckets = kobj_zalloc(mp->hashsize * sizeof (symid_t), KM_WAIT);
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate mp->bss = bootaux[BA_BSS].ba_val;
9450Sstevel@tonic-gate mp->bss_align = 0; /* pre-aligned during allocation */
9460Sstevel@tonic-gate mp->bss_size = (uintptr_t)_edata - mp->bss;
9470Sstevel@tonic-gate mp->text_size = _etext - mp->text;
9480Sstevel@tonic-gate mp->data_size = _edata - mp->data;
9490Sstevel@tonic-gate mp->filename = cp->mod_filename;
9500Sstevel@tonic-gate cp->mod_text = mp->text;
9510Sstevel@tonic-gate cp->mod_text_size = mp->text_size;
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate * Now that we've figured out where the linker is,
9550Sstevel@tonic-gate * set the limits for the booted object.
9560Sstevel@tonic-gate */
9570Sstevel@tonic-gate kmp->text_size = (size_t)(mp->text - kmp->text);
9580Sstevel@tonic-gate kmp->data_size = (size_t)(mp->data - kmp->data);
9590Sstevel@tonic-gate kobj_modules->mod_text_size = kmp->text_size;
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate #ifdef KOBJ_DEBUG
9620Sstevel@tonic-gate if (kobj_debug & D_LOADING) {
9630Sstevel@tonic-gate _kobj_printf(ops, "krtld: file=%s\n", mp->filename);
9640Sstevel@tonic-gate _kobj_printf(ops, "\ttext:0x%p", mp->text);
9650Sstevel@tonic-gate _kobj_printf(ops, " size: 0x%x\n", mp->text_size);
9660Sstevel@tonic-gate _kobj_printf(ops, "\tdata:0x%p", mp->data);
9670Sstevel@tonic-gate _kobj_printf(ops, " dsize: 0x%x\n", mp->data_size);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate /*
9720Sstevel@tonic-gate * Insert the symbols into the hash table.
9730Sstevel@tonic-gate */
9740Sstevel@tonic-gate for (i = 0; i < mp->nsyms; i++) {
9750Sstevel@tonic-gate sp = (Sym *)(mp->symtbl + i * mp->symhdr->sh_entsize);
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate if (sp->st_name == 0 || sp->st_shndx == SHN_UNDEF)
9780Sstevel@tonic-gate continue;
9790Sstevel@tonic-gate if (ELF_ST_BIND(sp->st_info) == STB_GLOBAL) {
9800Sstevel@tonic-gate if (sp->st_shndx == SHN_COMMON)
9810Sstevel@tonic-gate sp->st_shndx = SHN_ABS;
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate sym_insert(mp, mp->strings + sp->st_name, i);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate static kobj_notify_list_t **
kobj_notify_lookup(uint_t type)9890Sstevel@tonic-gate kobj_notify_lookup(uint_t type)
9900Sstevel@tonic-gate {
9910Sstevel@tonic-gate ASSERT(type != 0 && type < sizeof (kobj_notifiers) /
9920Sstevel@tonic-gate sizeof (kobj_notify_list_t *));
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate return (&kobj_notifiers[type]);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate int
kobj_notify_add(kobj_notify_list_t * knp)9980Sstevel@tonic-gate kobj_notify_add(kobj_notify_list_t *knp)
9990Sstevel@tonic-gate {
10000Sstevel@tonic-gate kobj_notify_list_t **knl;
10010Sstevel@tonic-gate
10020Sstevel@tonic-gate knl = kobj_notify_lookup(knp->kn_type);
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate knp->kn_next = NULL;
10050Sstevel@tonic-gate knp->kn_prev = NULL;
10060Sstevel@tonic-gate
10070Sstevel@tonic-gate mutex_enter(&kobj_lock);
10080Sstevel@tonic-gate
10090Sstevel@tonic-gate if (*knl != NULL) {
10100Sstevel@tonic-gate (*knl)->kn_prev = knp;
10110Sstevel@tonic-gate knp->kn_next = *knl;
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate (*knl) = knp;
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate mutex_exit(&kobj_lock);
10160Sstevel@tonic-gate return (0);
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate int
kobj_notify_remove(kobj_notify_list_t * knp)10200Sstevel@tonic-gate kobj_notify_remove(kobj_notify_list_t *knp)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate kobj_notify_list_t **knl = kobj_notify_lookup(knp->kn_type);
10230Sstevel@tonic-gate kobj_notify_list_t *tknp;
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate mutex_enter(&kobj_lock);
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate /* LINTED */
10280Sstevel@tonic-gate if (tknp = knp->kn_next)
10290Sstevel@tonic-gate tknp->kn_prev = knp->kn_prev;
10300Sstevel@tonic-gate
10310Sstevel@tonic-gate /* LINTED */
10320Sstevel@tonic-gate if (tknp = knp->kn_prev)
10330Sstevel@tonic-gate tknp->kn_next = knp->kn_next;
10340Sstevel@tonic-gate else
10350Sstevel@tonic-gate *knl = knp->kn_next;
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate mutex_exit(&kobj_lock);
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate return (0);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate
10420Sstevel@tonic-gate /*
10430Sstevel@tonic-gate * Notify all interested callbacks of a specified change in module state.
10440Sstevel@tonic-gate */
10450Sstevel@tonic-gate static void
kobj_notify(int type,struct modctl * modp)10460Sstevel@tonic-gate kobj_notify(int type, struct modctl *modp)
10470Sstevel@tonic-gate {
10480Sstevel@tonic-gate kobj_notify_list_t *knp;
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate if (modp->mod_loadflags & MOD_NONOTIFY || standalone)
10510Sstevel@tonic-gate return;
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate mutex_enter(&kobj_lock);
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate for (knp = *(kobj_notify_lookup(type)); knp != NULL; knp = knp->kn_next)
10560Sstevel@tonic-gate knp->kn_func(type, modp);
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate /*
10590Sstevel@tonic-gate * KDI notification must be last (it has to allow for work done by the
10600Sstevel@tonic-gate * other notification callbacks), so we call it manually.
10610Sstevel@tonic-gate */
10620Sstevel@tonic-gate kobj_kdi_mod_notify(type, modp);
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate mutex_exit(&kobj_lock);
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate /*
10685648Ssetje * Create the module path.
10690Sstevel@tonic-gate */
10700Sstevel@tonic-gate static char *
getmodpath(const char * filename)10713446Smrj getmodpath(const char *filename)
10720Sstevel@tonic-gate {
10735648Ssetje char *path = kobj_zalloc(MAXPATHLEN, KM_WAIT);
10743446Smrj
10753446Smrj /*
10765648Ssetje * Platform code gets first crack, then add
10775648Ssetje * the default components
10783446Smrj */
10795648Ssetje mach_modpath(path, filename);
10805648Ssetje if (*path != '\0')
10815648Ssetje (void) strcat(path, " ");
10823446Smrj return (strcat(path, MOD_DEFPATH));
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate static struct modctl *
add_primary(const char * filename,int lmid)10863446Smrj add_primary(const char *filename, int lmid)
10870Sstevel@tonic-gate {
10880Sstevel@tonic-gate struct modctl *cp;
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate cp = kobj_zalloc(sizeof (struct modctl), KM_WAIT);
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate cp->mod_filename = kobj_alloc(strlen(filename) + 1, KM_WAIT);
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /*
10950Sstevel@tonic-gate * For symbol lookup, we assemble our own
10960Sstevel@tonic-gate * modctl list of the primary modules.
10970Sstevel@tonic-gate */
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate (void) strcpy(cp->mod_filename, filename);
11000Sstevel@tonic-gate cp->mod_modname = basename(cp->mod_filename);
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate /* set values for modinfo assuming that the load will work */
11030Sstevel@tonic-gate cp->mod_prim = 1;
11040Sstevel@tonic-gate cp->mod_loaded = 1;
11050Sstevel@tonic-gate cp->mod_installed = 1;
11060Sstevel@tonic-gate cp->mod_loadcnt = 1;
11070Sstevel@tonic-gate cp->mod_loadflags = MOD_NOAUTOUNLOAD;
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate cp->mod_id = kobj_last_module_id++;
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate /*
11120Sstevel@tonic-gate * Link the module in. We'll pass this info on
11130Sstevel@tonic-gate * to the mod squad later.
11140Sstevel@tonic-gate */
11150Sstevel@tonic-gate if (kobj_modules == NULL) {
11160Sstevel@tonic-gate kobj_modules = cp;
11170Sstevel@tonic-gate cp->mod_prev = cp->mod_next = cp;
11180Sstevel@tonic-gate } else {
11190Sstevel@tonic-gate cp->mod_prev = kobj_modules->mod_prev;
11200Sstevel@tonic-gate cp->mod_next = kobj_modules;
11210Sstevel@tonic-gate kobj_modules->mod_prev->mod_next = cp;
11220Sstevel@tonic-gate kobj_modules->mod_prev = cp;
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate kobj_lm_append(lmid, cp);
11260Sstevel@tonic-gate
11270Sstevel@tonic-gate return (cp);
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate static int
bind_primary(val_t * bootaux,int lmid)11310Sstevel@tonic-gate bind_primary(val_t *bootaux, int lmid)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate struct modctl_list *linkmap = kobj_lm_lookup(lmid);
11340Sstevel@tonic-gate struct modctl_list *lp;
11350Sstevel@tonic-gate struct module *mp;
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate /*
11380Sstevel@tonic-gate * Do common symbols.
11390Sstevel@tonic-gate */
11400Sstevel@tonic-gate for (lp = linkmap; lp; lp = lp->modl_next) {
11410Sstevel@tonic-gate mp = mod(lp);
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate /*
11440Sstevel@tonic-gate * Don't do common section relocations for modules that
11450Sstevel@tonic-gate * don't need it.
11460Sstevel@tonic-gate */
11470Sstevel@tonic-gate if (mp->flags & (KOBJ_EXEC|KOBJ_INTERP))
11480Sstevel@tonic-gate continue;
11490Sstevel@tonic-gate
11500Sstevel@tonic-gate if (do_common(mp) < 0)
11510Sstevel@tonic-gate return (-1);
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate * Resolve symbols.
11560Sstevel@tonic-gate */
11570Sstevel@tonic-gate for (lp = linkmap; lp; lp = lp->modl_next) {
11580Sstevel@tonic-gate mp = mod(lp);
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate if (do_symbols(mp, 0) < 0)
11610Sstevel@tonic-gate return (-1);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * Do relocations.
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate for (lp = linkmap; lp; lp = lp->modl_next) {
11680Sstevel@tonic-gate mp = mod(lp);
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate if (mp->flags & KOBJ_EXEC) {
11713446Smrj Dyn *dyn;
11723446Smrj Word relasz = 0, relaent = 0;
11733446Smrj Word shtype;
11743446Smrj char *rela = NULL;
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate for (dyn = (Dyn *)bootaux[BA_DYNAMIC].ba_ptr;
11770Sstevel@tonic-gate dyn->d_tag != DT_NULL; dyn++) {
11780Sstevel@tonic-gate switch (dyn->d_tag) {
11790Sstevel@tonic-gate case DT_RELASZ:
11800Sstevel@tonic-gate case DT_RELSZ:
11810Sstevel@tonic-gate relasz = dyn->d_un.d_val;
11820Sstevel@tonic-gate break;
11830Sstevel@tonic-gate case DT_RELAENT:
11840Sstevel@tonic-gate case DT_RELENT:
11850Sstevel@tonic-gate relaent = dyn->d_un.d_val;
11860Sstevel@tonic-gate break;
11870Sstevel@tonic-gate case DT_RELA:
11880Sstevel@tonic-gate shtype = SHT_RELA;
11895648Ssetje rela = (char *)dyn->d_un.d_ptr;
11900Sstevel@tonic-gate break;
11910Sstevel@tonic-gate case DT_REL:
11920Sstevel@tonic-gate shtype = SHT_REL;
11935648Ssetje rela = (char *)dyn->d_un.d_ptr;
11940Sstevel@tonic-gate break;
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate if (relasz == 0 ||
11980Sstevel@tonic-gate relaent == 0 || rela == NULL) {
11990Sstevel@tonic-gate _kobj_printf(ops, "krtld: bind_primary(): "
12000Sstevel@tonic-gate "no relocation information found for "
12010Sstevel@tonic-gate "module %s\n", mp->filename);
12020Sstevel@tonic-gate return (-1);
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate #ifdef KOBJ_DEBUG
12050Sstevel@tonic-gate if (kobj_debug & D_RELOCATIONS)
12060Sstevel@tonic-gate _kobj_printf(ops, "krtld: relocating: file=%s "
12070Sstevel@tonic-gate "KOBJ_EXEC\n", mp->filename);
12080Sstevel@tonic-gate #endif
12090Sstevel@tonic-gate if (do_relocate(mp, rela, shtype, relasz/relaent,
12100Sstevel@tonic-gate relaent, (Addr)mp->text) < 0)
12110Sstevel@tonic-gate return (-1);
12120Sstevel@tonic-gate } else {
12130Sstevel@tonic-gate if (do_relocations(mp) < 0)
12140Sstevel@tonic-gate return (-1);
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate kobj_sync_instruction_memory(mp->text, mp->text_size);
12180Sstevel@tonic-gate }
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate for (lp = linkmap; lp; lp = lp->modl_next) {
12210Sstevel@tonic-gate mp = mod(lp);
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate * We need to re-read the full symbol table for the boot file,
12250Sstevel@tonic-gate * since we couldn't use the full one before. We also need to
12260Sstevel@tonic-gate * load the CTF sections of both the boot file and the
12270Sstevel@tonic-gate * interpreter (us).
12280Sstevel@tonic-gate */
12290Sstevel@tonic-gate if (mp->flags & KOBJ_EXEC) {
12300Sstevel@tonic-gate struct _buf *file;
12310Sstevel@tonic-gate int n;
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate file = kobj_open_file(mp->filename);
12340Sstevel@tonic-gate if (file == (struct _buf *)-1)
12350Sstevel@tonic-gate return (-1);
12360Sstevel@tonic-gate if (kobj_read_file(file, (char *)&mp->hdr,
12370Sstevel@tonic-gate sizeof (mp->hdr), 0) < 0)
12380Sstevel@tonic-gate return (-1);
12390Sstevel@tonic-gate n = mp->hdr.e_shentsize * mp->hdr.e_shnum;
12400Sstevel@tonic-gate mp->shdrs = kobj_alloc(n, KM_WAIT);
12410Sstevel@tonic-gate if (kobj_read_file(file, mp->shdrs, n,
12420Sstevel@tonic-gate mp->hdr.e_shoff) < 0)
12430Sstevel@tonic-gate return (-1);
12440Sstevel@tonic-gate if (get_syms(mp, file) < 0)
12450Sstevel@tonic-gate return (-1);
12460Sstevel@tonic-gate if (get_ctf(mp, file) < 0)
12470Sstevel@tonic-gate return (-1);
12480Sstevel@tonic-gate kobj_close_file(file);
12490Sstevel@tonic-gate mp->flags |= KOBJ_RELOCATED;
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate } else if (mp->flags & KOBJ_INTERP) {
12520Sstevel@tonic-gate struct _buf *file;
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate /*
12550Sstevel@tonic-gate * The interpreter path fragment in mp->filename
12560Sstevel@tonic-gate * will already have the module directory suffix
12570Sstevel@tonic-gate * in it (if appropriate).
12580Sstevel@tonic-gate */
12590Sstevel@tonic-gate file = kobj_open_path(mp->filename, 1, 0);
12600Sstevel@tonic-gate if (file == (struct _buf *)-1)
12610Sstevel@tonic-gate return (-1);
12620Sstevel@tonic-gate if (get_ctf(mp, file) < 0)
12630Sstevel@tonic-gate return (-1);
12640Sstevel@tonic-gate kobj_close_file(file);
12650Sstevel@tonic-gate mp->flags |= KOBJ_RELOCATED;
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate return (0);
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate static struct modctl *
mod_already_loaded(char * modname)12730Sstevel@tonic-gate mod_already_loaded(char *modname)
12740Sstevel@tonic-gate {
12750Sstevel@tonic-gate struct modctl *mctl = kobj_modules;
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate do {
12780Sstevel@tonic-gate if (strcmp(modname, mctl->mod_filename) == 0)
12790Sstevel@tonic-gate return (mctl);
12800Sstevel@tonic-gate mctl = mctl->mod_next;
12810Sstevel@tonic-gate
12820Sstevel@tonic-gate } while (mctl != kobj_modules);
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate return (NULL);
12850Sstevel@tonic-gate }
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate /*
12880Sstevel@tonic-gate * Load all the primary dependent modules.
12890Sstevel@tonic-gate */
12900Sstevel@tonic-gate static int
load_primary(struct module * mp,int lmid)12910Sstevel@tonic-gate load_primary(struct module *mp, int lmid)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate struct modctl *cp;
12940Sstevel@tonic-gate struct module *dmp;
12950Sstevel@tonic-gate char *p, *q;
12960Sstevel@tonic-gate char modname[MODMAXNAMELEN];
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate if ((p = mp->depends_on) == NULL)
12990Sstevel@tonic-gate return (0);
13000Sstevel@tonic-gate
13010Sstevel@tonic-gate /* CONSTANTCONDITION */
13020Sstevel@tonic-gate while (1) {
13030Sstevel@tonic-gate /*
13040Sstevel@tonic-gate * Skip space.
13050Sstevel@tonic-gate */
13060Sstevel@tonic-gate while (*p && (*p == ' ' || *p == '\t'))
13070Sstevel@tonic-gate p++;
13080Sstevel@tonic-gate /*
13090Sstevel@tonic-gate * Get module name.
13100Sstevel@tonic-gate */
13110Sstevel@tonic-gate q = modname;
13120Sstevel@tonic-gate while (*p && *p != ' ' && *p != '\t')
13130Sstevel@tonic-gate *q++ = *p++;
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate if (q == modname)
13160Sstevel@tonic-gate break;
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate *q = '\0';
13190Sstevel@tonic-gate /*
13200Sstevel@tonic-gate * Check for dup dependencies.
13210Sstevel@tonic-gate */
13220Sstevel@tonic-gate if (strcmp(modname, "dtracestubs") == 0 ||
13230Sstevel@tonic-gate mod_already_loaded(modname) != NULL)
13240Sstevel@tonic-gate continue;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate cp = add_primary(modname, lmid);
13270Sstevel@tonic-gate cp->mod_busy = 1;
13280Sstevel@tonic-gate /*
13290Sstevel@tonic-gate * Load it.
13300Sstevel@tonic-gate */
13310Sstevel@tonic-gate (void) kobj_load_module(cp, 1);
13320Sstevel@tonic-gate cp->mod_busy = 0;
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate if ((dmp = cp->mod_mp) == NULL) {
13350Sstevel@tonic-gate cp->mod_loaded = 0;
13360Sstevel@tonic-gate cp->mod_installed = 0;
13370Sstevel@tonic-gate cp->mod_loadcnt = 0;
13380Sstevel@tonic-gate return (-1);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate add_dependent(mp, dmp);
13420Sstevel@tonic-gate dmp->flags |= KOBJ_PRIM;
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate * Recurse.
13460Sstevel@tonic-gate */
13470Sstevel@tonic-gate if (load_primary(dmp, lmid) == -1) {
13480Sstevel@tonic-gate cp->mod_loaded = 0;
13490Sstevel@tonic-gate cp->mod_installed = 0;
13500Sstevel@tonic-gate cp->mod_loadcnt = 0;
13510Sstevel@tonic-gate return (-1);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate return (0);
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate static int
console_is_usb_serial(void)13582191Sszhou console_is_usb_serial(void)
13592191Sszhou {
13602191Sszhou char *console;
13612191Sszhou int len, ret;
13622191Sszhou
13632191Sszhou if ((len = BOP_GETPROPLEN(ops, "console")) == -1)
13642191Sszhou return (0);
13652191Sszhou
13662191Sszhou console = kobj_zalloc(len, KM_WAIT|KM_TMP);
13672191Sszhou (void) BOP_GETPROP(ops, "console", console);
13682191Sszhou ret = (strcmp(console, "usb-serial") == 0);
13692191Sszhou kobj_free(console, len);
13702191Sszhou
13712191Sszhou return (ret);
13722191Sszhou }
13732191Sszhou
13742191Sszhou static int
load_kmdb(val_t * bootaux)13750Sstevel@tonic-gate load_kmdb(val_t *bootaux)
13760Sstevel@tonic-gate {
13770Sstevel@tonic-gate struct modctl *mctl;
13780Sstevel@tonic-gate struct module *mp;
13790Sstevel@tonic-gate Sym *sym;
13800Sstevel@tonic-gate
13812191Sszhou if (console_is_usb_serial()) {
13822191Sszhou _kobj_printf(ops, "kmdb not loaded "
13832191Sszhou "(unsupported on usb serial console)\n");
13842191Sszhou return (0);
13852191Sszhou }
13862191Sszhou
13870Sstevel@tonic-gate _kobj_printf(ops, "Loading kmdb...\n");
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate if ((mctl = add_primary("misc/kmdbmod", KOBJ_LM_DEBUGGER)) == NULL)
13900Sstevel@tonic-gate return (-1);
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate mctl->mod_busy = 1;
13930Sstevel@tonic-gate (void) kobj_load_module(mctl, 1);
13940Sstevel@tonic-gate mctl->mod_busy = 0;
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate if ((mp = mctl->mod_mp) == NULL)
13970Sstevel@tonic-gate return (-1);
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate mp->flags |= KOBJ_PRIM;
14000Sstevel@tonic-gate
14010Sstevel@tonic-gate if (load_primary(mp, KOBJ_LM_DEBUGGER) < 0)
14020Sstevel@tonic-gate return (-1);
14030Sstevel@tonic-gate
14040Sstevel@tonic-gate if (boothowto & RB_VERBOSE)
14050Sstevel@tonic-gate kobj_lm_dump(KOBJ_LM_DEBUGGER);
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate if (bind_primary(bootaux, KOBJ_LM_DEBUGGER) < 0)
14080Sstevel@tonic-gate return (-1);
14090Sstevel@tonic-gate
14100Sstevel@tonic-gate if ((sym = lookup_one(mctl->mod_mp, "kctl_boot_activate")) == NULL)
14110Sstevel@tonic-gate return (-1);
14120Sstevel@tonic-gate
14133446Smrj #ifdef KOBJ_DEBUG
14143446Smrj if (kobj_debug & D_DEBUG) {
14153446Smrj _kobj_printf(ops, "calling kctl_boot_activate() @ 0x%lx\n",
14163446Smrj sym->st_value);
14173446Smrj _kobj_printf(ops, "\tops 0x%p\n", ops);
14183446Smrj _kobj_printf(ops, "\tromp 0x%p\n", romp);
14193446Smrj }
14203446Smrj #endif
14213446Smrj
14220Sstevel@tonic-gate if (((kctl_boot_activate_f *)sym->st_value)(ops, romp, 0,
14230Sstevel@tonic-gate (const char **)kobj_kmdb_argv) < 0)
14240Sstevel@tonic-gate return (-1);
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate return (0);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate /*
14300Sstevel@tonic-gate * Return a string listing module dependencies.
14310Sstevel@tonic-gate */
14320Sstevel@tonic-gate static char *
depends_on(struct module * mp)14330Sstevel@tonic-gate depends_on(struct module *mp)
14340Sstevel@tonic-gate {
14350Sstevel@tonic-gate Sym *sp;
14360Sstevel@tonic-gate char *depstr, *q;
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate /*
14390Sstevel@tonic-gate * The module doesn't have a depends_on value, so let's try it the
14400Sstevel@tonic-gate * old-fashioned way - via "_depends_on"
14410Sstevel@tonic-gate */
14420Sstevel@tonic-gate if ((sp = lookup_one(mp, "_depends_on")) == NULL)
14430Sstevel@tonic-gate return (NULL);
14440Sstevel@tonic-gate
14450Sstevel@tonic-gate q = (char *)sp->st_value;
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate /*
14480Sstevel@tonic-gate * Idiot checks. Make sure it's
14490Sstevel@tonic-gate * in-bounds and NULL terminated.
14500Sstevel@tonic-gate */
14510Sstevel@tonic-gate if (kobj_addrcheck(mp, q) || q[sp->st_size - 1] != '\0') {
14520Sstevel@tonic-gate _kobj_printf(ops, "Error processing dependency for %s\n",
14530Sstevel@tonic-gate mp->filename);
14540Sstevel@tonic-gate return (NULL);
14550Sstevel@tonic-gate }
14560Sstevel@tonic-gate
14570Sstevel@tonic-gate depstr = (char *)kobj_alloc(strlen(q) + 1, KM_WAIT);
14580Sstevel@tonic-gate (void) strcpy(depstr, q);
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate return (depstr);
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate
14630Sstevel@tonic-gate void
kobj_getmodinfo(void * xmp,struct modinfo * modinfo)14640Sstevel@tonic-gate kobj_getmodinfo(void *xmp, struct modinfo *modinfo)
14650Sstevel@tonic-gate {
14660Sstevel@tonic-gate struct module *mp;
14670Sstevel@tonic-gate mp = (struct module *)xmp;
14680Sstevel@tonic-gate
14690Sstevel@tonic-gate modinfo->mi_base = mp->text;
14700Sstevel@tonic-gate modinfo->mi_size = mp->text_size + mp->data_size;
14710Sstevel@tonic-gate }
14720Sstevel@tonic-gate
14730Sstevel@tonic-gate /*
14740Sstevel@tonic-gate * kobj_export_ksyms() performs the following services:
14750Sstevel@tonic-gate *
14760Sstevel@tonic-gate * (1) Migrates the symbol table from boot/kobj memory to the ksyms arena.
14770Sstevel@tonic-gate * (2) Removes unneeded symbols to save space.
14780Sstevel@tonic-gate * (3) Reduces memory footprint by using VM_BESTFIT allocations.
14790Sstevel@tonic-gate * (4) Makes the symbol table visible to /dev/ksyms.
14800Sstevel@tonic-gate */
14810Sstevel@tonic-gate static void
kobj_export_ksyms(struct module * mp)14820Sstevel@tonic-gate kobj_export_ksyms(struct module *mp)
14830Sstevel@tonic-gate {
14840Sstevel@tonic-gate Sym *esp = (Sym *)(mp->symtbl + mp->symhdr->sh_size);
14850Sstevel@tonic-gate Sym *sp, *osp;
14860Sstevel@tonic-gate char *name;
14870Sstevel@tonic-gate size_t namelen;
14880Sstevel@tonic-gate struct module *omp;
14890Sstevel@tonic-gate uint_t nsyms;
14900Sstevel@tonic-gate size_t symsize = mp->symhdr->sh_entsize;
14910Sstevel@tonic-gate size_t locals = 1;
14920Sstevel@tonic-gate size_t strsize;
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate /*
14950Sstevel@tonic-gate * Make a copy of the original module structure.
14960Sstevel@tonic-gate */
14970Sstevel@tonic-gate omp = kobj_alloc(sizeof (struct module), KM_WAIT);
14980Sstevel@tonic-gate bcopy(mp, omp, sizeof (struct module));
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate /*
15010Sstevel@tonic-gate * Compute the sizes of the new symbol table sections.
15020Sstevel@tonic-gate */
15030Sstevel@tonic-gate for (nsyms = strsize = 1, osp = (Sym *)omp->symtbl; osp < esp; osp++) {
15040Sstevel@tonic-gate if (osp->st_value == 0)
15050Sstevel@tonic-gate continue;
15060Sstevel@tonic-gate if (sym_lookup(omp, osp) == NULL)
15070Sstevel@tonic-gate continue;
15080Sstevel@tonic-gate name = omp->strings + osp->st_name;
15090Sstevel@tonic-gate namelen = strlen(name);
15100Sstevel@tonic-gate if (ELF_ST_BIND(osp->st_info) == STB_LOCAL)
15110Sstevel@tonic-gate locals++;
15120Sstevel@tonic-gate nsyms++;
15130Sstevel@tonic-gate strsize += namelen + 1;
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate mp->nsyms = nsyms;
15170Sstevel@tonic-gate mp->hashsize = kobj_gethashsize(mp->nsyms);
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate /*
15200Sstevel@tonic-gate * ksyms_lock must be held as writer during any operation that
15210Sstevel@tonic-gate * modifies ksyms_arena, including allocation from same, and
15220Sstevel@tonic-gate * must not be dropped until the arena is vmem_walk()able.
15230Sstevel@tonic-gate */
15240Sstevel@tonic-gate rw_enter(&ksyms_lock, RW_WRITER);
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate * Allocate space for the new section headers (symtab and strtab),
15280Sstevel@tonic-gate * symbol table, buckets, chains, and strings.
15290Sstevel@tonic-gate */
15300Sstevel@tonic-gate mp->symsize = (2 * sizeof (Shdr)) + (nsyms * symsize) +
15310Sstevel@tonic-gate (mp->hashsize + mp->nsyms) * sizeof (symid_t) + strsize;
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate if (mp->flags & KOBJ_NOKSYMS) {
15340Sstevel@tonic-gate mp->symspace = kobj_alloc(mp->symsize, KM_WAIT);
15350Sstevel@tonic-gate } else {
15360Sstevel@tonic-gate mp->symspace = vmem_alloc(ksyms_arena, mp->symsize,
15370Sstevel@tonic-gate VM_BESTFIT | VM_SLEEP);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate bzero(mp->symspace, mp->symsize);
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate /*
15420Sstevel@tonic-gate * Divvy up symspace.
15430Sstevel@tonic-gate */
15440Sstevel@tonic-gate mp->shdrs = mp->symspace;
15450Sstevel@tonic-gate mp->symhdr = (Shdr *)mp->shdrs;
15460Sstevel@tonic-gate mp->strhdr = (Shdr *)(mp->symhdr + 1);
15470Sstevel@tonic-gate mp->symtbl = (char *)(mp->strhdr + 1);
15480Sstevel@tonic-gate mp->buckets = (symid_t *)(mp->symtbl + (nsyms * symsize));
15490Sstevel@tonic-gate mp->chains = (symid_t *)(mp->buckets + mp->hashsize);
15500Sstevel@tonic-gate mp->strings = (char *)(mp->chains + nsyms);
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * Fill in the new section headers (symtab and strtab).
15540Sstevel@tonic-gate */
15550Sstevel@tonic-gate mp->hdr.e_shnum = 2;
15560Sstevel@tonic-gate mp->symtbl_section = 0;
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate mp->symhdr->sh_type = SHT_SYMTAB;
15590Sstevel@tonic-gate mp->symhdr->sh_addr = (Addr)mp->symtbl;
15600Sstevel@tonic-gate mp->symhdr->sh_size = nsyms * symsize;
15610Sstevel@tonic-gate mp->symhdr->sh_link = 1;
15620Sstevel@tonic-gate mp->symhdr->sh_info = locals;
15630Sstevel@tonic-gate mp->symhdr->sh_addralign = sizeof (Addr);
15640Sstevel@tonic-gate mp->symhdr->sh_entsize = symsize;
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate mp->strhdr->sh_type = SHT_STRTAB;
15670Sstevel@tonic-gate mp->strhdr->sh_addr = (Addr)mp->strings;
15680Sstevel@tonic-gate mp->strhdr->sh_size = strsize;
15690Sstevel@tonic-gate mp->strhdr->sh_addralign = 1;
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate /*
15720Sstevel@tonic-gate * Construct the new symbol table.
15730Sstevel@tonic-gate */
15740Sstevel@tonic-gate for (nsyms = strsize = 1, osp = (Sym *)omp->symtbl; osp < esp; osp++) {
15750Sstevel@tonic-gate if (osp->st_value == 0)
15760Sstevel@tonic-gate continue;
15770Sstevel@tonic-gate if (sym_lookup(omp, osp) == NULL)
15780Sstevel@tonic-gate continue;
15790Sstevel@tonic-gate name = omp->strings + osp->st_name;
15800Sstevel@tonic-gate namelen = strlen(name);
15810Sstevel@tonic-gate sp = (Sym *)(mp->symtbl + symsize * nsyms);
15820Sstevel@tonic-gate bcopy(osp, sp, symsize);
15830Sstevel@tonic-gate bcopy(name, mp->strings + strsize, namelen);
15840Sstevel@tonic-gate sp->st_name = strsize;
15850Sstevel@tonic-gate sym_insert(mp, name, nsyms);
15860Sstevel@tonic-gate nsyms++;
15870Sstevel@tonic-gate strsize += namelen + 1;
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate rw_exit(&ksyms_lock);
15910Sstevel@tonic-gate
15920Sstevel@tonic-gate /*
15930Sstevel@tonic-gate * Free the old section headers -- we'll never need them again.
15940Sstevel@tonic-gate */
15954515Skchow if (!(mp->flags & KOBJ_PRIM)) {
15964515Skchow uint_t shn;
15974515Skchow Shdr *shp;
15984515Skchow
15994515Skchow for (shn = 1; shn < omp->hdr.e_shnum; shn++) {
16004515Skchow shp = (Shdr *)(omp->shdrs + shn * omp->hdr.e_shentsize);
16014515Skchow switch (shp->sh_type) {
16024515Skchow case SHT_RELA:
16034515Skchow case SHT_REL:
16044515Skchow if (shp->sh_addr != 0) {
16054515Skchow kobj_free((void *)shp->sh_addr,
16064515Skchow shp->sh_size);
16074515Skchow }
16084515Skchow break;
16094515Skchow }
16104515Skchow }
16110Sstevel@tonic-gate kobj_free(omp->shdrs, omp->hdr.e_shentsize * omp->hdr.e_shnum);
16124515Skchow }
16130Sstevel@tonic-gate /*
16140Sstevel@tonic-gate * Discard the old symbol table and our copy of the module strucure.
16150Sstevel@tonic-gate */
16160Sstevel@tonic-gate if (!(mp->flags & KOBJ_PRIM))
16170Sstevel@tonic-gate kobj_free(omp->symspace, omp->symsize);
16180Sstevel@tonic-gate kobj_free(omp, sizeof (struct module));
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate static void
kobj_export_ctf(struct module * mp)16220Sstevel@tonic-gate kobj_export_ctf(struct module *mp)
16230Sstevel@tonic-gate {
16240Sstevel@tonic-gate char *data = mp->ctfdata;
16250Sstevel@tonic-gate size_t size = mp->ctfsize;
16260Sstevel@tonic-gate
16270Sstevel@tonic-gate if (data != NULL) {
16280Sstevel@tonic-gate if (_moddebug & MODDEBUG_NOCTF) {
16290Sstevel@tonic-gate mp->ctfdata = NULL;
16300Sstevel@tonic-gate mp->ctfsize = 0;
16310Sstevel@tonic-gate } else {
16320Sstevel@tonic-gate mp->ctfdata = vmem_alloc(ctf_arena, size,
16330Sstevel@tonic-gate VM_BESTFIT | VM_SLEEP);
16340Sstevel@tonic-gate bcopy(data, mp->ctfdata, size);
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate if (!(mp->flags & KOBJ_PRIM))
16380Sstevel@tonic-gate kobj_free(data, size);
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate }
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate void
kobj_export_module(struct module * mp)16430Sstevel@tonic-gate kobj_export_module(struct module *mp)
16440Sstevel@tonic-gate {
16450Sstevel@tonic-gate kobj_export_ksyms(mp);
16460Sstevel@tonic-gate kobj_export_ctf(mp);
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate mp->flags |= KOBJ_EXPORTED;
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate
16510Sstevel@tonic-gate static int
process_dynamic(struct module * mp,char * dyndata,char * strdata)16520Sstevel@tonic-gate process_dynamic(struct module *mp, char *dyndata, char *strdata)
16530Sstevel@tonic-gate {
16540Sstevel@tonic-gate char *path = NULL, *depstr = NULL;
16550Sstevel@tonic-gate int allocsize = 0, osize = 0, nsize = 0;
16560Sstevel@tonic-gate char *libname, *tmp;
16570Sstevel@tonic-gate int lsize;
16580Sstevel@tonic-gate Dyn *dynp;
16590Sstevel@tonic-gate
16600Sstevel@tonic-gate for (dynp = (Dyn *)dyndata; dynp && dynp->d_tag != DT_NULL; dynp++) {
16610Sstevel@tonic-gate switch (dynp->d_tag) {
16620Sstevel@tonic-gate case DT_NEEDED:
16630Sstevel@tonic-gate /*
16640Sstevel@tonic-gate * Read the DT_NEEDED entries, expanding the macros they
16650Sstevel@tonic-gate * contain (if any), and concatenating them into a
16660Sstevel@tonic-gate * single space-separated dependency list.
16670Sstevel@tonic-gate */
16680Sstevel@tonic-gate libname = (ulong_t)dynp->d_un.d_ptr + strdata;
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate if (strchr(libname, '$') != NULL) {
16710Sstevel@tonic-gate char *_lib;
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate if (path == NULL)
16740Sstevel@tonic-gate path = kobj_alloc(MAXPATHLEN, KM_WAIT);
16750Sstevel@tonic-gate if ((_lib = expand_libmacro(libname, path,
16760Sstevel@tonic-gate path)) != NULL)
16770Sstevel@tonic-gate libname = _lib;
16780Sstevel@tonic-gate else {
16790Sstevel@tonic-gate _kobj_printf(ops, "krtld: "
16800Sstevel@tonic-gate "process_dynamic: failed to expand "
16810Sstevel@tonic-gate "%s\n", libname);
16820Sstevel@tonic-gate }
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate lsize = strlen(libname);
16860Sstevel@tonic-gate nsize += lsize;
16870Sstevel@tonic-gate if (nsize + 1 > allocsize) {
16880Sstevel@tonic-gate tmp = kobj_alloc(allocsize + MAXPATHLEN,
16890Sstevel@tonic-gate KM_WAIT);
16900Sstevel@tonic-gate if (depstr != NULL) {
16910Sstevel@tonic-gate bcopy(depstr, tmp, osize);
16920Sstevel@tonic-gate kobj_free(depstr, allocsize);
16930Sstevel@tonic-gate }
16940Sstevel@tonic-gate depstr = tmp;
16950Sstevel@tonic-gate allocsize += MAXPATHLEN;
16960Sstevel@tonic-gate }
16970Sstevel@tonic-gate bcopy(libname, depstr + osize, lsize);
16980Sstevel@tonic-gate *(depstr + nsize) = ' '; /* separator */
16990Sstevel@tonic-gate nsize++;
17000Sstevel@tonic-gate osize = nsize;
17010Sstevel@tonic-gate break;
17020Sstevel@tonic-gate
17030Sstevel@tonic-gate case DT_FLAGS_1:
17040Sstevel@tonic-gate if (dynp->d_un.d_val & DF_1_IGNMULDEF)
17050Sstevel@tonic-gate mp->flags |= KOBJ_IGNMULDEF;
17060Sstevel@tonic-gate if (dynp->d_un.d_val & DF_1_NOKSYMS)
17070Sstevel@tonic-gate mp->flags |= KOBJ_NOKSYMS;
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate break;
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate }
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate /*
17140Sstevel@tonic-gate * finish up the depends string (if any)
17150Sstevel@tonic-gate */
17160Sstevel@tonic-gate if (depstr != NULL) {
17175331Samw *(depstr + nsize - 1) = '\0'; /* overwrite separator w/term */
17180Sstevel@tonic-gate if (path != NULL)
17190Sstevel@tonic-gate kobj_free(path, MAXPATHLEN);
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate tmp = kobj_alloc(nsize, KM_WAIT);
17220Sstevel@tonic-gate bcopy(depstr, tmp, nsize);
17230Sstevel@tonic-gate kobj_free(depstr, allocsize);
17240Sstevel@tonic-gate depstr = tmp;
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate mp->depends_on = depstr;
17270Sstevel@tonic-gate }
17280Sstevel@tonic-gate
17290Sstevel@tonic-gate return (0);
17300Sstevel@tonic-gate }
17310Sstevel@tonic-gate
17320Sstevel@tonic-gate static int
do_dynamic(struct module * mp,struct _buf * file)17330Sstevel@tonic-gate do_dynamic(struct module *mp, struct _buf *file)
17340Sstevel@tonic-gate {
17350Sstevel@tonic-gate Shdr *dshp, *dstrp, *shp;
17360Sstevel@tonic-gate char *dyndata, *dstrdata;
17370Sstevel@tonic-gate int dshn, shn, rc;
17380Sstevel@tonic-gate
17390Sstevel@tonic-gate /* find and validate the dynamic section (if any) */
17400Sstevel@tonic-gate
17410Sstevel@tonic-gate for (dshp = NULL, shn = 1; shn < mp->hdr.e_shnum; shn++) {
17420Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
17430Sstevel@tonic-gate switch (shp->sh_type) {
17440Sstevel@tonic-gate case SHT_DYNAMIC:
17450Sstevel@tonic-gate if (dshp != NULL) {
17460Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_dynamic: %s, ",
17470Sstevel@tonic-gate mp->filename);
17480Sstevel@tonic-gate _kobj_printf(ops,
17490Sstevel@tonic-gate "multiple dynamic sections\n");
17500Sstevel@tonic-gate return (-1);
17510Sstevel@tonic-gate } else {
17520Sstevel@tonic-gate dshp = shp;
17530Sstevel@tonic-gate dshn = shn;
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate break;
17560Sstevel@tonic-gate }
17570Sstevel@tonic-gate }
17580Sstevel@tonic-gate
17590Sstevel@tonic-gate if (dshp == NULL)
17600Sstevel@tonic-gate return (0);
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate if (dshp->sh_link > mp->hdr.e_shnum) {
17630Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
17640Sstevel@tonic-gate _kobj_printf(ops, "no section for sh_link %d\n", dshp->sh_link);
17650Sstevel@tonic-gate return (-1);
17660Sstevel@tonic-gate }
17670Sstevel@tonic-gate dstrp = (Shdr *)(mp->shdrs + dshp->sh_link * mp->hdr.e_shentsize);
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate if (dstrp->sh_type != SHT_STRTAB) {
17700Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
17710Sstevel@tonic-gate _kobj_printf(ops, "sh_link not a string table for section %d\n",
17720Sstevel@tonic-gate dshn);
17730Sstevel@tonic-gate return (-1);
17740Sstevel@tonic-gate }
17750Sstevel@tonic-gate
17760Sstevel@tonic-gate /* read it from disk */
17770Sstevel@tonic-gate
17780Sstevel@tonic-gate dyndata = kobj_alloc(dshp->sh_size, KM_WAIT|KM_TMP);
17790Sstevel@tonic-gate if (kobj_read_file(file, dyndata, dshp->sh_size, dshp->sh_offset) < 0) {
17800Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
17810Sstevel@tonic-gate _kobj_printf(ops, "error reading section %d\n", dshn);
17820Sstevel@tonic-gate
17830Sstevel@tonic-gate kobj_free(dyndata, dshp->sh_size);
17840Sstevel@tonic-gate return (-1);
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate
17870Sstevel@tonic-gate dstrdata = kobj_alloc(dstrp->sh_size, KM_WAIT|KM_TMP);
17880Sstevel@tonic-gate if (kobj_read_file(file, dstrdata, dstrp->sh_size,
17890Sstevel@tonic-gate dstrp->sh_offset) < 0) {
17900Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
17910Sstevel@tonic-gate _kobj_printf(ops, "error reading section %d\n", dshp->sh_link);
17920Sstevel@tonic-gate
17930Sstevel@tonic-gate kobj_free(dyndata, dshp->sh_size);
17940Sstevel@tonic-gate kobj_free(dstrdata, dstrp->sh_size);
17950Sstevel@tonic-gate return (-1);
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate
17980Sstevel@tonic-gate /* pull the interesting pieces out */
17990Sstevel@tonic-gate
18000Sstevel@tonic-gate rc = process_dynamic(mp, dyndata, dstrdata);
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate kobj_free(dyndata, dshp->sh_size);
18030Sstevel@tonic-gate kobj_free(dstrdata, dstrp->sh_size);
18040Sstevel@tonic-gate
18050Sstevel@tonic-gate return (rc);
18060Sstevel@tonic-gate }
18070Sstevel@tonic-gate
18080Sstevel@tonic-gate void
kobj_set_ctf(struct module * mp,caddr_t data,size_t size)18090Sstevel@tonic-gate kobj_set_ctf(struct module *mp, caddr_t data, size_t size)
18100Sstevel@tonic-gate {
18110Sstevel@tonic-gate if (!standalone) {
18120Sstevel@tonic-gate if (mp->ctfdata != NULL) {
18130Sstevel@tonic-gate if (vmem_contains(ctf_arena, mp->ctfdata,
18143912Slling mp->ctfsize)) {
18150Sstevel@tonic-gate vmem_free(ctf_arena, mp->ctfdata, mp->ctfsize);
18160Sstevel@tonic-gate } else {
18170Sstevel@tonic-gate kobj_free(mp->ctfdata, mp->ctfsize);
18180Sstevel@tonic-gate }
18190Sstevel@tonic-gate }
18200Sstevel@tonic-gate }
18210Sstevel@tonic-gate
18220Sstevel@tonic-gate /*
18230Sstevel@tonic-gate * The order is very important here. We need to make sure that
18240Sstevel@tonic-gate * consumers, at any given instant, see a consistent state. We'd
18250Sstevel@tonic-gate * rather they see no CTF data than the address of one buffer and the
18260Sstevel@tonic-gate * size of another.
18270Sstevel@tonic-gate */
18280Sstevel@tonic-gate mp->ctfdata = NULL;
18290Sstevel@tonic-gate membar_producer();
18300Sstevel@tonic-gate mp->ctfsize = size;
18310Sstevel@tonic-gate mp->ctfdata = data;
18320Sstevel@tonic-gate membar_producer();
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate int
kobj_load_module(struct modctl * modp,int use_path)18360Sstevel@tonic-gate kobj_load_module(struct modctl *modp, int use_path)
18370Sstevel@tonic-gate {
18380Sstevel@tonic-gate char *filename = modp->mod_filename;
18390Sstevel@tonic-gate char *modname = modp->mod_modname;
18400Sstevel@tonic-gate int i;
18410Sstevel@tonic-gate int n;
18420Sstevel@tonic-gate struct _buf *file;
18430Sstevel@tonic-gate struct module *mp = NULL;
18440Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
18450Sstevel@tonic-gate int no_suffixdir_drv = 0;
18460Sstevel@tonic-gate #endif
18470Sstevel@tonic-gate
18480Sstevel@tonic-gate mp = kobj_zalloc(sizeof (struct module), KM_WAIT);
18490Sstevel@tonic-gate
18500Sstevel@tonic-gate /*
18510Sstevel@tonic-gate * We need to prevent kmdb's symbols from leaking into /dev/ksyms.
18520Sstevel@tonic-gate * kmdb contains a bunch of symbols with well-known names, symbols
18530Sstevel@tonic-gate * which will mask the real versions, thus causing no end of trouble
18540Sstevel@tonic-gate * for mdb.
18550Sstevel@tonic-gate */
18560Sstevel@tonic-gate if (strcmp(modp->mod_modname, "kmdbmod") == 0)
18570Sstevel@tonic-gate mp->flags |= KOBJ_NOKSYMS;
18580Sstevel@tonic-gate
18590Sstevel@tonic-gate file = kobj_open_path(filename, use_path, 1);
18600Sstevel@tonic-gate if (file == (struct _buf *)-1) {
18610Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
18620Sstevel@tonic-gate file = kobj_open_path(filename, use_path, 0);
18630Sstevel@tonic-gate #endif
18640Sstevel@tonic-gate if (file == (struct _buf *)-1) {
18650Sstevel@tonic-gate kobj_free(mp, sizeof (*mp));
18660Sstevel@tonic-gate goto bad;
18670Sstevel@tonic-gate }
18680Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
18690Sstevel@tonic-gate /*
18700Sstevel@tonic-gate * There is no driver module in the ISA specific (suffix)
18710Sstevel@tonic-gate * subdirectory but there is a module in the parent directory.
18720Sstevel@tonic-gate */
18730Sstevel@tonic-gate if (strncmp(filename, "drv/", 4) == 0) {
18740Sstevel@tonic-gate no_suffixdir_drv = 1;
18750Sstevel@tonic-gate }
18760Sstevel@tonic-gate #endif
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate mp->filename = kobj_alloc(strlen(file->_name) + 1, KM_WAIT);
18800Sstevel@tonic-gate (void) strcpy(mp->filename, file->_name);
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate if (kobj_read_file(file, (char *)&mp->hdr, sizeof (mp->hdr), 0) < 0) {
18830Sstevel@tonic-gate _kobj_printf(ops, "kobj_load_module: %s read header failed\n",
18840Sstevel@tonic-gate modname);
18850Sstevel@tonic-gate kobj_free(mp->filename, strlen(file->_name) + 1);
18860Sstevel@tonic-gate kobj_free(mp, sizeof (*mp));
18870Sstevel@tonic-gate goto bad;
18880Sstevel@tonic-gate }
18890Sstevel@tonic-gate for (i = 0; i < SELFMAG; i++) {
18900Sstevel@tonic-gate if (mp->hdr.e_ident[i] != ELFMAG[i]) {
18910Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
18920Sstevel@tonic-gate _kobj_printf(ops, "%s not an elf module\n",
18930Sstevel@tonic-gate modname);
18940Sstevel@tonic-gate kobj_free(mp->filename, strlen(file->_name) + 1);
18950Sstevel@tonic-gate kobj_free(mp, sizeof (*mp));
18960Sstevel@tonic-gate goto bad;
18970Sstevel@tonic-gate }
18980Sstevel@tonic-gate }
18990Sstevel@tonic-gate /*
19000Sstevel@tonic-gate * It's ELF, but is it our ISA? Interpreting the header
19010Sstevel@tonic-gate * from a file for a byte-swapped ISA could cause a huge
19020Sstevel@tonic-gate * and unsatisfiable value to be passed to kobj_alloc below
19030Sstevel@tonic-gate * and therefore hang booting.
19040Sstevel@tonic-gate */
19050Sstevel@tonic-gate if (!elf_mach_ok(&mp->hdr)) {
19060Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
19070Sstevel@tonic-gate _kobj_printf(ops, "%s not an elf module for this ISA\n",
19080Sstevel@tonic-gate modname);
19090Sstevel@tonic-gate kobj_free(mp->filename, strlen(file->_name) + 1);
19100Sstevel@tonic-gate kobj_free(mp, sizeof (*mp));
19110Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
19120Sstevel@tonic-gate /*
19130Sstevel@tonic-gate * The driver mod is not in the ISA specific subdirectory
19140Sstevel@tonic-gate * and the module in the parent directory is not our ISA.
19150Sstevel@tonic-gate * If it is our ISA, for now we will silently succeed.
19160Sstevel@tonic-gate */
19170Sstevel@tonic-gate if (no_suffixdir_drv == 1) {
19180Sstevel@tonic-gate cmn_err(CE_CONT, "?NOTICE: %s: 64-bit driver module"
19190Sstevel@tonic-gate " not found\n", modname);
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate #endif
19220Sstevel@tonic-gate goto bad;
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate /*
19260Sstevel@tonic-gate * All modules, save for unix, should be relocatable (as opposed to
19270Sstevel@tonic-gate * dynamic). Dynamic modules come with PLTs and GOTs, which can't
19280Sstevel@tonic-gate * currently be processed by krtld.
19290Sstevel@tonic-gate */
19300Sstevel@tonic-gate if (mp->hdr.e_type != ET_REL) {
19310Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
19320Sstevel@tonic-gate _kobj_printf(ops, "%s isn't a relocatable (ET_REL) "
19330Sstevel@tonic-gate "module\n", modname);
19340Sstevel@tonic-gate kobj_free(mp->filename, strlen(file->_name) + 1);
19350Sstevel@tonic-gate kobj_free(mp, sizeof (*mp));
19360Sstevel@tonic-gate goto bad;
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate n = mp->hdr.e_shentsize * mp->hdr.e_shnum;
19400Sstevel@tonic-gate mp->shdrs = kobj_alloc(n, KM_WAIT);
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate if (kobj_read_file(file, mp->shdrs, n, mp->hdr.e_shoff) < 0) {
19430Sstevel@tonic-gate _kobj_printf(ops, "kobj_load_module: %s error reading "
19440Sstevel@tonic-gate "section headers\n", modname);
19450Sstevel@tonic-gate kobj_free(mp->shdrs, n);
19460Sstevel@tonic-gate kobj_free(mp->filename, strlen(file->_name) + 1);
19470Sstevel@tonic-gate kobj_free(mp, sizeof (*mp));
19480Sstevel@tonic-gate goto bad;
19490Sstevel@tonic-gate }
19500Sstevel@tonic-gate
19510Sstevel@tonic-gate kobj_notify(KOBJ_NOTIFY_MODLOADING, modp);
19520Sstevel@tonic-gate module_assign(modp, mp);
19530Sstevel@tonic-gate
19540Sstevel@tonic-gate /* read in sections */
19550Sstevel@tonic-gate if (get_progbits(mp, file) < 0) {
19560Sstevel@tonic-gate _kobj_printf(ops, "%s error reading sections\n", modname);
19570Sstevel@tonic-gate goto bad;
19580Sstevel@tonic-gate }
19590Sstevel@tonic-gate
19600Sstevel@tonic-gate if (do_dynamic(mp, file) < 0) {
19610Sstevel@tonic-gate _kobj_printf(ops, "%s error reading dynamic section\n",
19620Sstevel@tonic-gate modname);
19630Sstevel@tonic-gate goto bad;
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate
19660Sstevel@tonic-gate modp->mod_text = mp->text;
19670Sstevel@tonic-gate modp->mod_text_size = mp->text_size;
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate /* read in symbols; adjust values for each section's real address */
19700Sstevel@tonic-gate if (get_syms(mp, file) < 0) {
19710Sstevel@tonic-gate _kobj_printf(ops, "%s error reading symbols\n",
19720Sstevel@tonic-gate modname);
19730Sstevel@tonic-gate goto bad;
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate
19760Sstevel@tonic-gate /*
19770Sstevel@tonic-gate * If we didn't dependency information from the dynamic section, look
19780Sstevel@tonic-gate * for it the old-fashioned way.
19790Sstevel@tonic-gate */
19800Sstevel@tonic-gate if (mp->depends_on == NULL)
19810Sstevel@tonic-gate mp->depends_on = depends_on(mp);
19820Sstevel@tonic-gate
19830Sstevel@tonic-gate if (get_ctf(mp, file) < 0) {
19840Sstevel@tonic-gate _kobj_printf(ops, "%s debug information will not "
19850Sstevel@tonic-gate "be available\n", modname);
19860Sstevel@tonic-gate }
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate /* primary kernel modules do not have a signature section */
19890Sstevel@tonic-gate if (!(mp->flags & KOBJ_PRIM))
19900Sstevel@tonic-gate get_signature(mp, file);
19910Sstevel@tonic-gate
19920Sstevel@tonic-gate #ifdef KOBJ_DEBUG
19930Sstevel@tonic-gate if (kobj_debug & D_LOADING) {
19940Sstevel@tonic-gate _kobj_printf(ops, "krtld: file=%s\n", mp->filename);
19950Sstevel@tonic-gate _kobj_printf(ops, "\ttext:0x%p", mp->text);
19960Sstevel@tonic-gate _kobj_printf(ops, " size: 0x%x\n", mp->text_size);
19970Sstevel@tonic-gate _kobj_printf(ops, "\tdata:0x%p", mp->data);
19980Sstevel@tonic-gate _kobj_printf(ops, " dsize: 0x%x\n", mp->data_size);
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
20010Sstevel@tonic-gate
20020Sstevel@tonic-gate /*
20030Sstevel@tonic-gate * For primary kernel modules, we defer
20040Sstevel@tonic-gate * symbol resolution and relocation until
20050Sstevel@tonic-gate * all primary objects have been loaded.
20060Sstevel@tonic-gate */
20070Sstevel@tonic-gate if (!standalone) {
20080Sstevel@tonic-gate int ddrval, dcrval;
20090Sstevel@tonic-gate char *dependent_modname;
20100Sstevel@tonic-gate /* load all dependents */
20110Sstevel@tonic-gate dependent_modname = kobj_zalloc(MODMAXNAMELEN, KM_WAIT);
20120Sstevel@tonic-gate ddrval = do_dependents(modp, dependent_modname, MODMAXNAMELEN);
20130Sstevel@tonic-gate
20140Sstevel@tonic-gate /*
20150Sstevel@tonic-gate * resolve undefined and common symbols,
20160Sstevel@tonic-gate * also allocates common space
20170Sstevel@tonic-gate */
20180Sstevel@tonic-gate if ((dcrval = do_common(mp)) < 0) {
20190Sstevel@tonic-gate switch (dcrval) {
20200Sstevel@tonic-gate case DOSYM_UNSAFE:
20210Sstevel@tonic-gate _kobj_printf(ops, "WARNING: mod_load: "
20220Sstevel@tonic-gate "MT-unsafe module '%s' rejected\n",
20230Sstevel@tonic-gate modname);
20240Sstevel@tonic-gate break;
20250Sstevel@tonic-gate case DOSYM_UNDEF:
20260Sstevel@tonic-gate _kobj_printf(ops, "WARNING: mod_load: "
20270Sstevel@tonic-gate "cannot load module '%s'\n",
20280Sstevel@tonic-gate modname);
20290Sstevel@tonic-gate if (ddrval == -1) {
20300Sstevel@tonic-gate _kobj_printf(ops, "WARNING: %s: ",
20310Sstevel@tonic-gate modname);
20320Sstevel@tonic-gate _kobj_printf(ops,
20330Sstevel@tonic-gate "unable to resolve dependency, "
20340Sstevel@tonic-gate "module '%s' not found\n",
20350Sstevel@tonic-gate dependent_modname);
20360Sstevel@tonic-gate }
20370Sstevel@tonic-gate break;
20380Sstevel@tonic-gate }
20390Sstevel@tonic-gate }
20400Sstevel@tonic-gate kobj_free(dependent_modname, MODMAXNAMELEN);
20410Sstevel@tonic-gate if (dcrval < 0)
20420Sstevel@tonic-gate goto bad;
20430Sstevel@tonic-gate
20440Sstevel@tonic-gate /* process relocation tables */
20450Sstevel@tonic-gate if (do_relocations(mp) < 0) {
20460Sstevel@tonic-gate _kobj_printf(ops, "%s error doing relocations\n",
20470Sstevel@tonic-gate modname);
20480Sstevel@tonic-gate goto bad;
20490Sstevel@tonic-gate }
20500Sstevel@tonic-gate
20510Sstevel@tonic-gate if (mp->destination) {
20520Sstevel@tonic-gate off_t off = (uintptr_t)mp->destination & PAGEOFFSET;
20530Sstevel@tonic-gate caddr_t base = (caddr_t)mp->destination - off;
20540Sstevel@tonic-gate size_t size = P2ROUNDUP(mp->text_size + off, PAGESIZE);
20550Sstevel@tonic-gate
20560Sstevel@tonic-gate hat_unload(kas.a_hat, base, size, HAT_UNLOAD_UNLOCK);
20570Sstevel@tonic-gate vmem_free(heap_arena, base, size);
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate
20600Sstevel@tonic-gate /* sync_instruction_memory */
20610Sstevel@tonic-gate kobj_sync_instruction_memory(mp->text, mp->text_size);
20620Sstevel@tonic-gate kobj_export_module(mp);
20630Sstevel@tonic-gate kobj_notify(KOBJ_NOTIFY_MODLOADED, modp);
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate kobj_close_file(file);
20660Sstevel@tonic-gate return (0);
20670Sstevel@tonic-gate bad:
20680Sstevel@tonic-gate if (file != (struct _buf *)-1)
20690Sstevel@tonic-gate kobj_close_file(file);
20700Sstevel@tonic-gate if (modp->mod_mp != NULL)
20710Sstevel@tonic-gate free_module_data(modp->mod_mp);
20720Sstevel@tonic-gate
20730Sstevel@tonic-gate module_assign(modp, NULL);
20740Sstevel@tonic-gate return ((file == (struct _buf *)-1) ? ENOENT : EINVAL);
20750Sstevel@tonic-gate }
20760Sstevel@tonic-gate
20770Sstevel@tonic-gate int
kobj_load_primary_module(struct modctl * modp)20780Sstevel@tonic-gate kobj_load_primary_module(struct modctl *modp)
20790Sstevel@tonic-gate {
20800Sstevel@tonic-gate struct modctl *dep;
20810Sstevel@tonic-gate struct module *mp;
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate if (kobj_load_module(modp, 0) != 0)
20840Sstevel@tonic-gate return (-1);
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate mp = modp->mod_mp;
20870Sstevel@tonic-gate mp->flags |= KOBJ_PRIM;
20880Sstevel@tonic-gate
20890Sstevel@tonic-gate /* Bind new module to its dependents */
20900Sstevel@tonic-gate if (mp->depends_on != NULL && (dep =
20910Sstevel@tonic-gate mod_already_loaded(mp->depends_on)) == NULL) {
20920Sstevel@tonic-gate #ifdef KOBJ_DEBUG
20930Sstevel@tonic-gate if (kobj_debug & D_DEBUG) {
20940Sstevel@tonic-gate _kobj_printf(ops, "krtld: failed to resolve deps "
20950Sstevel@tonic-gate "for primary %s\n", modp->mod_modname);
20960Sstevel@tonic-gate }
20970Sstevel@tonic-gate #endif
20980Sstevel@tonic-gate return (-1);
20990Sstevel@tonic-gate }
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate add_dependent(mp, dep->mod_mp);
21020Sstevel@tonic-gate
21030Sstevel@tonic-gate /*
21040Sstevel@tonic-gate * Relocate it. This module may not be part of a link map, so we
21050Sstevel@tonic-gate * can't use bind_primary.
21060Sstevel@tonic-gate */
21070Sstevel@tonic-gate if (do_common(mp) < 0 || do_symbols(mp, 0) < 0 ||
21080Sstevel@tonic-gate do_relocations(mp) < 0) {
21090Sstevel@tonic-gate #ifdef KOBJ_DEBUG
21100Sstevel@tonic-gate if (kobj_debug & D_DEBUG) {
21110Sstevel@tonic-gate _kobj_printf(ops, "krtld: failed to relocate "
21120Sstevel@tonic-gate "primary %s\n", modp->mod_modname);
21130Sstevel@tonic-gate }
21140Sstevel@tonic-gate #endif
21150Sstevel@tonic-gate return (-1);
21160Sstevel@tonic-gate }
21170Sstevel@tonic-gate
21180Sstevel@tonic-gate return (0);
21190Sstevel@tonic-gate }
21200Sstevel@tonic-gate
21210Sstevel@tonic-gate static void
module_assign(struct modctl * cp,struct module * mp)21220Sstevel@tonic-gate module_assign(struct modctl *cp, struct module *mp)
21230Sstevel@tonic-gate {
21240Sstevel@tonic-gate if (standalone) {
21250Sstevel@tonic-gate cp->mod_mp = mp;
21260Sstevel@tonic-gate return;
21270Sstevel@tonic-gate }
21280Sstevel@tonic-gate mutex_enter(&mod_lock);
21290Sstevel@tonic-gate cp->mod_mp = mp;
21300Sstevel@tonic-gate cp->mod_gencount++;
21310Sstevel@tonic-gate mutex_exit(&mod_lock);
21320Sstevel@tonic-gate }
21330Sstevel@tonic-gate
21340Sstevel@tonic-gate void
kobj_unload_module(struct modctl * modp)21350Sstevel@tonic-gate kobj_unload_module(struct modctl *modp)
21360Sstevel@tonic-gate {
21370Sstevel@tonic-gate struct module *mp = modp->mod_mp;
21380Sstevel@tonic-gate
21390Sstevel@tonic-gate if ((_moddebug & MODDEBUG_KEEPTEXT) && mp) {
21400Sstevel@tonic-gate _kobj_printf(ops, "text for %s ", mp->filename);
21410Sstevel@tonic-gate _kobj_printf(ops, "was at %p\n", mp->text);
21420Sstevel@tonic-gate mp->text = NULL; /* don't actually free it */
21430Sstevel@tonic-gate }
21440Sstevel@tonic-gate
21450Sstevel@tonic-gate kobj_notify(KOBJ_NOTIFY_MODUNLOADING, modp);
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate /*
21480Sstevel@tonic-gate * Null out mod_mp first, so consumers (debuggers) know not to look
21490Sstevel@tonic-gate * at the module structure any more.
21500Sstevel@tonic-gate */
21510Sstevel@tonic-gate mutex_enter(&mod_lock);
21520Sstevel@tonic-gate modp->mod_mp = NULL;
21530Sstevel@tonic-gate mutex_exit(&mod_lock);
21540Sstevel@tonic-gate
21550Sstevel@tonic-gate kobj_notify(KOBJ_NOTIFY_MODUNLOADED, modp);
21560Sstevel@tonic-gate free_module_data(mp);
21570Sstevel@tonic-gate }
21580Sstevel@tonic-gate
21590Sstevel@tonic-gate static void
free_module_data(struct module * mp)21600Sstevel@tonic-gate free_module_data(struct module *mp)
21610Sstevel@tonic-gate {
21620Sstevel@tonic-gate struct module_list *lp, *tmp;
21630Sstevel@tonic-gate int ksyms_exported = 0;
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate lp = mp->head;
21660Sstevel@tonic-gate while (lp) {
21670Sstevel@tonic-gate tmp = lp;
21680Sstevel@tonic-gate lp = lp->next;
21690Sstevel@tonic-gate kobj_free((char *)tmp, sizeof (*tmp));
21700Sstevel@tonic-gate }
21710Sstevel@tonic-gate
21720Sstevel@tonic-gate rw_enter(&ksyms_lock, RW_WRITER);
21730Sstevel@tonic-gate if (mp->symspace) {
21740Sstevel@tonic-gate if (vmem_contains(ksyms_arena, mp->symspace, mp->symsize)) {
21750Sstevel@tonic-gate vmem_free(ksyms_arena, mp->symspace, mp->symsize);
21760Sstevel@tonic-gate ksyms_exported = 1;
21770Sstevel@tonic-gate } else {
21780Sstevel@tonic-gate if (mp->flags & KOBJ_NOKSYMS)
21790Sstevel@tonic-gate ksyms_exported = 1;
21800Sstevel@tonic-gate kobj_free(mp->symspace, mp->symsize);
21810Sstevel@tonic-gate }
21820Sstevel@tonic-gate }
21830Sstevel@tonic-gate rw_exit(&ksyms_lock);
21840Sstevel@tonic-gate
21850Sstevel@tonic-gate if (mp->ctfdata) {
21860Sstevel@tonic-gate if (vmem_contains(ctf_arena, mp->ctfdata, mp->ctfsize))
21870Sstevel@tonic-gate vmem_free(ctf_arena, mp->ctfdata, mp->ctfsize);
21880Sstevel@tonic-gate else
21890Sstevel@tonic-gate kobj_free(mp->ctfdata, mp->ctfsize);
21900Sstevel@tonic-gate }
21910Sstevel@tonic-gate
21920Sstevel@tonic-gate if (mp->sigdata)
21930Sstevel@tonic-gate kobj_free(mp->sigdata, mp->sigsize);
21940Sstevel@tonic-gate
21950Sstevel@tonic-gate /*
21960Sstevel@tonic-gate * We did not get far enough into kobj_export_ksyms() to free allocated
21970Sstevel@tonic-gate * buffers because we encounted error conditions. Free the buffers.
21980Sstevel@tonic-gate */
21990Sstevel@tonic-gate if ((ksyms_exported == 0) && (mp->shdrs != NULL)) {
22000Sstevel@tonic-gate uint_t shn;
22010Sstevel@tonic-gate Shdr *shp;
22020Sstevel@tonic-gate
22030Sstevel@tonic-gate for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
22040Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
22050Sstevel@tonic-gate switch (shp->sh_type) {
22060Sstevel@tonic-gate case SHT_RELA:
22070Sstevel@tonic-gate case SHT_REL:
22080Sstevel@tonic-gate if (shp->sh_addr != 0)
22090Sstevel@tonic-gate kobj_free((void *)shp->sh_addr,
22100Sstevel@tonic-gate shp->sh_size);
22110Sstevel@tonic-gate break;
22120Sstevel@tonic-gate }
22130Sstevel@tonic-gate }
22140Sstevel@tonic-gate err_free_done:
22150Sstevel@tonic-gate if (!(mp->flags & KOBJ_PRIM)) {
22160Sstevel@tonic-gate kobj_free(mp->shdrs,
22170Sstevel@tonic-gate mp->hdr.e_shentsize * mp->hdr.e_shnum);
22180Sstevel@tonic-gate }
22190Sstevel@tonic-gate }
22200Sstevel@tonic-gate
22210Sstevel@tonic-gate if (mp->bss)
22220Sstevel@tonic-gate vmem_free(data_arena, (void *)mp->bss, mp->bss_size);
22230Sstevel@tonic-gate
22240Sstevel@tonic-gate if (mp->fbt_tab)
22250Sstevel@tonic-gate kobj_texthole_free(mp->fbt_tab, mp->fbt_size);
22260Sstevel@tonic-gate
22270Sstevel@tonic-gate if (mp->textwin_base)
22280Sstevel@tonic-gate kobj_textwin_free(mp);
22290Sstevel@tonic-gate
22300Sstevel@tonic-gate if (mp->sdt_probes != NULL) {
22310Sstevel@tonic-gate sdt_probedesc_t *sdp = mp->sdt_probes, *next;
22320Sstevel@tonic-gate
22330Sstevel@tonic-gate while (sdp != NULL) {
22340Sstevel@tonic-gate next = sdp->sdpd_next;
22350Sstevel@tonic-gate kobj_free(sdp->sdpd_name, strlen(sdp->sdpd_name) + 1);
22360Sstevel@tonic-gate kobj_free(sdp, sizeof (sdt_probedesc_t));
22370Sstevel@tonic-gate sdp = next;
22380Sstevel@tonic-gate }
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate
22410Sstevel@tonic-gate if (mp->sdt_tab)
22420Sstevel@tonic-gate kobj_texthole_free(mp->sdt_tab, mp->sdt_size);
22430Sstevel@tonic-gate if (mp->text)
22440Sstevel@tonic-gate vmem_free(text_arena, mp->text, mp->text_size);
22450Sstevel@tonic-gate if (mp->data)
22460Sstevel@tonic-gate vmem_free(data_arena, mp->data, mp->data_size);
22470Sstevel@tonic-gate if (mp->depends_on)
22480Sstevel@tonic-gate kobj_free(mp->depends_on, strlen(mp->depends_on)+1);
22490Sstevel@tonic-gate if (mp->filename)
22500Sstevel@tonic-gate kobj_free(mp->filename, strlen(mp->filename)+1);
22510Sstevel@tonic-gate
22520Sstevel@tonic-gate kobj_free((char *)mp, sizeof (*mp));
22530Sstevel@tonic-gate }
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate static int
get_progbits(struct module * mp,struct _buf * file)22560Sstevel@tonic-gate get_progbits(struct module *mp, struct _buf *file)
22570Sstevel@tonic-gate {
22580Sstevel@tonic-gate struct proginfo *tp, *dp, *sdp;
22590Sstevel@tonic-gate Shdr *shp;
22600Sstevel@tonic-gate reloc_dest_t dest = NULL;
22610Sstevel@tonic-gate uintptr_t bits_ptr;
22626206Sab196087 uintptr_t text = 0, data, textptr;
22630Sstevel@tonic-gate uint_t shn;
22640Sstevel@tonic-gate int err = -1;
22650Sstevel@tonic-gate
22665648Ssetje tp = kobj_zalloc(sizeof (struct proginfo), KM_WAIT|KM_TMP);
22675648Ssetje dp = kobj_zalloc(sizeof (struct proginfo), KM_WAIT|KM_TMP);
22685648Ssetje sdp = kobj_zalloc(sizeof (struct proginfo), KM_WAIT|KM_TMP);
22690Sstevel@tonic-gate /*
22700Sstevel@tonic-gate * loop through sections to find out how much space we need
22710Sstevel@tonic-gate * for text, data, (also bss that is already assigned)
22720Sstevel@tonic-gate */
22730Sstevel@tonic-gate if (get_progbits_size(mp, tp, dp, sdp) < 0)
22740Sstevel@tonic-gate goto done;
22750Sstevel@tonic-gate
22760Sstevel@tonic-gate mp->text_size = tp->size;
22770Sstevel@tonic-gate mp->data_size = dp->size;
22780Sstevel@tonic-gate
22790Sstevel@tonic-gate if (standalone) {
22803446Smrj caddr_t limit = _data;
22813446Smrj
22823446Smrj if (lg_pagesize && _text + lg_pagesize < limit)
22833446Smrj limit = _text + lg_pagesize;
22843446Smrj
22850Sstevel@tonic-gate mp->text = kobj_segbrk(&_etext, mp->text_size,
22863912Slling tp->align, limit);
22870Sstevel@tonic-gate /*
22880Sstevel@tonic-gate * If we can't grow the text segment, try the
22890Sstevel@tonic-gate * data segment before failing.
22900Sstevel@tonic-gate */
22910Sstevel@tonic-gate if (mp->text == NULL) {
22920Sstevel@tonic-gate mp->text = kobj_segbrk(&_edata, mp->text_size,
22933912Slling tp->align, 0);
22940Sstevel@tonic-gate }
22950Sstevel@tonic-gate
22960Sstevel@tonic-gate mp->data = kobj_segbrk(&_edata, mp->data_size, dp->align, 0);
22970Sstevel@tonic-gate
22980Sstevel@tonic-gate if (mp->text == NULL || mp->data == NULL)
22990Sstevel@tonic-gate goto done;
23000Sstevel@tonic-gate
23010Sstevel@tonic-gate } else {
23020Sstevel@tonic-gate if (text_arena == NULL)
23030Sstevel@tonic-gate kobj_vmem_init(&text_arena, &data_arena);
23040Sstevel@tonic-gate
23050Sstevel@tonic-gate /*
23060Sstevel@tonic-gate * some architectures may want to load the module on a
23070Sstevel@tonic-gate * page that is currently read only. It may not be
23080Sstevel@tonic-gate * possible for those architectures to remap their page
23090Sstevel@tonic-gate * on the fly. So we provide a facility for them to hang
23100Sstevel@tonic-gate * a private hook where the memory they assign the module
23110Sstevel@tonic-gate * is not the actual place where the module loads.
23120Sstevel@tonic-gate *
23130Sstevel@tonic-gate * In this case there are two addresses that deal with the
23140Sstevel@tonic-gate * modload.
23150Sstevel@tonic-gate * 1) the final destination of the module
23160Sstevel@tonic-gate * 2) the address that is used to view the newly
23170Sstevel@tonic-gate * loaded module until all the relocations relative to 1
23180Sstevel@tonic-gate * above are completed.
23190Sstevel@tonic-gate *
23200Sstevel@tonic-gate * That is what dest is used for below.
23210Sstevel@tonic-gate */
23220Sstevel@tonic-gate mp->text_size += tp->align;
23230Sstevel@tonic-gate mp->data_size += dp->align;
23240Sstevel@tonic-gate
23250Sstevel@tonic-gate mp->text = kobj_text_alloc(text_arena, mp->text_size);
23260Sstevel@tonic-gate
23270Sstevel@tonic-gate /*
23280Sstevel@tonic-gate * a remap is taking place. Align the text ptr relative
23290Sstevel@tonic-gate * to the secondary mapping. That is where the bits will
23300Sstevel@tonic-gate * be read in.
23310Sstevel@tonic-gate */
23320Sstevel@tonic-gate if (kvseg.s_base != NULL && !vmem_contains(heaptext_arena,
23330Sstevel@tonic-gate mp->text, mp->text_size)) {
23340Sstevel@tonic-gate off_t off = (uintptr_t)mp->text & PAGEOFFSET;
23350Sstevel@tonic-gate size_t size = P2ROUNDUP(mp->text_size + off, PAGESIZE);
23360Sstevel@tonic-gate caddr_t map = vmem_alloc(heap_arena, size, VM_SLEEP);
23370Sstevel@tonic-gate caddr_t orig = mp->text - off;
23380Sstevel@tonic-gate pgcnt_t pages = size / PAGESIZE;
23390Sstevel@tonic-gate
23400Sstevel@tonic-gate dest = (reloc_dest_t)(map + off);
23410Sstevel@tonic-gate text = ALIGN((uintptr_t)dest, tp->align);
23420Sstevel@tonic-gate
23430Sstevel@tonic-gate while (pages--) {
23440Sstevel@tonic-gate hat_devload(kas.a_hat, map, PAGESIZE,
23450Sstevel@tonic-gate hat_getpfnum(kas.a_hat, orig),
23460Sstevel@tonic-gate PROT_READ | PROT_WRITE | PROT_EXEC,
23470Sstevel@tonic-gate HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK);
23480Sstevel@tonic-gate map += PAGESIZE;
23490Sstevel@tonic-gate orig += PAGESIZE;
23500Sstevel@tonic-gate }
23510Sstevel@tonic-gate /*
23520Sstevel@tonic-gate * Since we set up a non-cacheable mapping, we need
23530Sstevel@tonic-gate * to flush any old entries in the cache that might
23540Sstevel@tonic-gate * be left around from the read-only mapping.
23550Sstevel@tonic-gate */
23560Sstevel@tonic-gate dcache_flushall();
23570Sstevel@tonic-gate }
23580Sstevel@tonic-gate if (mp->data_size)
23590Sstevel@tonic-gate mp->data = vmem_alloc(data_arena, mp->data_size,
23600Sstevel@tonic-gate VM_SLEEP | VM_BESTFIT);
23610Sstevel@tonic-gate }
23620Sstevel@tonic-gate textptr = (uintptr_t)mp->text;
23630Sstevel@tonic-gate textptr = ALIGN(textptr, tp->align);
23640Sstevel@tonic-gate mp->destination = dest;
23650Sstevel@tonic-gate
23660Sstevel@tonic-gate /*
23670Sstevel@tonic-gate * This is the case where a remap is not being done.
23680Sstevel@tonic-gate */
23690Sstevel@tonic-gate if (text == 0)
23700Sstevel@tonic-gate text = ALIGN((uintptr_t)mp->text, tp->align);
23710Sstevel@tonic-gate data = ALIGN((uintptr_t)mp->data, dp->align);
23720Sstevel@tonic-gate
23730Sstevel@tonic-gate /* now loop though sections assigning addresses and loading the data */
23740Sstevel@tonic-gate for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
23750Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
23760Sstevel@tonic-gate if (!(shp->sh_flags & SHF_ALLOC))
23770Sstevel@tonic-gate continue;
23780Sstevel@tonic-gate
23790Sstevel@tonic-gate if ((shp->sh_flags & SHF_WRITE) == 0)
23800Sstevel@tonic-gate bits_ptr = text;
23810Sstevel@tonic-gate else
23820Sstevel@tonic-gate bits_ptr = data;
23830Sstevel@tonic-gate
23840Sstevel@tonic-gate bits_ptr = ALIGN(bits_ptr, shp->sh_addralign);
23850Sstevel@tonic-gate
23860Sstevel@tonic-gate if (shp->sh_type == SHT_NOBITS) {
23870Sstevel@tonic-gate /*
23880Sstevel@tonic-gate * Zero bss.
23890Sstevel@tonic-gate */
23900Sstevel@tonic-gate bzero((caddr_t)bits_ptr, shp->sh_size);
23910Sstevel@tonic-gate shp->sh_type = SHT_PROGBITS;
23920Sstevel@tonic-gate } else {
23930Sstevel@tonic-gate if (kobj_read_file(file, (char *)bits_ptr,
23940Sstevel@tonic-gate shp->sh_size, shp->sh_offset) < 0)
23950Sstevel@tonic-gate goto done;
23960Sstevel@tonic-gate }
23970Sstevel@tonic-gate
23980Sstevel@tonic-gate if (shp->sh_flags & SHF_WRITE) {
23990Sstevel@tonic-gate shp->sh_addr = bits_ptr;
24000Sstevel@tonic-gate } else {
24010Sstevel@tonic-gate textptr = ALIGN(textptr, shp->sh_addralign);
24020Sstevel@tonic-gate shp->sh_addr = textptr;
24030Sstevel@tonic-gate textptr += shp->sh_size;
24040Sstevel@tonic-gate }
24050Sstevel@tonic-gate
24060Sstevel@tonic-gate bits_ptr += shp->sh_size;
24070Sstevel@tonic-gate if ((shp->sh_flags & SHF_WRITE) == 0)
24080Sstevel@tonic-gate text = bits_ptr;
24090Sstevel@tonic-gate else
24100Sstevel@tonic-gate data = bits_ptr;
24110Sstevel@tonic-gate }
24120Sstevel@tonic-gate
24130Sstevel@tonic-gate err = 0;
24140Sstevel@tonic-gate done:
24150Sstevel@tonic-gate /*
24160Sstevel@tonic-gate * Free and mark as freed the section headers here so that
24170Sstevel@tonic-gate * free_module_data() does not have to worry about this buffer.
24180Sstevel@tonic-gate *
24190Sstevel@tonic-gate * This buffer is freed here because one of the possible reasons
24200Sstevel@tonic-gate * for error is a section with non-zero sh_addr and in that case
24210Sstevel@tonic-gate * free_module_data() would have no way of recognizing that this
24220Sstevel@tonic-gate * buffer was unallocated.
24230Sstevel@tonic-gate */
24240Sstevel@tonic-gate if (err != 0) {
24250Sstevel@tonic-gate kobj_free(mp->shdrs, mp->hdr.e_shentsize * mp->hdr.e_shnum);
24260Sstevel@tonic-gate mp->shdrs = NULL;
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate
24290Sstevel@tonic-gate (void) kobj_free(tp, sizeof (struct proginfo));
24300Sstevel@tonic-gate (void) kobj_free(dp, sizeof (struct proginfo));
24310Sstevel@tonic-gate (void) kobj_free(sdp, sizeof (struct proginfo));
24320Sstevel@tonic-gate
24330Sstevel@tonic-gate return (err);
24340Sstevel@tonic-gate }
24350Sstevel@tonic-gate
24360Sstevel@tonic-gate /*
24370Sstevel@tonic-gate * Go through suppress_sym_list to see if "multiply defined"
24380Sstevel@tonic-gate * warning of this symbol should be suppressed. Return 1 if
24390Sstevel@tonic-gate * warning should be suppressed, 0 otherwise.
24400Sstevel@tonic-gate */
24410Sstevel@tonic-gate static int
kobj_suppress_warning(char * symname)24420Sstevel@tonic-gate kobj_suppress_warning(char *symname)
24430Sstevel@tonic-gate {
24440Sstevel@tonic-gate int i;
24450Sstevel@tonic-gate
24460Sstevel@tonic-gate for (i = 0; suppress_sym_list[i] != NULL; i++) {
24470Sstevel@tonic-gate if (strcmp(suppress_sym_list[i], symname) == 0)
24480Sstevel@tonic-gate return (1);
24490Sstevel@tonic-gate }
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate return (0);
24520Sstevel@tonic-gate }
24530Sstevel@tonic-gate
24540Sstevel@tonic-gate static int
get_syms(struct module * mp,struct _buf * file)24550Sstevel@tonic-gate get_syms(struct module *mp, struct _buf *file)
24560Sstevel@tonic-gate {
24570Sstevel@tonic-gate uint_t shn;
24580Sstevel@tonic-gate Shdr *shp;
24590Sstevel@tonic-gate uint_t i;
24600Sstevel@tonic-gate Sym *sp, *ksp;
24610Sstevel@tonic-gate char *symname;
24620Sstevel@tonic-gate int dosymtab = 0;
24630Sstevel@tonic-gate
24640Sstevel@tonic-gate /*
24650Sstevel@tonic-gate * Find the interesting sections.
24660Sstevel@tonic-gate */
24670Sstevel@tonic-gate for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
24680Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
24690Sstevel@tonic-gate switch (shp->sh_type) {
24700Sstevel@tonic-gate case SHT_SYMTAB:
24710Sstevel@tonic-gate mp->symtbl_section = shn;
24720Sstevel@tonic-gate mp->symhdr = shp;
24730Sstevel@tonic-gate dosymtab++;
24740Sstevel@tonic-gate break;
24750Sstevel@tonic-gate
24760Sstevel@tonic-gate case SHT_RELA:
24770Sstevel@tonic-gate case SHT_REL:
24780Sstevel@tonic-gate /*
24790Sstevel@tonic-gate * Already loaded.
24800Sstevel@tonic-gate */
24810Sstevel@tonic-gate if (shp->sh_addr)
24820Sstevel@tonic-gate continue;
24835648Ssetje
24845648Ssetje /* KM_TMP since kobj_free'd in do_relocations */
24850Sstevel@tonic-gate shp->sh_addr = (Addr)
24860Sstevel@tonic-gate kobj_alloc(shp->sh_size, KM_WAIT|KM_TMP);
24870Sstevel@tonic-gate
24880Sstevel@tonic-gate if (kobj_read_file(file, (char *)shp->sh_addr,
24890Sstevel@tonic-gate shp->sh_size, shp->sh_offset) < 0) {
24900Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_syms: %s, ",
24910Sstevel@tonic-gate mp->filename);
24920Sstevel@tonic-gate _kobj_printf(ops, "error reading section %d\n",
24930Sstevel@tonic-gate shn);
24940Sstevel@tonic-gate return (-1);
24950Sstevel@tonic-gate }
24960Sstevel@tonic-gate break;
24970Sstevel@tonic-gate }
24980Sstevel@tonic-gate }
24990Sstevel@tonic-gate
25000Sstevel@tonic-gate /*
25010Sstevel@tonic-gate * This is true for a stripped executable. In the case of
25020Sstevel@tonic-gate * 'unix' it can be stripped but it still contains the SHT_DYNSYM,
25030Sstevel@tonic-gate * and since that symbol information is still present everything
25040Sstevel@tonic-gate * is just fine.
25050Sstevel@tonic-gate */
25060Sstevel@tonic-gate if (!dosymtab) {
25070Sstevel@tonic-gate if (mp->flags & KOBJ_EXEC)
25080Sstevel@tonic-gate return (0);
25090Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_syms: %s ",
25103912Slling mp->filename);
25110Sstevel@tonic-gate _kobj_printf(ops, "no SHT_SYMTAB symbol table found\n");
25120Sstevel@tonic-gate return (-1);
25130Sstevel@tonic-gate }
25140Sstevel@tonic-gate
25150Sstevel@tonic-gate /*
25160Sstevel@tonic-gate * get the associated string table header
25170Sstevel@tonic-gate */
25180Sstevel@tonic-gate if ((mp->symhdr == 0) || (mp->symhdr->sh_link >= mp->hdr.e_shnum))
25190Sstevel@tonic-gate return (-1);
25200Sstevel@tonic-gate mp->strhdr = (Shdr *)
25213912Slling (mp->shdrs + mp->symhdr->sh_link * mp->hdr.e_shentsize);
25220Sstevel@tonic-gate
25230Sstevel@tonic-gate mp->nsyms = mp->symhdr->sh_size / mp->symhdr->sh_entsize;
25240Sstevel@tonic-gate mp->hashsize = kobj_gethashsize(mp->nsyms);
25250Sstevel@tonic-gate
25260Sstevel@tonic-gate /*
25270Sstevel@tonic-gate * Allocate space for the symbol table, buckets, chains, and strings.
25280Sstevel@tonic-gate */
25290Sstevel@tonic-gate mp->symsize = mp->symhdr->sh_size +
25300Sstevel@tonic-gate (mp->hashsize + mp->nsyms) * sizeof (symid_t) + mp->strhdr->sh_size;
25310Sstevel@tonic-gate mp->symspace = kobj_zalloc(mp->symsize, KM_WAIT|KM_SCRATCH);
25320Sstevel@tonic-gate
25330Sstevel@tonic-gate mp->symtbl = mp->symspace;
25340Sstevel@tonic-gate mp->buckets = (symid_t *)(mp->symtbl + mp->symhdr->sh_size);
25350Sstevel@tonic-gate mp->chains = mp->buckets + mp->hashsize;
25360Sstevel@tonic-gate mp->strings = (char *)(mp->chains + mp->nsyms);
25370Sstevel@tonic-gate
25380Sstevel@tonic-gate if (kobj_read_file(file, mp->symtbl,
25390Sstevel@tonic-gate mp->symhdr->sh_size, mp->symhdr->sh_offset) < 0 ||
25400Sstevel@tonic-gate kobj_read_file(file, mp->strings,
25410Sstevel@tonic-gate mp->strhdr->sh_size, mp->strhdr->sh_offset) < 0)
25420Sstevel@tonic-gate return (-1);
25430Sstevel@tonic-gate
25440Sstevel@tonic-gate /*
25450Sstevel@tonic-gate * loop through the symbol table adjusting values to account
25460Sstevel@tonic-gate * for where each section got loaded into memory. Also
25470Sstevel@tonic-gate * fill in the hash table.
25480Sstevel@tonic-gate */
25490Sstevel@tonic-gate for (i = 1; i < mp->nsyms; i++) {
25500Sstevel@tonic-gate sp = (Sym *)(mp->symtbl + i * mp->symhdr->sh_entsize);
25510Sstevel@tonic-gate if (sp->st_shndx < SHN_LORESERVE) {
25520Sstevel@tonic-gate if (sp->st_shndx >= mp->hdr.e_shnum) {
25530Sstevel@tonic-gate _kobj_printf(ops, "%s bad shndx ",
25540Sstevel@tonic-gate file->_name);
25550Sstevel@tonic-gate _kobj_printf(ops, "in symbol %d\n", i);
25560Sstevel@tonic-gate return (-1);
25570Sstevel@tonic-gate }
25580Sstevel@tonic-gate shp = (Shdr *)
25590Sstevel@tonic-gate (mp->shdrs +
25600Sstevel@tonic-gate sp->st_shndx * mp->hdr.e_shentsize);
25610Sstevel@tonic-gate if (!(mp->flags & KOBJ_EXEC))
25620Sstevel@tonic-gate sp->st_value += shp->sh_addr;
25630Sstevel@tonic-gate }
25640Sstevel@tonic-gate
25650Sstevel@tonic-gate if (sp->st_name == 0 || sp->st_shndx == SHN_UNDEF)
25660Sstevel@tonic-gate continue;
25670Sstevel@tonic-gate if (sp->st_name >= mp->strhdr->sh_size)
25680Sstevel@tonic-gate return (-1);
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate symname = mp->strings + sp->st_name;
25710Sstevel@tonic-gate
25720Sstevel@tonic-gate if (!(mp->flags & KOBJ_EXEC) &&
25730Sstevel@tonic-gate ELF_ST_BIND(sp->st_info) == STB_GLOBAL) {
25740Sstevel@tonic-gate ksp = kobj_lookup_all(mp, symname, 0);
25750Sstevel@tonic-gate
25760Sstevel@tonic-gate if (ksp && ELF_ST_BIND(ksp->st_info) == STB_GLOBAL &&
25770Sstevel@tonic-gate !kobj_suppress_warning(symname) &&
25780Sstevel@tonic-gate sp->st_shndx != SHN_UNDEF &&
25790Sstevel@tonic-gate sp->st_shndx != SHN_COMMON &&
25800Sstevel@tonic-gate ksp->st_shndx != SHN_UNDEF &&
25810Sstevel@tonic-gate ksp->st_shndx != SHN_COMMON) {
25820Sstevel@tonic-gate /*
25830Sstevel@tonic-gate * Unless this symbol is a stub, it's multiply
25840Sstevel@tonic-gate * defined. Multiply-defined symbols are
25850Sstevel@tonic-gate * usually bad, but some objects (kmdb) have
25860Sstevel@tonic-gate * a legitimate need to have their own
25870Sstevel@tonic-gate * copies of common functions.
25880Sstevel@tonic-gate */
25890Sstevel@tonic-gate if ((standalone ||
25900Sstevel@tonic-gate ksp->st_value < (uintptr_t)stubs_base ||
25910Sstevel@tonic-gate ksp->st_value >= (uintptr_t)stubs_end) &&
25920Sstevel@tonic-gate !(mp->flags & KOBJ_IGNMULDEF)) {
25930Sstevel@tonic-gate _kobj_printf(ops,
25940Sstevel@tonic-gate "%s symbol ", file->_name);
25950Sstevel@tonic-gate _kobj_printf(ops,
25960Sstevel@tonic-gate "%s multiply defined\n", symname);
25970Sstevel@tonic-gate }
25980Sstevel@tonic-gate }
25990Sstevel@tonic-gate }
26003446Smrj
26010Sstevel@tonic-gate sym_insert(mp, symname, i);
26020Sstevel@tonic-gate }
26030Sstevel@tonic-gate
26040Sstevel@tonic-gate return (0);
26050Sstevel@tonic-gate }
26060Sstevel@tonic-gate
26070Sstevel@tonic-gate static int
get_ctf(struct module * mp,struct _buf * file)26080Sstevel@tonic-gate get_ctf(struct module *mp, struct _buf *file)
26090Sstevel@tonic-gate {
26100Sstevel@tonic-gate char *shstrtab, *ctfdata;
26110Sstevel@tonic-gate size_t shstrlen;
26120Sstevel@tonic-gate Shdr *shp;
26130Sstevel@tonic-gate uint_t i;
26140Sstevel@tonic-gate
26150Sstevel@tonic-gate if (_moddebug & MODDEBUG_NOCTF)
26160Sstevel@tonic-gate return (0); /* do not attempt to even load CTF data */
26170Sstevel@tonic-gate
26180Sstevel@tonic-gate if (mp->hdr.e_shstrndx >= mp->hdr.e_shnum) {
26190Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_ctf: %s, ",
26200Sstevel@tonic-gate mp->filename);
26210Sstevel@tonic-gate _kobj_printf(ops, "corrupt e_shstrndx %u\n",
26220Sstevel@tonic-gate mp->hdr.e_shstrndx);
26230Sstevel@tonic-gate return (-1);
26240Sstevel@tonic-gate }
26250Sstevel@tonic-gate
26260Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + mp->hdr.e_shstrndx * mp->hdr.e_shentsize);
26270Sstevel@tonic-gate shstrlen = shp->sh_size;
26280Sstevel@tonic-gate shstrtab = kobj_alloc(shstrlen, KM_WAIT|KM_TMP);
26290Sstevel@tonic-gate
26300Sstevel@tonic-gate if (kobj_read_file(file, shstrtab, shstrlen, shp->sh_offset) < 0) {
26310Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_ctf: %s, ",
26320Sstevel@tonic-gate mp->filename);
26330Sstevel@tonic-gate _kobj_printf(ops, "error reading section %u\n",
26340Sstevel@tonic-gate mp->hdr.e_shstrndx);
26350Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
26360Sstevel@tonic-gate return (-1);
26370Sstevel@tonic-gate }
26380Sstevel@tonic-gate
26390Sstevel@tonic-gate for (i = 0; i < mp->hdr.e_shnum; i++) {
26400Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + i * mp->hdr.e_shentsize);
26410Sstevel@tonic-gate
26420Sstevel@tonic-gate if (shp->sh_size != 0 && shp->sh_name < shstrlen &&
26430Sstevel@tonic-gate strcmp(shstrtab + shp->sh_name, ".SUNW_ctf") == 0) {
26440Sstevel@tonic-gate ctfdata = kobj_alloc(shp->sh_size, KM_WAIT|KM_SCRATCH);
26450Sstevel@tonic-gate
26460Sstevel@tonic-gate if (kobj_read_file(file, ctfdata, shp->sh_size,
26470Sstevel@tonic-gate shp->sh_offset) < 0) {
26480Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_ctf: %s, error "
26490Sstevel@tonic-gate "reading .SUNW_ctf data\n", mp->filename);
26500Sstevel@tonic-gate kobj_free(ctfdata, shp->sh_size);
26510Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
26520Sstevel@tonic-gate return (-1);
26530Sstevel@tonic-gate }
26540Sstevel@tonic-gate
26550Sstevel@tonic-gate mp->ctfdata = ctfdata;
26560Sstevel@tonic-gate mp->ctfsize = shp->sh_size;
26570Sstevel@tonic-gate break;
26580Sstevel@tonic-gate }
26590Sstevel@tonic-gate }
26600Sstevel@tonic-gate
26610Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
26620Sstevel@tonic-gate return (0);
26630Sstevel@tonic-gate }
26640Sstevel@tonic-gate
26650Sstevel@tonic-gate #define SHA1_DIGEST_LENGTH 20 /* SHA1 digest length in bytes */
26660Sstevel@tonic-gate
26670Sstevel@tonic-gate /*
26680Sstevel@tonic-gate * Return the hash of the ELF sections that are memory resident.
26690Sstevel@tonic-gate * i.e. text and data. We skip a SHT_NOBITS section since it occupies
26700Sstevel@tonic-gate * no space in the file. We use SHA1 here since libelfsign uses
26710Sstevel@tonic-gate * it and both places need to use the same algorithm.
26720Sstevel@tonic-gate */
26730Sstevel@tonic-gate static void
crypto_es_hash(struct module * mp,char * hash,char * shstrtab)26740Sstevel@tonic-gate crypto_es_hash(struct module *mp, char *hash, char *shstrtab)
26750Sstevel@tonic-gate {
26760Sstevel@tonic-gate uint_t shn;
26770Sstevel@tonic-gate Shdr *shp;
26780Sstevel@tonic-gate SHA1_CTX ctx;
26790Sstevel@tonic-gate
26800Sstevel@tonic-gate SHA1Init(&ctx);
26810Sstevel@tonic-gate
26820Sstevel@tonic-gate for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
26830Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
26840Sstevel@tonic-gate if (!(shp->sh_flags & SHF_ALLOC) || shp->sh_size == 0)
26850Sstevel@tonic-gate continue;
26860Sstevel@tonic-gate
26870Sstevel@tonic-gate /*
26880Sstevel@tonic-gate * The check should ideally be shp->sh_type == SHT_NOBITS.
26890Sstevel@tonic-gate * However, we can't do that check here as get_progbits()
26900Sstevel@tonic-gate * resets the type.
26910Sstevel@tonic-gate */
26920Sstevel@tonic-gate if (strcmp(shstrtab + shp->sh_name, ".bss") == 0)
26930Sstevel@tonic-gate continue;
26940Sstevel@tonic-gate #ifdef KOBJ_DEBUG
26950Sstevel@tonic-gate if (kobj_debug & D_DEBUG)
26960Sstevel@tonic-gate _kobj_printf(ops,
26970Sstevel@tonic-gate "krtld: crypto_es_hash: updating hash with"
26980Sstevel@tonic-gate " %s data size=%d\n", shstrtab + shp->sh_name,
26993912Slling shp->sh_size);
27000Sstevel@tonic-gate #endif
27010Sstevel@tonic-gate ASSERT(shp->sh_addr != NULL);
27020Sstevel@tonic-gate SHA1Update(&ctx, (const uint8_t *)shp->sh_addr, shp->sh_size);
27030Sstevel@tonic-gate }
27040Sstevel@tonic-gate
27050Sstevel@tonic-gate SHA1Final((uchar_t *)hash, &ctx);
27060Sstevel@tonic-gate }
27070Sstevel@tonic-gate
27080Sstevel@tonic-gate /*
27090Sstevel@tonic-gate * Get the .SUNW_signature section for the module, it it exists.
27100Sstevel@tonic-gate *
27110Sstevel@tonic-gate * This section exists only for crypto modules. None of the
27120Sstevel@tonic-gate * primary modules have this section currently.
27130Sstevel@tonic-gate */
27140Sstevel@tonic-gate static void
get_signature(struct module * mp,struct _buf * file)27150Sstevel@tonic-gate get_signature(struct module *mp, struct _buf *file)
27160Sstevel@tonic-gate {
27170Sstevel@tonic-gate char *shstrtab, *sigdata = NULL;
27180Sstevel@tonic-gate size_t shstrlen;
27190Sstevel@tonic-gate Shdr *shp;
27200Sstevel@tonic-gate uint_t i;
27210Sstevel@tonic-gate
27220Sstevel@tonic-gate if (mp->hdr.e_shstrndx >= mp->hdr.e_shnum) {
27230Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_signature: %s, ",
27240Sstevel@tonic-gate mp->filename);
27250Sstevel@tonic-gate _kobj_printf(ops, "corrupt e_shstrndx %u\n",
27260Sstevel@tonic-gate mp->hdr.e_shstrndx);
27270Sstevel@tonic-gate return;
27280Sstevel@tonic-gate }
27290Sstevel@tonic-gate
27300Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + mp->hdr.e_shstrndx * mp->hdr.e_shentsize);
27310Sstevel@tonic-gate shstrlen = shp->sh_size;
27320Sstevel@tonic-gate shstrtab = kobj_alloc(shstrlen, KM_WAIT|KM_TMP);
27330Sstevel@tonic-gate
27340Sstevel@tonic-gate if (kobj_read_file(file, shstrtab, shstrlen, shp->sh_offset) < 0) {
27350Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_signature: %s, ",
27360Sstevel@tonic-gate mp->filename);
27370Sstevel@tonic-gate _kobj_printf(ops, "error reading section %u\n",
27380Sstevel@tonic-gate mp->hdr.e_shstrndx);
27390Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
27400Sstevel@tonic-gate return;
27410Sstevel@tonic-gate }
27420Sstevel@tonic-gate
27430Sstevel@tonic-gate for (i = 0; i < mp->hdr.e_shnum; i++) {
27440Sstevel@tonic-gate shp = (Shdr *)(mp->shdrs + i * mp->hdr.e_shentsize);
27450Sstevel@tonic-gate if (shp->sh_size != 0 && shp->sh_name < shstrlen &&
27460Sstevel@tonic-gate strcmp(shstrtab + shp->sh_name,
27470Sstevel@tonic-gate ELF_SIGNATURE_SECTION) == 0) {
27480Sstevel@tonic-gate filesig_vers_t filesig_version;
27490Sstevel@tonic-gate size_t sigsize = shp->sh_size + SHA1_DIGEST_LENGTH;
27500Sstevel@tonic-gate sigdata = kobj_alloc(sigsize, KM_WAIT|KM_SCRATCH);
27510Sstevel@tonic-gate
27520Sstevel@tonic-gate if (kobj_read_file(file, sigdata, shp->sh_size,
27530Sstevel@tonic-gate shp->sh_offset) < 0) {
27540Sstevel@tonic-gate _kobj_printf(ops, "krtld: get_signature: %s,"
27550Sstevel@tonic-gate " error reading .SUNW_signature data\n",
27560Sstevel@tonic-gate mp->filename);
27570Sstevel@tonic-gate kobj_free(sigdata, sigsize);
27580Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
27590Sstevel@tonic-gate return;
27600Sstevel@tonic-gate }
27610Sstevel@tonic-gate filesig_version = ((struct filesignatures *)sigdata)->
27620Sstevel@tonic-gate filesig_sig.filesig_version;
27630Sstevel@tonic-gate if (!(filesig_version == FILESIG_VERSION1 ||
27640Sstevel@tonic-gate filesig_version == FILESIG_VERSION3)) {
27650Sstevel@tonic-gate /* skip versions we don't understand */
27660Sstevel@tonic-gate kobj_free(sigdata, sigsize);
27670Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
27680Sstevel@tonic-gate return;
27690Sstevel@tonic-gate }
27700Sstevel@tonic-gate
27710Sstevel@tonic-gate mp->sigdata = sigdata;
27720Sstevel@tonic-gate mp->sigsize = sigsize;
27730Sstevel@tonic-gate break;
27740Sstevel@tonic-gate }
27750Sstevel@tonic-gate }
27760Sstevel@tonic-gate
27770Sstevel@tonic-gate if (sigdata != NULL) {
27780Sstevel@tonic-gate crypto_es_hash(mp, sigdata + shp->sh_size, shstrtab);
27790Sstevel@tonic-gate }
27800Sstevel@tonic-gate
27810Sstevel@tonic-gate kobj_free(shstrtab, shstrlen);
27820Sstevel@tonic-gate }
27830Sstevel@tonic-gate
27840Sstevel@tonic-gate static void
add_dependent(struct module * mp,struct module * dep)27850Sstevel@tonic-gate add_dependent(struct module *mp, struct module *dep)
27860Sstevel@tonic-gate {
27870Sstevel@tonic-gate struct module_list *lp;
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate for (lp = mp->head; lp; lp = lp->next) {
27900Sstevel@tonic-gate if (lp->mp == dep)
27910Sstevel@tonic-gate return; /* already on the list */
27920Sstevel@tonic-gate }
27930Sstevel@tonic-gate
27940Sstevel@tonic-gate if (lp == NULL) {
27950Sstevel@tonic-gate lp = kobj_zalloc(sizeof (*lp), KM_WAIT);
27960Sstevel@tonic-gate
27970Sstevel@tonic-gate lp->mp = dep;
27980Sstevel@tonic-gate lp->next = NULL;
27990Sstevel@tonic-gate if (mp->tail)
28000Sstevel@tonic-gate mp->tail->next = lp;
28010Sstevel@tonic-gate else
28020Sstevel@tonic-gate mp->head = lp;
28030Sstevel@tonic-gate mp->tail = lp;
28040Sstevel@tonic-gate }
28050Sstevel@tonic-gate }
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate static int
do_dependents(struct modctl * modp,char * modname,size_t modnamelen)28080Sstevel@tonic-gate do_dependents(struct modctl *modp, char *modname, size_t modnamelen)
28090Sstevel@tonic-gate {
28100Sstevel@tonic-gate struct module *mp;
28110Sstevel@tonic-gate struct modctl *req;
28120Sstevel@tonic-gate char *d, *p, *q;
28130Sstevel@tonic-gate int c;
28140Sstevel@tonic-gate char *err_modname = NULL;
28150Sstevel@tonic-gate
28160Sstevel@tonic-gate mp = modp->mod_mp;
28170Sstevel@tonic-gate
28180Sstevel@tonic-gate if ((p = mp->depends_on) == NULL)
28190Sstevel@tonic-gate return (0);
28200Sstevel@tonic-gate
28210Sstevel@tonic-gate for (;;) {
28220Sstevel@tonic-gate /*
28230Sstevel@tonic-gate * Skip space.
28240Sstevel@tonic-gate */
28250Sstevel@tonic-gate while (*p && (*p == ' ' || *p == '\t'))
28260Sstevel@tonic-gate p++;
28270Sstevel@tonic-gate /*
28280Sstevel@tonic-gate * Get module name.
28290Sstevel@tonic-gate */
28300Sstevel@tonic-gate d = p;
28310Sstevel@tonic-gate q = modname;
28320Sstevel@tonic-gate c = 0;
28330Sstevel@tonic-gate while (*p && *p != ' ' && *p != '\t') {
28340Sstevel@tonic-gate if (c < modnamelen - 1) {
28350Sstevel@tonic-gate *q++ = *p;
28360Sstevel@tonic-gate c++;
28370Sstevel@tonic-gate }
28380Sstevel@tonic-gate p++;
28390Sstevel@tonic-gate }
28400Sstevel@tonic-gate
28410Sstevel@tonic-gate if (q == modname)
28420Sstevel@tonic-gate break;
28430Sstevel@tonic-gate
28440Sstevel@tonic-gate if (c == modnamelen - 1) {
28450Sstevel@tonic-gate char *dep = kobj_alloc(p - d + 1, KM_WAIT|KM_TMP);
28460Sstevel@tonic-gate
28470Sstevel@tonic-gate (void) strncpy(dep, d, p - d + 1);
28480Sstevel@tonic-gate dep[p - d] = '\0';
28490Sstevel@tonic-gate
28500Sstevel@tonic-gate _kobj_printf(ops, "%s: dependency ", modp->mod_modname);
28510Sstevel@tonic-gate _kobj_printf(ops, "'%s' too long ", dep);
28520Sstevel@tonic-gate _kobj_printf(ops, "(max %d chars)\n", modnamelen);
28530Sstevel@tonic-gate
28540Sstevel@tonic-gate kobj_free(dep, p - d + 1);
28550Sstevel@tonic-gate
28560Sstevel@tonic-gate return (-1);
28570Sstevel@tonic-gate }
28580Sstevel@tonic-gate
28590Sstevel@tonic-gate *q = '\0';
28600Sstevel@tonic-gate if ((req = mod_load_requisite(modp, modname)) == NULL) {
28610Sstevel@tonic-gate #ifndef KOBJ_DEBUG
28620Sstevel@tonic-gate if (_moddebug & MODDEBUG_LOADMSG) {
28630Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
28640Sstevel@tonic-gate _kobj_printf(ops,
28650Sstevel@tonic-gate "%s: unable to resolve dependency, ",
28660Sstevel@tonic-gate modp->mod_modname);
28670Sstevel@tonic-gate _kobj_printf(ops, "cannot load module '%s'\n",
28680Sstevel@tonic-gate modname);
28690Sstevel@tonic-gate #ifndef KOBJ_DEBUG
28700Sstevel@tonic-gate }
28710Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
28720Sstevel@tonic-gate if (err_modname == NULL) {
28730Sstevel@tonic-gate /*
28740Sstevel@tonic-gate * This must be the same size as the modname
28750Sstevel@tonic-gate * one.
28760Sstevel@tonic-gate */
28770Sstevel@tonic-gate err_modname = kobj_zalloc(MODMAXNAMELEN,
28780Sstevel@tonic-gate KM_WAIT);
28790Sstevel@tonic-gate
28800Sstevel@tonic-gate /*
28810Sstevel@tonic-gate * We can use strcpy() here without fearing
28820Sstevel@tonic-gate * the NULL terminator because the size of
28830Sstevel@tonic-gate * err_modname is the same as one of modname,
28840Sstevel@tonic-gate * and it's filled with zeros.
28850Sstevel@tonic-gate */
28860Sstevel@tonic-gate (void) strcpy(err_modname, modname);
28870Sstevel@tonic-gate }
28880Sstevel@tonic-gate continue;
28890Sstevel@tonic-gate }
28900Sstevel@tonic-gate
28910Sstevel@tonic-gate add_dependent(mp, req->mod_mp);
28920Sstevel@tonic-gate mod_release_mod(req);
28930Sstevel@tonic-gate
28940Sstevel@tonic-gate }
28950Sstevel@tonic-gate
28960Sstevel@tonic-gate if (err_modname != NULL) {
28970Sstevel@tonic-gate /*
28980Sstevel@tonic-gate * Copy the first module name where you detect an error to keep
28990Sstevel@tonic-gate * its behavior the same as before.
29000Sstevel@tonic-gate * This way keeps minimizing the memory use for error
29010Sstevel@tonic-gate * modules, and this might be important at boot time because
29020Sstevel@tonic-gate * the memory usage is a crucial factor for booting in most
29030Sstevel@tonic-gate * cases. You can expect more verbose messages when using
29040Sstevel@tonic-gate * a debug kernel or setting a bit in moddebug.
29050Sstevel@tonic-gate */
29060Sstevel@tonic-gate bzero(modname, MODMAXNAMELEN);
29070Sstevel@tonic-gate (void) strcpy(modname, err_modname);
29080Sstevel@tonic-gate kobj_free(err_modname, MODMAXNAMELEN);
29090Sstevel@tonic-gate return (-1);
29100Sstevel@tonic-gate }
29110Sstevel@tonic-gate
29120Sstevel@tonic-gate return (0);
29130Sstevel@tonic-gate }
29140Sstevel@tonic-gate
29150Sstevel@tonic-gate static int
do_common(struct module * mp)29160Sstevel@tonic-gate do_common(struct module *mp)
29170Sstevel@tonic-gate {
29180Sstevel@tonic-gate int err;
29190Sstevel@tonic-gate
29200Sstevel@tonic-gate /*
29210Sstevel@tonic-gate * first time through, assign all symbols defined in other
29220Sstevel@tonic-gate * modules, and count up how much common space will be needed
29230Sstevel@tonic-gate * (bss_size and bss_align)
29240Sstevel@tonic-gate */
29250Sstevel@tonic-gate if ((err = do_symbols(mp, 0)) < 0)
29260Sstevel@tonic-gate return (err);
29270Sstevel@tonic-gate /*
29280Sstevel@tonic-gate * increase bss_size by the maximum delta that could be
29290Sstevel@tonic-gate * computed by the ALIGN below
29300Sstevel@tonic-gate */
29310Sstevel@tonic-gate mp->bss_size += mp->bss_align;
29320Sstevel@tonic-gate if (mp->bss_size) {
29330Sstevel@tonic-gate if (standalone)
29340Sstevel@tonic-gate mp->bss = (uintptr_t)kobj_segbrk(&_edata, mp->bss_size,
29350Sstevel@tonic-gate MINALIGN, 0);
29360Sstevel@tonic-gate else
29370Sstevel@tonic-gate mp->bss = (uintptr_t)vmem_alloc(data_arena,
29380Sstevel@tonic-gate mp->bss_size, VM_SLEEP | VM_BESTFIT);
29390Sstevel@tonic-gate bzero((void *)mp->bss, mp->bss_size);
29400Sstevel@tonic-gate /* now assign addresses to all common symbols */
29410Sstevel@tonic-gate if ((err = do_symbols(mp, ALIGN(mp->bss, mp->bss_align))) < 0)
29420Sstevel@tonic-gate return (err);
29430Sstevel@tonic-gate }
29440Sstevel@tonic-gate return (0);
29450Sstevel@tonic-gate }
29460Sstevel@tonic-gate
29470Sstevel@tonic-gate static int
do_symbols(struct module * mp,Elf64_Addr bss_base)29480Sstevel@tonic-gate do_symbols(struct module *mp, Elf64_Addr bss_base)
29490Sstevel@tonic-gate {
29500Sstevel@tonic-gate int bss_align;
29510Sstevel@tonic-gate uintptr_t bss_ptr;
29520Sstevel@tonic-gate int err;
29530Sstevel@tonic-gate int i;
29540Sstevel@tonic-gate Sym *sp, *sp1;
29550Sstevel@tonic-gate char *name;
29560Sstevel@tonic-gate int assign;
29570Sstevel@tonic-gate int resolved = 1;
29580Sstevel@tonic-gate
29590Sstevel@tonic-gate /*
29600Sstevel@tonic-gate * Nothing left to do (optimization).
29610Sstevel@tonic-gate */
29620Sstevel@tonic-gate if (mp->flags & KOBJ_RESOLVED)
29630Sstevel@tonic-gate return (0);
29640Sstevel@tonic-gate
29650Sstevel@tonic-gate assign = (bss_base) ? 1 : 0;
29660Sstevel@tonic-gate bss_ptr = bss_base;
29670Sstevel@tonic-gate bss_align = 0;
29680Sstevel@tonic-gate err = 0;
29690Sstevel@tonic-gate
29700Sstevel@tonic-gate for (i = 1; i < mp->nsyms; i++) {
29710Sstevel@tonic-gate sp = (Sym *)(mp->symtbl + mp->symhdr->sh_entsize * i);
29720Sstevel@tonic-gate /*
29730Sstevel@tonic-gate * we know that st_name is in bounds, since get_sections
29740Sstevel@tonic-gate * has already checked all of the symbols
29750Sstevel@tonic-gate */
29760Sstevel@tonic-gate name = mp->strings + sp->st_name;
29770Sstevel@tonic-gate if (sp->st_shndx != SHN_UNDEF && sp->st_shndx != SHN_COMMON)
29780Sstevel@tonic-gate continue;
29795648Ssetje #if defined(__sparc)
29800Sstevel@tonic-gate /*
29810Sstevel@tonic-gate * Register symbols are ignored in the kernel
29820Sstevel@tonic-gate */
29830Sstevel@tonic-gate if (ELF_ST_TYPE(sp->st_info) == STT_SPARC_REGISTER) {
29840Sstevel@tonic-gate if (*name != '\0') {
29850Sstevel@tonic-gate _kobj_printf(ops, "%s: named REGISTER symbol ",
29863912Slling mp->filename);
29870Sstevel@tonic-gate _kobj_printf(ops, "not supported '%s'\n",
29883912Slling name);
29890Sstevel@tonic-gate err = DOSYM_UNDEF;
29900Sstevel@tonic-gate }
29910Sstevel@tonic-gate continue;
29920Sstevel@tonic-gate }
29930Sstevel@tonic-gate #endif /* __sparc */
29940Sstevel@tonic-gate /*
29950Sstevel@tonic-gate * TLS symbols are ignored in the kernel
29960Sstevel@tonic-gate */
29970Sstevel@tonic-gate if (ELF_ST_TYPE(sp->st_info) == STT_TLS) {
29980Sstevel@tonic-gate _kobj_printf(ops, "%s: TLS symbol ",
29993912Slling mp->filename);
30000Sstevel@tonic-gate _kobj_printf(ops, "not supported '%s'\n",
30013912Slling name);
30020Sstevel@tonic-gate err = DOSYM_UNDEF;
30030Sstevel@tonic-gate continue;
30040Sstevel@tonic-gate }
30050Sstevel@tonic-gate
30060Sstevel@tonic-gate if (ELF_ST_BIND(sp->st_info) != STB_LOCAL) {
30070Sstevel@tonic-gate if ((sp1 = kobj_lookup_all(mp, name, 0)) != NULL) {
30080Sstevel@tonic-gate sp->st_shndx = SHN_ABS;
30090Sstevel@tonic-gate sp->st_value = sp1->st_value;
30100Sstevel@tonic-gate continue;
30110Sstevel@tonic-gate }
30120Sstevel@tonic-gate }
30130Sstevel@tonic-gate
30140Sstevel@tonic-gate if (sp->st_shndx == SHN_UNDEF) {
30150Sstevel@tonic-gate resolved = 0;
30160Sstevel@tonic-gate
30170Sstevel@tonic-gate if (strncmp(name, sdt_prefix, strlen(sdt_prefix)) == 0)
30180Sstevel@tonic-gate continue;
30190Sstevel@tonic-gate
30200Sstevel@tonic-gate /*
30210Sstevel@tonic-gate * If it's not a weak reference and it's
30220Sstevel@tonic-gate * not a primary object, it's an error.
30230Sstevel@tonic-gate * (Primary objects may take more than
30240Sstevel@tonic-gate * one pass to resolve)
30250Sstevel@tonic-gate */
30260Sstevel@tonic-gate if (!(mp->flags & KOBJ_PRIM) &&
30270Sstevel@tonic-gate ELF_ST_BIND(sp->st_info) != STB_WEAK) {
30280Sstevel@tonic-gate _kobj_printf(ops, "%s: undefined symbol",
30290Sstevel@tonic-gate mp->filename);
30300Sstevel@tonic-gate _kobj_printf(ops, " '%s'\n", name);
30310Sstevel@tonic-gate /*
30320Sstevel@tonic-gate * Try to determine whether this symbol
30330Sstevel@tonic-gate * represents a dependency on obsolete
30340Sstevel@tonic-gate * unsafe driver support. This is just
30350Sstevel@tonic-gate * to make the warning more informative.
30360Sstevel@tonic-gate */
30370Sstevel@tonic-gate if (strcmp(name, "sleep") == 0 ||
30380Sstevel@tonic-gate strcmp(name, "unsleep") == 0 ||
30390Sstevel@tonic-gate strcmp(name, "wakeup") == 0 ||
30400Sstevel@tonic-gate strcmp(name, "bsd_compat_ioctl") == 0 ||
30410Sstevel@tonic-gate strcmp(name, "unsafe_driver") == 0 ||
30420Sstevel@tonic-gate strncmp(name, "spl", 3) == 0 ||
30430Sstevel@tonic-gate strncmp(name, "i_ddi_spl", 9) == 0)
30440Sstevel@tonic-gate err = DOSYM_UNSAFE;
30450Sstevel@tonic-gate if (err == 0)
30460Sstevel@tonic-gate err = DOSYM_UNDEF;
30470Sstevel@tonic-gate }
30480Sstevel@tonic-gate continue;
30490Sstevel@tonic-gate }
30500Sstevel@tonic-gate /*
30510Sstevel@tonic-gate * It's a common symbol - st_value is the
30520Sstevel@tonic-gate * required alignment.
30530Sstevel@tonic-gate */
30540Sstevel@tonic-gate if (sp->st_value > bss_align)
30550Sstevel@tonic-gate bss_align = sp->st_value;
30560Sstevel@tonic-gate bss_ptr = ALIGN(bss_ptr, sp->st_value);
30570Sstevel@tonic-gate if (assign) {
30580Sstevel@tonic-gate sp->st_shndx = SHN_ABS;
30590Sstevel@tonic-gate sp->st_value = bss_ptr;
30600Sstevel@tonic-gate }
30610Sstevel@tonic-gate bss_ptr += sp->st_size;
30620Sstevel@tonic-gate }
30630Sstevel@tonic-gate if (err)
30640Sstevel@tonic-gate return (err);
30650Sstevel@tonic-gate if (assign == 0 && mp->bss == NULL) {
30660Sstevel@tonic-gate mp->bss_align = bss_align;
30670Sstevel@tonic-gate mp->bss_size = bss_ptr;
30680Sstevel@tonic-gate } else if (resolved) {
30690Sstevel@tonic-gate mp->flags |= KOBJ_RESOLVED;
30700Sstevel@tonic-gate }
30710Sstevel@tonic-gate
30720Sstevel@tonic-gate return (0);
30730Sstevel@tonic-gate }
30740Sstevel@tonic-gate
30750Sstevel@tonic-gate uint_t
kobj_hash_name(const char * p)30760Sstevel@tonic-gate kobj_hash_name(const char *p)
30770Sstevel@tonic-gate {
30785648Ssetje uint_t g;
30790Sstevel@tonic-gate uint_t hval;
30800Sstevel@tonic-gate
30810Sstevel@tonic-gate hval = 0;
30820Sstevel@tonic-gate while (*p) {
30830Sstevel@tonic-gate hval = (hval << 4) + *p++;
30840Sstevel@tonic-gate if ((g = (hval & 0xf0000000)) != 0)
30850Sstevel@tonic-gate hval ^= g >> 24;
30860Sstevel@tonic-gate hval &= ~g;
30870Sstevel@tonic-gate }
30880Sstevel@tonic-gate return (hval);
30890Sstevel@tonic-gate }
30900Sstevel@tonic-gate
30910Sstevel@tonic-gate /* look for name in all modules */
30920Sstevel@tonic-gate uintptr_t
kobj_getsymvalue(char * name,int kernelonly)30930Sstevel@tonic-gate kobj_getsymvalue(char *name, int kernelonly)
30940Sstevel@tonic-gate {
30950Sstevel@tonic-gate Sym *sp;
30960Sstevel@tonic-gate struct modctl *modp;
30970Sstevel@tonic-gate struct module *mp;
30980Sstevel@tonic-gate uintptr_t value = 0;
30990Sstevel@tonic-gate
31000Sstevel@tonic-gate if ((sp = kobj_lookup_kernel(name)) != NULL)
31010Sstevel@tonic-gate return ((uintptr_t)sp->st_value);
31020Sstevel@tonic-gate
31030Sstevel@tonic-gate if (kernelonly)
31040Sstevel@tonic-gate return (0); /* didn't find it in the kernel so give up */
31050Sstevel@tonic-gate
31060Sstevel@tonic-gate mutex_enter(&mod_lock);
31070Sstevel@tonic-gate modp = &modules;
31080Sstevel@tonic-gate do {
31090Sstevel@tonic-gate mp = (struct module *)modp->mod_mp;
31100Sstevel@tonic-gate if (mp && !(mp->flags & KOBJ_PRIM) && modp->mod_loaded &&
31110Sstevel@tonic-gate (sp = lookup_one(mp, name))) {
31120Sstevel@tonic-gate value = (uintptr_t)sp->st_value;
31130Sstevel@tonic-gate break;
31140Sstevel@tonic-gate }
31150Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules);
31160Sstevel@tonic-gate mutex_exit(&mod_lock);
31170Sstevel@tonic-gate return (value);
31180Sstevel@tonic-gate }
31190Sstevel@tonic-gate
31200Sstevel@tonic-gate /* look for a symbol near value. */
31210Sstevel@tonic-gate char *
kobj_getsymname(uintptr_t value,ulong_t * offset)31220Sstevel@tonic-gate kobj_getsymname(uintptr_t value, ulong_t *offset)
31230Sstevel@tonic-gate {
31240Sstevel@tonic-gate char *name = NULL;
31250Sstevel@tonic-gate struct modctl *modp;
31260Sstevel@tonic-gate
31270Sstevel@tonic-gate struct modctl_list *lp;
31280Sstevel@tonic-gate struct module *mp;
31290Sstevel@tonic-gate
31300Sstevel@tonic-gate /*
31310Sstevel@tonic-gate * Loop through the primary kernel modules.
31320Sstevel@tonic-gate */
31330Sstevel@tonic-gate for (lp = kobj_lm_lookup(KOBJ_LM_PRIMARY); lp; lp = lp->modl_next) {
31340Sstevel@tonic-gate mp = mod(lp);
31350Sstevel@tonic-gate
31360Sstevel@tonic-gate if ((name = kobj_searchsym(mp, value, offset)) != NULL)
31370Sstevel@tonic-gate return (name);
31380Sstevel@tonic-gate }
31390Sstevel@tonic-gate
31400Sstevel@tonic-gate mutex_enter(&mod_lock);
31410Sstevel@tonic-gate modp = &modules;
31420Sstevel@tonic-gate do {
31430Sstevel@tonic-gate mp = (struct module *)modp->mod_mp;
31440Sstevel@tonic-gate if (mp && !(mp->flags & KOBJ_PRIM) && modp->mod_loaded &&
31450Sstevel@tonic-gate (name = kobj_searchsym(mp, value, offset)))
31460Sstevel@tonic-gate break;
31470Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules);
31480Sstevel@tonic-gate mutex_exit(&mod_lock);
31490Sstevel@tonic-gate return (name);
31500Sstevel@tonic-gate }
31510Sstevel@tonic-gate
31520Sstevel@tonic-gate /* return address of symbol and size */
31530Sstevel@tonic-gate
31540Sstevel@tonic-gate uintptr_t
kobj_getelfsym(char * name,void * mp,int * size)31550Sstevel@tonic-gate kobj_getelfsym(char *name, void *mp, int *size)
31560Sstevel@tonic-gate {
31570Sstevel@tonic-gate Sym *sp;
31580Sstevel@tonic-gate
31590Sstevel@tonic-gate if (mp == NULL)
31600Sstevel@tonic-gate sp = kobj_lookup_kernel(name);
31610Sstevel@tonic-gate else
31620Sstevel@tonic-gate sp = lookup_one(mp, name);
31630Sstevel@tonic-gate
31640Sstevel@tonic-gate if (sp == NULL)
31650Sstevel@tonic-gate return (0);
31660Sstevel@tonic-gate
31670Sstevel@tonic-gate *size = (int)sp->st_size;
31680Sstevel@tonic-gate return ((uintptr_t)sp->st_value);
31690Sstevel@tonic-gate }
31700Sstevel@tonic-gate
31710Sstevel@tonic-gate uintptr_t
kobj_lookup(struct module * mod,const char * name)31721414Scindi kobj_lookup(struct module *mod, const char *name)
31730Sstevel@tonic-gate {
31740Sstevel@tonic-gate Sym *sp;
31750Sstevel@tonic-gate
31760Sstevel@tonic-gate sp = lookup_one(mod, name);
31770Sstevel@tonic-gate
31780Sstevel@tonic-gate if (sp == NULL)
31790Sstevel@tonic-gate return (0);
31800Sstevel@tonic-gate
31810Sstevel@tonic-gate return ((uintptr_t)sp->st_value);
31820Sstevel@tonic-gate }
31830Sstevel@tonic-gate
31840Sstevel@tonic-gate char *
kobj_searchsym(struct module * mp,uintptr_t value,ulong_t * offset)31850Sstevel@tonic-gate kobj_searchsym(struct module *mp, uintptr_t value, ulong_t *offset)
31860Sstevel@tonic-gate {
31870Sstevel@tonic-gate Sym *symtabptr;
31880Sstevel@tonic-gate char *strtabptr;
31890Sstevel@tonic-gate int symnum;
31900Sstevel@tonic-gate Sym *sym;
31910Sstevel@tonic-gate Sym *cursym;
31920Sstevel@tonic-gate uintptr_t curval;
31930Sstevel@tonic-gate
31940Sstevel@tonic-gate *offset = (ulong_t)-1l; /* assume not found */
31950Sstevel@tonic-gate cursym = NULL;
31960Sstevel@tonic-gate
31970Sstevel@tonic-gate if (kobj_addrcheck(mp, (void *)value) != 0)
31980Sstevel@tonic-gate return (NULL); /* not in this module */
31990Sstevel@tonic-gate
32000Sstevel@tonic-gate strtabptr = mp->strings;
32010Sstevel@tonic-gate symtabptr = (Sym *)mp->symtbl;
32020Sstevel@tonic-gate
32030Sstevel@tonic-gate /*
32040Sstevel@tonic-gate * Scan the module's symbol table for a symbol <= value
32050Sstevel@tonic-gate */
32060Sstevel@tonic-gate for (symnum = 1, sym = symtabptr + 1;
32070Sstevel@tonic-gate symnum < mp->nsyms; symnum++, sym = (Sym *)
32080Sstevel@tonic-gate ((uintptr_t)sym + mp->symhdr->sh_entsize)) {
32090Sstevel@tonic-gate if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
32100Sstevel@tonic-gate if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
32110Sstevel@tonic-gate continue;
32120Sstevel@tonic-gate if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
32130Sstevel@tonic-gate ELF_ST_TYPE(sym->st_info) != STT_FUNC)
32140Sstevel@tonic-gate continue;
32150Sstevel@tonic-gate }
32160Sstevel@tonic-gate
32170Sstevel@tonic-gate curval = (uintptr_t)sym->st_value;
32180Sstevel@tonic-gate
32190Sstevel@tonic-gate if (curval > value)
32200Sstevel@tonic-gate continue;
32210Sstevel@tonic-gate
32220Sstevel@tonic-gate /*
32230Sstevel@tonic-gate * If one or both are functions...
32240Sstevel@tonic-gate */
32250Sstevel@tonic-gate if (ELF_ST_TYPE(sym->st_info) == STT_FUNC || (cursym != NULL &&
32260Sstevel@tonic-gate ELF_ST_TYPE(cursym->st_info) == STT_FUNC)) {
32270Sstevel@tonic-gate /* Ignore if the address is out of the bounds */
32280Sstevel@tonic-gate if (value - sym->st_value >= sym->st_size)
32290Sstevel@tonic-gate continue;
32300Sstevel@tonic-gate
32310Sstevel@tonic-gate if (cursym != NULL &&
32320Sstevel@tonic-gate ELF_ST_TYPE(cursym->st_info) == STT_FUNC) {
32330Sstevel@tonic-gate /* Prefer the function to the non-function */
32340Sstevel@tonic-gate if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
32350Sstevel@tonic-gate continue;
32360Sstevel@tonic-gate
32370Sstevel@tonic-gate /* Prefer the larger of the two functions */
32380Sstevel@tonic-gate if (sym->st_size <= cursym->st_size)
32390Sstevel@tonic-gate continue;
32400Sstevel@tonic-gate }
32410Sstevel@tonic-gate } else if (value - curval >= *offset) {
32420Sstevel@tonic-gate continue;
32430Sstevel@tonic-gate }
32440Sstevel@tonic-gate
32450Sstevel@tonic-gate *offset = (ulong_t)(value - curval);
32460Sstevel@tonic-gate cursym = sym;
32470Sstevel@tonic-gate }
32480Sstevel@tonic-gate if (cursym == NULL)
32490Sstevel@tonic-gate return (NULL);
32500Sstevel@tonic-gate
32510Sstevel@tonic-gate return (strtabptr + cursym->st_name);
32520Sstevel@tonic-gate }
32530Sstevel@tonic-gate
32540Sstevel@tonic-gate Sym *
kobj_lookup_all(struct module * mp,char * name,int include_self)32550Sstevel@tonic-gate kobj_lookup_all(struct module *mp, char *name, int include_self)
32560Sstevel@tonic-gate {
32570Sstevel@tonic-gate Sym *sp;
32580Sstevel@tonic-gate struct module_list *mlp;
32590Sstevel@tonic-gate struct modctl_list *clp;
32600Sstevel@tonic-gate struct module *mmp;
32610Sstevel@tonic-gate
32620Sstevel@tonic-gate if (include_self && (sp = lookup_one(mp, name)) != NULL)
32630Sstevel@tonic-gate return (sp);
32640Sstevel@tonic-gate
32650Sstevel@tonic-gate for (mlp = mp->head; mlp; mlp = mlp->next) {
32660Sstevel@tonic-gate if ((sp = lookup_one(mlp->mp, name)) != NULL &&
32670Sstevel@tonic-gate ELF_ST_BIND(sp->st_info) != STB_LOCAL)
32680Sstevel@tonic-gate return (sp);
32690Sstevel@tonic-gate }
32700Sstevel@tonic-gate
32710Sstevel@tonic-gate /*
32720Sstevel@tonic-gate * Loop through the primary kernel modules.
32730Sstevel@tonic-gate */
32740Sstevel@tonic-gate for (clp = kobj_lm_lookup(KOBJ_LM_PRIMARY); clp; clp = clp->modl_next) {
32750Sstevel@tonic-gate mmp = mod(clp);
32760Sstevel@tonic-gate
32770Sstevel@tonic-gate if (mmp == NULL || mp == mmp)
32780Sstevel@tonic-gate continue;
32790Sstevel@tonic-gate
32800Sstevel@tonic-gate if ((sp = lookup_one(mmp, name)) != NULL &&
32810Sstevel@tonic-gate ELF_ST_BIND(sp->st_info) != STB_LOCAL)
32820Sstevel@tonic-gate return (sp);
32830Sstevel@tonic-gate }
32840Sstevel@tonic-gate return (NULL);
32850Sstevel@tonic-gate }
32860Sstevel@tonic-gate
32870Sstevel@tonic-gate Sym *
kobj_lookup_kernel(const char * name)32880Sstevel@tonic-gate kobj_lookup_kernel(const char *name)
32890Sstevel@tonic-gate {
32900Sstevel@tonic-gate struct modctl_list *lp;
32910Sstevel@tonic-gate struct module *mp;
32920Sstevel@tonic-gate Sym *sp;
32930Sstevel@tonic-gate
32940Sstevel@tonic-gate /*
32950Sstevel@tonic-gate * Loop through the primary kernel modules.
32960Sstevel@tonic-gate */
32970Sstevel@tonic-gate for (lp = kobj_lm_lookup(KOBJ_LM_PRIMARY); lp; lp = lp->modl_next) {
32980Sstevel@tonic-gate mp = mod(lp);
32990Sstevel@tonic-gate
33000Sstevel@tonic-gate if (mp == NULL)
33010Sstevel@tonic-gate continue;
33020Sstevel@tonic-gate
33030Sstevel@tonic-gate if ((sp = lookup_one(mp, name)) != NULL)
33040Sstevel@tonic-gate return (sp);
33050Sstevel@tonic-gate }
33060Sstevel@tonic-gate return (NULL);
33070Sstevel@tonic-gate }
33080Sstevel@tonic-gate
33090Sstevel@tonic-gate static Sym *
lookup_one(struct module * mp,const char * name)33100Sstevel@tonic-gate lookup_one(struct module *mp, const char *name)
33110Sstevel@tonic-gate {
33120Sstevel@tonic-gate symid_t *ip;
33130Sstevel@tonic-gate char *name1;
33140Sstevel@tonic-gate Sym *sp;
33150Sstevel@tonic-gate
33160Sstevel@tonic-gate for (ip = &mp->buckets[kobj_hash_name(name) % mp->hashsize]; *ip;
33170Sstevel@tonic-gate ip = &mp->chains[*ip]) {
33180Sstevel@tonic-gate sp = (Sym *)(mp->symtbl +
33190Sstevel@tonic-gate mp->symhdr->sh_entsize * *ip);
33200Sstevel@tonic-gate name1 = mp->strings + sp->st_name;
33210Sstevel@tonic-gate if (strcmp(name, name1) == 0 &&
33220Sstevel@tonic-gate ELF_ST_TYPE(sp->st_info) != STT_FILE &&
33230Sstevel@tonic-gate sp->st_shndx != SHN_UNDEF &&
33240Sstevel@tonic-gate sp->st_shndx != SHN_COMMON)
33250Sstevel@tonic-gate return (sp);
33260Sstevel@tonic-gate }
33270Sstevel@tonic-gate return (NULL);
33280Sstevel@tonic-gate }
33290Sstevel@tonic-gate
33300Sstevel@tonic-gate /*
33310Sstevel@tonic-gate * Lookup a given symbol pointer in the module's symbol hash. If the symbol
33320Sstevel@tonic-gate * is hashed, return the symbol pointer; otherwise return NULL.
33330Sstevel@tonic-gate */
33340Sstevel@tonic-gate static Sym *
sym_lookup(struct module * mp,Sym * ksp)33350Sstevel@tonic-gate sym_lookup(struct module *mp, Sym *ksp)
33360Sstevel@tonic-gate {
33370Sstevel@tonic-gate char *name = mp->strings + ksp->st_name;
33380Sstevel@tonic-gate symid_t *ip;
33390Sstevel@tonic-gate Sym *sp;
33400Sstevel@tonic-gate
33410Sstevel@tonic-gate for (ip = &mp->buckets[kobj_hash_name(name) % mp->hashsize]; *ip;
33420Sstevel@tonic-gate ip = &mp->chains[*ip]) {
33430Sstevel@tonic-gate sp = (Sym *)(mp->symtbl + mp->symhdr->sh_entsize * *ip);
33440Sstevel@tonic-gate if (sp == ksp)
33450Sstevel@tonic-gate return (ksp);
33460Sstevel@tonic-gate }
33470Sstevel@tonic-gate return (NULL);
33480Sstevel@tonic-gate }
33490Sstevel@tonic-gate
33500Sstevel@tonic-gate static void
sym_insert(struct module * mp,char * name,symid_t index)33510Sstevel@tonic-gate sym_insert(struct module *mp, char *name, symid_t index)
33520Sstevel@tonic-gate {
33530Sstevel@tonic-gate symid_t *ip;
33540Sstevel@tonic-gate
33550Sstevel@tonic-gate #ifdef KOBJ_DEBUG
33560Sstevel@tonic-gate if (kobj_debug & D_SYMBOLS) {
33570Sstevel@tonic-gate static struct module *lastmp = NULL;
33580Sstevel@tonic-gate Sym *sp;
33590Sstevel@tonic-gate if (lastmp != mp) {
33600Sstevel@tonic-gate _kobj_printf(ops,
33610Sstevel@tonic-gate "krtld: symbol entry: file=%s\n",
33620Sstevel@tonic-gate mp->filename);
33630Sstevel@tonic-gate _kobj_printf(ops,
33640Sstevel@tonic-gate "krtld:\tsymndx\tvalue\t\t"
33650Sstevel@tonic-gate "symbol name\n");
33660Sstevel@tonic-gate lastmp = mp;
33670Sstevel@tonic-gate }
33680Sstevel@tonic-gate sp = (Sym *)(mp->symtbl +
33693912Slling index * mp->symhdr->sh_entsize);
33700Sstevel@tonic-gate _kobj_printf(ops, "krtld:\t[%3d]", index);
33710Sstevel@tonic-gate _kobj_printf(ops, "\t0x%lx", sp->st_value);
33720Sstevel@tonic-gate _kobj_printf(ops, "\t%s\n", name);
33730Sstevel@tonic-gate }
33740Sstevel@tonic-gate
33750Sstevel@tonic-gate #endif
33760Sstevel@tonic-gate for (ip = &mp->buckets[kobj_hash_name(name) % mp->hashsize]; *ip;
33770Sstevel@tonic-gate ip = &mp->chains[*ip]) {
33780Sstevel@tonic-gate ;
33790Sstevel@tonic-gate }
33800Sstevel@tonic-gate *ip = index;
33810Sstevel@tonic-gate }
33820Sstevel@tonic-gate
33830Sstevel@tonic-gate struct modctl *
kobj_boot_mod_lookup(const char * modname)33840Sstevel@tonic-gate kobj_boot_mod_lookup(const char *modname)
33850Sstevel@tonic-gate {
33860Sstevel@tonic-gate struct modctl *mctl = kobj_modules;
33870Sstevel@tonic-gate
33880Sstevel@tonic-gate do {
33890Sstevel@tonic-gate if (strcmp(modname, mctl->mod_modname) == 0)
33900Sstevel@tonic-gate return (mctl);
33910Sstevel@tonic-gate } while ((mctl = mctl->mod_next) != kobj_modules);
33920Sstevel@tonic-gate
33930Sstevel@tonic-gate return (NULL);
33940Sstevel@tonic-gate }
33950Sstevel@tonic-gate
33960Sstevel@tonic-gate /*
3397309Scth * Determine if the module exists.
3398309Scth */
3399309Scth int
kobj_path_exists(char * name,int use_path)3400309Scth kobj_path_exists(char *name, int use_path)
3401309Scth {
3402309Scth struct _buf *file;
3403309Scth
3404309Scth file = kobj_open_path(name, use_path, 1);
3405309Scth #ifdef MODDIR_SUFFIX
3406309Scth if (file == (struct _buf *)-1)
3407309Scth file = kobj_open_path(name, use_path, 0);
3408309Scth #endif /* MODDIR_SUFFIX */
3409309Scth if (file == (struct _buf *)-1)
3410309Scth return (0);
3411309Scth kobj_close_file(file);
3412309Scth return (1);
3413309Scth }
3414309Scth
3415309Scth /*
34160Sstevel@tonic-gate * fullname is dynamically allocated to be able to hold the
34170Sstevel@tonic-gate * maximum size string that can be constructed from name.
34180Sstevel@tonic-gate * path is exactly like the shell PATH variable.
34190Sstevel@tonic-gate */
34200Sstevel@tonic-gate struct _buf *
kobj_open_path(char * name,int use_path,int use_moddir_suffix)34210Sstevel@tonic-gate kobj_open_path(char *name, int use_path, int use_moddir_suffix)
34220Sstevel@tonic-gate {
34230Sstevel@tonic-gate char *p, *q;
34240Sstevel@tonic-gate char *pathp;
34250Sstevel@tonic-gate char *pathpsave;
34260Sstevel@tonic-gate char *fullname;
34270Sstevel@tonic-gate int maxpathlen;
34280Sstevel@tonic-gate struct _buf *file;
34290Sstevel@tonic-gate
34300Sstevel@tonic-gate #if !defined(MODDIR_SUFFIX)
34310Sstevel@tonic-gate use_moddir_suffix = B_FALSE;
34320Sstevel@tonic-gate #endif
34330Sstevel@tonic-gate
34340Sstevel@tonic-gate if (!use_path)
34350Sstevel@tonic-gate pathp = ""; /* use name as specified */
34360Sstevel@tonic-gate else
34373446Smrj pathp = kobj_module_path;
34383446Smrj /* use configured default path */
34390Sstevel@tonic-gate
34400Sstevel@tonic-gate pathpsave = pathp; /* keep this for error reporting */
34410Sstevel@tonic-gate
34420Sstevel@tonic-gate /*
34430Sstevel@tonic-gate * Allocate enough space for the largest possible fullname.
34440Sstevel@tonic-gate * since path is of the form <directory> : <directory> : ...
34450Sstevel@tonic-gate * we're potentially allocating a little more than we need to
34460Sstevel@tonic-gate * but we'll allocate the exact amount when we find the right directory.
34470Sstevel@tonic-gate * (The + 3 below is one for NULL terminator and one for the '/'
34480Sstevel@tonic-gate * we might have to add at the beginning of path and one for
34490Sstevel@tonic-gate * the '/' between path and name.)
34500Sstevel@tonic-gate */
34510Sstevel@tonic-gate maxpathlen = strlen(pathp) + strlen(name) + 3;
34520Sstevel@tonic-gate /* sizeof includes null */
34530Sstevel@tonic-gate maxpathlen += sizeof (slash_moddir_suffix_slash) - 1;
34540Sstevel@tonic-gate fullname = kobj_zalloc(maxpathlen, KM_WAIT);
34550Sstevel@tonic-gate
34560Sstevel@tonic-gate for (;;) {
34570Sstevel@tonic-gate p = fullname;
34580Sstevel@tonic-gate if (*pathp != '\0' && *pathp != '/')
34590Sstevel@tonic-gate *p++ = '/'; /* path must start with '/' */
34600Sstevel@tonic-gate while (*pathp && *pathp != ':' && *pathp != ' ')
34610Sstevel@tonic-gate *p++ = *pathp++;
34620Sstevel@tonic-gate if (p != fullname && p[-1] != '/')
34630Sstevel@tonic-gate *p++ = '/';
34640Sstevel@tonic-gate if (use_moddir_suffix) {
34650Sstevel@tonic-gate char *b = basename(name);
34660Sstevel@tonic-gate char *s;
34670Sstevel@tonic-gate
34680Sstevel@tonic-gate /* copy everything up to the base name */
34690Sstevel@tonic-gate q = name;
34700Sstevel@tonic-gate while (q != b && *q)
34710Sstevel@tonic-gate *p++ = *q++;
34720Sstevel@tonic-gate s = slash_moddir_suffix_slash;
34730Sstevel@tonic-gate while (*s)
34740Sstevel@tonic-gate *p++ = *s++;
34750Sstevel@tonic-gate /* copy the rest */
34760Sstevel@tonic-gate while (*b)
34770Sstevel@tonic-gate *p++ = *b++;
34780Sstevel@tonic-gate } else {
34790Sstevel@tonic-gate q = name;
34800Sstevel@tonic-gate while (*q)
34810Sstevel@tonic-gate *p++ = *q++;
34820Sstevel@tonic-gate }
34830Sstevel@tonic-gate *p = 0;
34840Sstevel@tonic-gate if ((file = kobj_open_file(fullname)) != (struct _buf *)-1) {
34850Sstevel@tonic-gate kobj_free(fullname, maxpathlen);
34860Sstevel@tonic-gate return (file);
34870Sstevel@tonic-gate }
3488*10047SPramod.Batni@Sun.COM while (*pathp == ' ')
3489*10047SPramod.Batni@Sun.COM pathp++;
34900Sstevel@tonic-gate if (*pathp == 0)
34910Sstevel@tonic-gate break;
3492*10047SPramod.Batni@Sun.COM
34930Sstevel@tonic-gate }
34940Sstevel@tonic-gate kobj_free(fullname, maxpathlen);
34950Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG) {
34960Sstevel@tonic-gate _kobj_printf(ops, "can't open %s,", name);
34970Sstevel@tonic-gate _kobj_printf(ops, " path is %s\n", pathpsave);
34980Sstevel@tonic-gate }
34990Sstevel@tonic-gate return ((struct _buf *)-1);
35000Sstevel@tonic-gate }
35010Sstevel@tonic-gate
35020Sstevel@tonic-gate intptr_t
kobj_open(char * filename)35030Sstevel@tonic-gate kobj_open(char *filename)
35040Sstevel@tonic-gate {
35050Sstevel@tonic-gate struct vnode *vp;
35060Sstevel@tonic-gate int fd;
35070Sstevel@tonic-gate
35080Sstevel@tonic-gate if (_modrootloaded) {
35090Sstevel@tonic-gate struct kobjopen_tctl *ltp = kobjopen_alloc(filename);
35100Sstevel@tonic-gate int Errno;
35110Sstevel@tonic-gate
35120Sstevel@tonic-gate /*
35130Sstevel@tonic-gate * Hand off the open to a thread who has a
35140Sstevel@tonic-gate * stack size capable handling the request.
35150Sstevel@tonic-gate */
35160Sstevel@tonic-gate if (curthread != &t0) {
35170Sstevel@tonic-gate (void) thread_create(NULL, DEFAULTSTKSZ * 2,
35180Sstevel@tonic-gate kobjopen_thread, ltp, 0, &p0, TS_RUN, maxclsyspri);
35190Sstevel@tonic-gate sema_p(<p->sema);
35200Sstevel@tonic-gate Errno = ltp->Errno;
35210Sstevel@tonic-gate vp = ltp->vp;
35220Sstevel@tonic-gate } else {
35230Sstevel@tonic-gate /*
35240Sstevel@tonic-gate * 1098067: module creds should not be those of the
35250Sstevel@tonic-gate * caller
35260Sstevel@tonic-gate */
35270Sstevel@tonic-gate cred_t *saved_cred = curthread->t_cred;
35280Sstevel@tonic-gate curthread->t_cred = kcred;
35291544Seschrock Errno = vn_openat(filename, UIO_SYSSPACE, FREAD, 0, &vp,
35305331Samw 0, 0, rootdir, -1);
35310Sstevel@tonic-gate curthread->t_cred = saved_cred;
35320Sstevel@tonic-gate }
35330Sstevel@tonic-gate kobjopen_free(ltp);
35340Sstevel@tonic-gate
35350Sstevel@tonic-gate if (Errno) {
35360Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG) {
35370Sstevel@tonic-gate _kobj_printf(ops,
35380Sstevel@tonic-gate "kobj_open: vn_open of %s fails, ",
35390Sstevel@tonic-gate filename);
35400Sstevel@tonic-gate _kobj_printf(ops, "Errno = %d\n", Errno);
35410Sstevel@tonic-gate }
35420Sstevel@tonic-gate return (-1);
35430Sstevel@tonic-gate } else {
35440Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG) {
35450Sstevel@tonic-gate _kobj_printf(ops, "kobj_open: '%s'", filename);
35460Sstevel@tonic-gate _kobj_printf(ops, " vp = %p\n", vp);
35470Sstevel@tonic-gate }
35480Sstevel@tonic-gate return ((intptr_t)vp);
35490Sstevel@tonic-gate }
35500Sstevel@tonic-gate } else {
35510Sstevel@tonic-gate fd = kobj_boot_open(filename, 0);
35520Sstevel@tonic-gate
35530Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG) {
35540Sstevel@tonic-gate if (fd < 0)
35550Sstevel@tonic-gate _kobj_printf(ops,
35560Sstevel@tonic-gate "kobj_open: can't open %s\n", filename);
35570Sstevel@tonic-gate else {
35580Sstevel@tonic-gate _kobj_printf(ops, "kobj_open: '%s'", filename);
35590Sstevel@tonic-gate _kobj_printf(ops, " descr = 0x%x\n", fd);
35600Sstevel@tonic-gate }
35610Sstevel@tonic-gate }
35620Sstevel@tonic-gate return ((intptr_t)fd);
35630Sstevel@tonic-gate }
35640Sstevel@tonic-gate }
35650Sstevel@tonic-gate
35660Sstevel@tonic-gate /*
35670Sstevel@tonic-gate * Calls to kobj_open() are handled off to this routine as a separate thread.
35680Sstevel@tonic-gate */
35690Sstevel@tonic-gate static void
kobjopen_thread(struct kobjopen_tctl * ltp)35700Sstevel@tonic-gate kobjopen_thread(struct kobjopen_tctl *ltp)
35710Sstevel@tonic-gate {
35720Sstevel@tonic-gate kmutex_t cpr_lk;
35730Sstevel@tonic-gate callb_cpr_t cpr_i;
35740Sstevel@tonic-gate
35750Sstevel@tonic-gate mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL);
35760Sstevel@tonic-gate CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "kobjopen");
35770Sstevel@tonic-gate ltp->Errno = vn_open(ltp->name, UIO_SYSSPACE, FREAD, 0, &(ltp->vp),
35783912Slling 0, 0);
35790Sstevel@tonic-gate sema_v(<p->sema);
35800Sstevel@tonic-gate mutex_enter(&cpr_lk);
35810Sstevel@tonic-gate CALLB_CPR_EXIT(&cpr_i);
35820Sstevel@tonic-gate mutex_destroy(&cpr_lk);
35830Sstevel@tonic-gate thread_exit();
35840Sstevel@tonic-gate }
35850Sstevel@tonic-gate
35860Sstevel@tonic-gate /*
35870Sstevel@tonic-gate * allocate and initialize a kobjopen thread structure
35880Sstevel@tonic-gate */
35890Sstevel@tonic-gate static struct kobjopen_tctl *
kobjopen_alloc(char * filename)35900Sstevel@tonic-gate kobjopen_alloc(char *filename)
35910Sstevel@tonic-gate {
35920Sstevel@tonic-gate struct kobjopen_tctl *ltp = kmem_zalloc(sizeof (*ltp), KM_SLEEP);
35930Sstevel@tonic-gate
35940Sstevel@tonic-gate ASSERT(filename != NULL);
35950Sstevel@tonic-gate
35960Sstevel@tonic-gate ltp->name = kmem_alloc(strlen(filename) + 1, KM_SLEEP);
35970Sstevel@tonic-gate bcopy(filename, ltp->name, strlen(filename) + 1);
35980Sstevel@tonic-gate sema_init(<p->sema, 0, NULL, SEMA_DEFAULT, NULL);
35990Sstevel@tonic-gate return (ltp);
36000Sstevel@tonic-gate }
36010Sstevel@tonic-gate
36020Sstevel@tonic-gate /*
36030Sstevel@tonic-gate * free a kobjopen thread control structure
36040Sstevel@tonic-gate */
36050Sstevel@tonic-gate static void
kobjopen_free(struct kobjopen_tctl * ltp)36060Sstevel@tonic-gate kobjopen_free(struct kobjopen_tctl *ltp)
36070Sstevel@tonic-gate {
36080Sstevel@tonic-gate sema_destroy(<p->sema);
36090Sstevel@tonic-gate kmem_free(ltp->name, strlen(ltp->name) + 1);
36100Sstevel@tonic-gate kmem_free(ltp, sizeof (*ltp));
36110Sstevel@tonic-gate }
36120Sstevel@tonic-gate
36130Sstevel@tonic-gate int
kobj_read(intptr_t descr,char * buf,uint_t size,uint_t offset)36145648Ssetje kobj_read(intptr_t descr, char *buf, uint_t size, uint_t offset)
36150Sstevel@tonic-gate {
36160Sstevel@tonic-gate int stat;
36170Sstevel@tonic-gate ssize_t resid;
36180Sstevel@tonic-gate
36190Sstevel@tonic-gate if (_modrootloaded) {
36200Sstevel@tonic-gate if ((stat = vn_rdwr(UIO_READ, (struct vnode *)descr, buf, size,
36210Sstevel@tonic-gate (offset_t)offset, UIO_SYSSPACE, 0, (rlim64_t)0, CRED(),
36220Sstevel@tonic-gate &resid)) != 0) {
36230Sstevel@tonic-gate _kobj_printf(ops,
36240Sstevel@tonic-gate "vn_rdwr failed with error 0x%x\n", stat);
36250Sstevel@tonic-gate return (-1);
36260Sstevel@tonic-gate }
36270Sstevel@tonic-gate return (size - resid);
36280Sstevel@tonic-gate } else {
36290Sstevel@tonic-gate int count = 0;
36300Sstevel@tonic-gate
36310Sstevel@tonic-gate if (kobj_boot_seek((int)descr, (off_t)0, offset) != 0) {
36320Sstevel@tonic-gate _kobj_printf(ops,
36330Sstevel@tonic-gate "kobj_read: seek 0x%x failed\n", offset);
36340Sstevel@tonic-gate return (-1);
36350Sstevel@tonic-gate }
36360Sstevel@tonic-gate
36370Sstevel@tonic-gate count = kobj_boot_read((int)descr, buf, size);
36380Sstevel@tonic-gate if (count < size) {
36390Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG) {
36400Sstevel@tonic-gate _kobj_printf(ops,
36410Sstevel@tonic-gate "kobj_read: req %d bytes, ", size);
36420Sstevel@tonic-gate _kobj_printf(ops, "got %d\n", count);
36430Sstevel@tonic-gate }
36440Sstevel@tonic-gate }
36450Sstevel@tonic-gate return (count);
36460Sstevel@tonic-gate }
36470Sstevel@tonic-gate }
36480Sstevel@tonic-gate
36490Sstevel@tonic-gate void
kobj_close(intptr_t descr)36500Sstevel@tonic-gate kobj_close(intptr_t descr)
36510Sstevel@tonic-gate {
36520Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
36530Sstevel@tonic-gate _kobj_printf(ops, "kobj_close: 0x%lx\n", descr);
36540Sstevel@tonic-gate
36550Sstevel@tonic-gate if (_modrootloaded) {
36560Sstevel@tonic-gate struct vnode *vp = (struct vnode *)descr;
36575331Samw (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
36580Sstevel@tonic-gate VN_RELE(vp);
36590Sstevel@tonic-gate } else
36600Sstevel@tonic-gate (void) kobj_boot_close((int)descr);
36610Sstevel@tonic-gate }
36620Sstevel@tonic-gate
36631544Seschrock int
kobj_fstat(intptr_t descr,struct bootstat * buf)36641544Seschrock kobj_fstat(intptr_t descr, struct bootstat *buf)
36651544Seschrock {
36661544Seschrock if (buf == NULL)
36671544Seschrock return (-1);
36681544Seschrock
36691544Seschrock if (_modrootloaded) {
36701544Seschrock vattr_t vattr;
36711544Seschrock struct vnode *vp = (struct vnode *)descr;
36725331Samw if (VOP_GETATTR(vp, &vattr, 0, kcred, NULL) != 0)
36731544Seschrock return (-1);
36741544Seschrock
36751544Seschrock /*
36761544Seschrock * The vattr and bootstat structures are similar, but not
36771544Seschrock * identical. We do our best to fill in the bootstat structure
36781544Seschrock * from the contents of vattr (transfering only the ones that
36791544Seschrock * are obvious.
36801544Seschrock */
36811544Seschrock
36821544Seschrock buf->st_mode = (uint32_t)vattr.va_mode;
36831544Seschrock buf->st_nlink = (uint32_t)vattr.va_nlink;
36841544Seschrock buf->st_uid = (int32_t)vattr.va_uid;
36851544Seschrock buf->st_gid = (int32_t)vattr.va_gid;
36861544Seschrock buf->st_rdev = (uint64_t)vattr.va_rdev;
36871544Seschrock buf->st_size = (uint64_t)vattr.va_size;
36881544Seschrock buf->st_atim.tv_sec = (int64_t)vattr.va_atime.tv_sec;
36891544Seschrock buf->st_atim.tv_nsec = (int64_t)vattr.va_atime.tv_nsec;
36901544Seschrock buf->st_mtim.tv_sec = (int64_t)vattr.va_mtime.tv_sec;
36911544Seschrock buf->st_mtim.tv_nsec = (int64_t)vattr.va_mtime.tv_nsec;
36921544Seschrock buf->st_ctim.tv_sec = (int64_t)vattr.va_ctime.tv_sec;
36931544Seschrock buf->st_ctim.tv_nsec = (int64_t)vattr.va_ctime.tv_nsec;
36941544Seschrock buf->st_blksize = (int32_t)vattr.va_blksize;
36951544Seschrock buf->st_blocks = (int64_t)vattr.va_nblocks;
36961544Seschrock
36971544Seschrock return (0);
36981544Seschrock }
36991544Seschrock
37001544Seschrock return (kobj_boot_fstat((int)descr, buf));
37011544Seschrock }
37021544Seschrock
37031544Seschrock
37040Sstevel@tonic-gate struct _buf *
kobj_open_file(char * name)37050Sstevel@tonic-gate kobj_open_file(char *name)
37060Sstevel@tonic-gate {
37070Sstevel@tonic-gate struct _buf *file;
37085648Ssetje struct compinfo cbuf;
37090Sstevel@tonic-gate intptr_t fd;
37100Sstevel@tonic-gate
37110Sstevel@tonic-gate if ((fd = kobj_open(name)) == -1) {
37120Sstevel@tonic-gate return ((struct _buf *)-1);
37130Sstevel@tonic-gate }
37140Sstevel@tonic-gate
37150Sstevel@tonic-gate file = kobj_zalloc(sizeof (struct _buf), KM_WAIT|KM_TMP);
37160Sstevel@tonic-gate file->_fd = fd;
37170Sstevel@tonic-gate file->_name = kobj_alloc(strlen(name)+1, KM_WAIT|KM_TMP);
37180Sstevel@tonic-gate file->_cnt = file->_size = file->_off = 0;
37190Sstevel@tonic-gate file->_ln = 1;
37200Sstevel@tonic-gate file->_ptr = file->_base;
37210Sstevel@tonic-gate (void) strcpy(file->_name, name);
37225648Ssetje
37235648Ssetje /*
37245648Ssetje * Before root is mounted, we must check
37255648Ssetje * for a compressed file and do our own
37265648Ssetje * buffering.
37275648Ssetje */
37285648Ssetje if (_modrootloaded) {
37295648Ssetje file->_base = kobj_zalloc(MAXBSIZE, KM_WAIT);
37305648Ssetje file->_bsize = MAXBSIZE;
37317858SKrishnendu.Sadhukhan@Sun.COM
37327858SKrishnendu.Sadhukhan@Sun.COM /* Check if the file is compressed */
37338001SKrishnendu.Sadhukhan@Sun.COM file->_iscmp = kobj_is_compressed(fd);
37345648Ssetje } else {
37355648Ssetje if (kobj_boot_compinfo(fd, &cbuf) != 0) {
37365648Ssetje kobj_close_file(file);
37375648Ssetje return ((struct _buf *)-1);
37385648Ssetje }
37395648Ssetje file->_iscmp = cbuf.iscmp;
37405648Ssetje if (file->_iscmp) {
37415648Ssetje if (kobj_comp_setup(file, &cbuf) != 0) {
37425648Ssetje kobj_close_file(file);
37435648Ssetje return ((struct _buf *)-1);
37445648Ssetje }
37455648Ssetje } else {
37465648Ssetje file->_base = kobj_zalloc(cbuf.blksize, KM_WAIT|KM_TMP);
37475648Ssetje file->_bsize = cbuf.blksize;
37485648Ssetje }
37495648Ssetje }
37500Sstevel@tonic-gate return (file);
37510Sstevel@tonic-gate }
37520Sstevel@tonic-gate
37535648Ssetje static int
kobj_comp_setup(struct _buf * file,struct compinfo * cip)37545648Ssetje kobj_comp_setup(struct _buf *file, struct compinfo *cip)
37555648Ssetje {
37565648Ssetje struct comphdr *hdr;
37575648Ssetje
37585648Ssetje /*
37595648Ssetje * read the compressed image into memory,
37605648Ssetje * so we can deompress from there
37615648Ssetje */
37625648Ssetje file->_dsize = cip->fsize;
37635648Ssetje file->_dbuf = kobj_alloc(cip->fsize, KM_WAIT|KM_TMP);
37645648Ssetje if (kobj_read(file->_fd, file->_dbuf, cip->fsize, 0) != cip->fsize) {
37655648Ssetje kobj_free(file->_dbuf, cip->fsize);
37665648Ssetje return (-1);
37675648Ssetje }
37685648Ssetje
37695648Ssetje hdr = kobj_comphdr(file);
37707858SKrishnendu.Sadhukhan@Sun.COM if (hdr->ch_magic != CH_MAGIC_ZLIB || hdr->ch_version != CH_VERSION ||
37715648Ssetje hdr->ch_algorithm != CH_ALG_ZLIB || hdr->ch_fsize == 0 ||
37725648Ssetje (hdr->ch_blksize & (hdr->ch_blksize - 1)) != 0) {
37735648Ssetje kobj_free(file->_dbuf, cip->fsize);
37745648Ssetje return (-1);
37755648Ssetje }
37765648Ssetje file->_base = kobj_alloc(hdr->ch_blksize, KM_WAIT|KM_TMP);
37775648Ssetje file->_bsize = hdr->ch_blksize;
37785648Ssetje return (0);
37795648Ssetje }
37805648Ssetje
37810Sstevel@tonic-gate void
kobj_close_file(struct _buf * file)37820Sstevel@tonic-gate kobj_close_file(struct _buf *file)
37830Sstevel@tonic-gate {
37840Sstevel@tonic-gate kobj_close(file->_fd);
37855648Ssetje if (file->_base != NULL)
37865648Ssetje kobj_free(file->_base, file->_bsize);
37875648Ssetje if (file->_dbuf != NULL)
37885648Ssetje kobj_free(file->_dbuf, file->_dsize);
37890Sstevel@tonic-gate kobj_free(file->_name, strlen(file->_name)+1);
37900Sstevel@tonic-gate kobj_free(file, sizeof (struct _buf));
37910Sstevel@tonic-gate }
37920Sstevel@tonic-gate
37930Sstevel@tonic-gate int
kobj_read_file(struct _buf * file,char * buf,uint_t size,uint_t off)37945648Ssetje kobj_read_file(struct _buf *file, char *buf, uint_t size, uint_t off)
37950Sstevel@tonic-gate {
37960Sstevel@tonic-gate int b_size, c_size;
37970Sstevel@tonic-gate int b_off; /* Offset into buffer for start of bcopy */
37980Sstevel@tonic-gate int count = 0;
37990Sstevel@tonic-gate int page_addr;
38000Sstevel@tonic-gate
38010Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG) {
38020Sstevel@tonic-gate _kobj_printf(ops, "kobj_read_file: size=%x,", size);
38030Sstevel@tonic-gate _kobj_printf(ops, " offset=%x at", off);
38040Sstevel@tonic-gate _kobj_printf(ops, " buf=%x\n", buf);
38050Sstevel@tonic-gate }
38060Sstevel@tonic-gate
38077858SKrishnendu.Sadhukhan@Sun.COM /*
38087858SKrishnendu.Sadhukhan@Sun.COM * Handle compressed (gzip for now) file here. First get the
38097858SKrishnendu.Sadhukhan@Sun.COM * compressed size, then read the image into memory and finally
38107858SKrishnendu.Sadhukhan@Sun.COM * call zlib to decompress the image at the supplied memory buffer.
38117858SKrishnendu.Sadhukhan@Sun.COM */
38128001SKrishnendu.Sadhukhan@Sun.COM if (file->_iscmp == CH_MAGIC_GZIP) {
38137858SKrishnendu.Sadhukhan@Sun.COM ulong_t dlen;
38147858SKrishnendu.Sadhukhan@Sun.COM vattr_t vattr;
38157858SKrishnendu.Sadhukhan@Sun.COM struct vnode *vp = (struct vnode *)file->_fd;
38167858SKrishnendu.Sadhukhan@Sun.COM ssize_t resid;
38177858SKrishnendu.Sadhukhan@Sun.COM int err = 0;
38187858SKrishnendu.Sadhukhan@Sun.COM
38197858SKrishnendu.Sadhukhan@Sun.COM if (VOP_GETATTR(vp, &vattr, 0, kcred, NULL) != 0)
38207858SKrishnendu.Sadhukhan@Sun.COM return (-1);
38217858SKrishnendu.Sadhukhan@Sun.COM
38227858SKrishnendu.Sadhukhan@Sun.COM file->_dbuf = kobj_alloc(vattr.va_size, KM_WAIT|KM_TMP);
38237858SKrishnendu.Sadhukhan@Sun.COM file->_dsize = vattr.va_size;
38247858SKrishnendu.Sadhukhan@Sun.COM
38257858SKrishnendu.Sadhukhan@Sun.COM /* Read the compressed file into memory */
38267858SKrishnendu.Sadhukhan@Sun.COM if ((err = vn_rdwr(UIO_READ, vp, file->_dbuf, vattr.va_size,
38277858SKrishnendu.Sadhukhan@Sun.COM (offset_t)(0), UIO_SYSSPACE, 0, (rlim64_t)0, CRED(),
38287858SKrishnendu.Sadhukhan@Sun.COM &resid)) != 0) {
38297858SKrishnendu.Sadhukhan@Sun.COM
38307858SKrishnendu.Sadhukhan@Sun.COM _kobj_printf(ops, "kobj_read_file :vn_rdwr() failed, "
38317858SKrishnendu.Sadhukhan@Sun.COM "error code 0x%x\n", err);
38327858SKrishnendu.Sadhukhan@Sun.COM return (-1);
38337858SKrishnendu.Sadhukhan@Sun.COM }
38347858SKrishnendu.Sadhukhan@Sun.COM
38357858SKrishnendu.Sadhukhan@Sun.COM dlen = size;
38367858SKrishnendu.Sadhukhan@Sun.COM
38377858SKrishnendu.Sadhukhan@Sun.COM /* Decompress the image at the supplied memory buffer */
38387858SKrishnendu.Sadhukhan@Sun.COM if ((err = z_uncompress(buf, &dlen, file->_dbuf,
38397858SKrishnendu.Sadhukhan@Sun.COM vattr.va_size)) != Z_OK) {
38407858SKrishnendu.Sadhukhan@Sun.COM _kobj_printf(ops, "kobj_read_file: z_uncompress "
38417858SKrishnendu.Sadhukhan@Sun.COM "failed, error code : 0x%x\n", err);
38427858SKrishnendu.Sadhukhan@Sun.COM return (-1);
38437858SKrishnendu.Sadhukhan@Sun.COM }
38447858SKrishnendu.Sadhukhan@Sun.COM
38457858SKrishnendu.Sadhukhan@Sun.COM if (dlen != size) {
38467858SKrishnendu.Sadhukhan@Sun.COM _kobj_printf(ops, "kobj_read_file: z_uncompress "
38477858SKrishnendu.Sadhukhan@Sun.COM "failed to uncompress (size returned 0x%x , "
38487858SKrishnendu.Sadhukhan@Sun.COM "expected size: 0x%x)\n", dlen, size);
38497858SKrishnendu.Sadhukhan@Sun.COM return (-1);
38507858SKrishnendu.Sadhukhan@Sun.COM }
38517858SKrishnendu.Sadhukhan@Sun.COM
38527858SKrishnendu.Sadhukhan@Sun.COM return (0);
38537858SKrishnendu.Sadhukhan@Sun.COM }
38547858SKrishnendu.Sadhukhan@Sun.COM
38550Sstevel@tonic-gate while (size) {
38565648Ssetje page_addr = F_PAGE(file, off);
38570Sstevel@tonic-gate b_size = file->_size;
38580Sstevel@tonic-gate /*
38590Sstevel@tonic-gate * If we have the filesystem page the caller's referring to
38600Sstevel@tonic-gate * and we have something in the buffer,
38610Sstevel@tonic-gate * satisfy as much of the request from the buffer as we can.
38620Sstevel@tonic-gate */
38630Sstevel@tonic-gate if (page_addr == file->_off && b_size > 0) {
38645648Ssetje b_off = B_OFFSET(file, off);
38650Sstevel@tonic-gate c_size = b_size - b_off;
38660Sstevel@tonic-gate /*
38670Sstevel@tonic-gate * If there's nothing to copy, we're at EOF.
38680Sstevel@tonic-gate */
38690Sstevel@tonic-gate if (c_size <= 0)
38700Sstevel@tonic-gate break;
38710Sstevel@tonic-gate if (c_size > size)
38720Sstevel@tonic-gate c_size = size;
38730Sstevel@tonic-gate if (buf) {
38740Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
38750Sstevel@tonic-gate _kobj_printf(ops, "copying %x bytes\n",
38760Sstevel@tonic-gate c_size);
38770Sstevel@tonic-gate bcopy(file->_base+b_off, buf, c_size);
38780Sstevel@tonic-gate size -= c_size;
38790Sstevel@tonic-gate off += c_size;
38800Sstevel@tonic-gate buf += c_size;
38810Sstevel@tonic-gate count += c_size;
38820Sstevel@tonic-gate } else {
38830Sstevel@tonic-gate _kobj_printf(ops, "kobj_read: system error");
38840Sstevel@tonic-gate count = -1;
38850Sstevel@tonic-gate break;
38860Sstevel@tonic-gate }
38870Sstevel@tonic-gate } else {
38880Sstevel@tonic-gate /*
38890Sstevel@tonic-gate * If the caller's offset is page aligned and
38900Sstevel@tonic-gate * the caller want's at least a filesystem page and
38910Sstevel@tonic-gate * the caller provided a buffer,
38920Sstevel@tonic-gate * read directly into the caller's buffer.
38930Sstevel@tonic-gate */
38940Sstevel@tonic-gate if (page_addr == off &&
38955648Ssetje (c_size = F_BLKS(file, size)) && buf) {
38965648Ssetje c_size = kobj_read_blks(file, buf, c_size,
38973912Slling page_addr);
38980Sstevel@tonic-gate if (c_size < 0) {
38990Sstevel@tonic-gate count = -1;
39000Sstevel@tonic-gate break;
39010Sstevel@tonic-gate }
39020Sstevel@tonic-gate count += c_size;
39035648Ssetje if (c_size != F_BLKS(file, size))
39040Sstevel@tonic-gate break;
39050Sstevel@tonic-gate size -= c_size;
39060Sstevel@tonic-gate off += c_size;
39070Sstevel@tonic-gate buf += c_size;
39080Sstevel@tonic-gate /*
39090Sstevel@tonic-gate * Otherwise, read into our buffer and copy next time
39100Sstevel@tonic-gate * around the loop.
39110Sstevel@tonic-gate */
39120Sstevel@tonic-gate } else {
39130Sstevel@tonic-gate file->_off = page_addr;
39145648Ssetje c_size = kobj_read_blks(file, file->_base,
39155648Ssetje file->_bsize, page_addr);
39160Sstevel@tonic-gate file->_ptr = file->_base;
39170Sstevel@tonic-gate file->_cnt = c_size;
39180Sstevel@tonic-gate file->_size = c_size;
39190Sstevel@tonic-gate /*
39200Sstevel@tonic-gate * If a _filbuf call or nothing read, break.
39210Sstevel@tonic-gate */
39220Sstevel@tonic-gate if (buf == NULL || c_size <= 0) {
39230Sstevel@tonic-gate count = c_size;
39240Sstevel@tonic-gate break;
39250Sstevel@tonic-gate }
39260Sstevel@tonic-gate }
39270Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
39280Sstevel@tonic-gate _kobj_printf(ops, "read %x bytes\n", c_size);
39290Sstevel@tonic-gate }
39300Sstevel@tonic-gate }
39310Sstevel@tonic-gate if (_moddebug & MODDEBUG_ERRMSG)
39320Sstevel@tonic-gate _kobj_printf(ops, "count = %x\n", count);
39330Sstevel@tonic-gate
39340Sstevel@tonic-gate return (count);
39350Sstevel@tonic-gate }
39360Sstevel@tonic-gate
39375648Ssetje static int
kobj_read_blks(struct _buf * file,char * buf,uint_t size,uint_t off)39385648Ssetje kobj_read_blks(struct _buf *file, char *buf, uint_t size, uint_t off)
39395648Ssetje {
39405648Ssetje int ret;
39415648Ssetje
39425648Ssetje ASSERT(B_OFFSET(file, size) == 0 && B_OFFSET(file, off) == 0);
39435648Ssetje if (file->_iscmp) {
39445648Ssetje uint_t blks;
39455648Ssetje int nret;
39465648Ssetje
39475648Ssetje ret = 0;
39485648Ssetje for (blks = size / file->_bsize; blks != 0; blks--) {
39495648Ssetje nret = kobj_uncomp_blk(file, buf, off);
39505648Ssetje if (nret == -1)
39515648Ssetje return (-1);
39525648Ssetje buf += nret;
39535648Ssetje off += nret;
39545648Ssetje ret += nret;
39555648Ssetje if (nret < file->_bsize)
39565648Ssetje break;
39575648Ssetje }
39585648Ssetje } else
39595648Ssetje ret = kobj_read(file->_fd, buf, size, off);
39605648Ssetje return (ret);
39615648Ssetje }
39625648Ssetje
39635648Ssetje static int
kobj_uncomp_blk(struct _buf * file,char * buf,uint_t off)39645648Ssetje kobj_uncomp_blk(struct _buf *file, char *buf, uint_t off)
39655648Ssetje {
39665648Ssetje struct comphdr *hdr = kobj_comphdr(file);
39675648Ssetje ulong_t dlen, slen;
39685648Ssetje caddr_t src;
39695648Ssetje int i;
39705648Ssetje
39715648Ssetje dlen = file->_bsize;
39725648Ssetje i = off / file->_bsize;
39735648Ssetje src = file->_dbuf + hdr->ch_blkmap[i];
39745648Ssetje if (i == hdr->ch_fsize / file->_bsize)
39756582Ssetje slen = file->_dsize - hdr->ch_blkmap[i];
39765648Ssetje else
39775648Ssetje slen = hdr->ch_blkmap[i + 1] - hdr->ch_blkmap[i];
39785648Ssetje if (z_uncompress(buf, &dlen, src, slen) != Z_OK)
39795648Ssetje return (-1);
39805648Ssetje return (dlen);
39815648Ssetje }
39825648Ssetje
39830Sstevel@tonic-gate int
kobj_filbuf(struct _buf * f)39840Sstevel@tonic-gate kobj_filbuf(struct _buf *f)
39850Sstevel@tonic-gate {
39865648Ssetje if (kobj_read_file(f, NULL, f->_bsize, f->_off + f->_size) > 0)
39870Sstevel@tonic-gate return (kobj_getc(f));
39880Sstevel@tonic-gate return (-1);
39890Sstevel@tonic-gate }
39900Sstevel@tonic-gate
39910Sstevel@tonic-gate void
kobj_free(void * address,size_t size)39920Sstevel@tonic-gate kobj_free(void *address, size_t size)
39930Sstevel@tonic-gate {
39940Sstevel@tonic-gate if (standalone)
39950Sstevel@tonic-gate return;
39960Sstevel@tonic-gate
39970Sstevel@tonic-gate kmem_free(address, size);
39980Sstevel@tonic-gate kobj_stat.nfree_calls++;
39990Sstevel@tonic-gate kobj_stat.nfree += size;
40000Sstevel@tonic-gate }
40010Sstevel@tonic-gate
40020Sstevel@tonic-gate void *
kobj_zalloc(size_t size,int flag)40030Sstevel@tonic-gate kobj_zalloc(size_t size, int flag)
40040Sstevel@tonic-gate {
40050Sstevel@tonic-gate void *v;
40060Sstevel@tonic-gate
40070Sstevel@tonic-gate if ((v = kobj_alloc(size, flag)) != 0) {
40080Sstevel@tonic-gate bzero(v, size);
40090Sstevel@tonic-gate }
40100Sstevel@tonic-gate
40110Sstevel@tonic-gate return (v);
40120Sstevel@tonic-gate }
40130Sstevel@tonic-gate
40140Sstevel@tonic-gate void *
kobj_alloc(size_t size,int flag)40150Sstevel@tonic-gate kobj_alloc(size_t size, int flag)
40160Sstevel@tonic-gate {
40170Sstevel@tonic-gate /*
40180Sstevel@tonic-gate * If we are running standalone in the
40190Sstevel@tonic-gate * linker, we ask boot for memory.
40200Sstevel@tonic-gate * Either it's temporary memory that we lose
40210Sstevel@tonic-gate * once boot is mapped out or we allocate it
40220Sstevel@tonic-gate * permanently using the dynamic data segment.
40230Sstevel@tonic-gate */
40240Sstevel@tonic-gate if (standalone) {
40255648Ssetje #if defined(_OBP)
40265648Ssetje if (flag & (KM_TMP | KM_SCRATCH))
40275648Ssetje return (bop_temp_alloc(size, MINALIGN));
40285648Ssetje #else
40290Sstevel@tonic-gate if (flag & (KM_TMP | KM_SCRATCH))
40300Sstevel@tonic-gate return (BOP_ALLOC(ops, 0, size, MINALIGN));
40310Sstevel@tonic-gate #endif
40320Sstevel@tonic-gate return (kobj_segbrk(&_edata, size, MINALIGN, 0));
40330Sstevel@tonic-gate }
40340Sstevel@tonic-gate
40350Sstevel@tonic-gate kobj_stat.nalloc_calls++;
40360Sstevel@tonic-gate kobj_stat.nalloc += size;
40370Sstevel@tonic-gate
40380Sstevel@tonic-gate return (kmem_alloc(size, (flag & KM_NOWAIT) ? KM_NOSLEEP : KM_SLEEP));
40390Sstevel@tonic-gate }
40400Sstevel@tonic-gate
40410Sstevel@tonic-gate /*
40420Sstevel@tonic-gate * Allow the "mod" system to sync up with the work
40430Sstevel@tonic-gate * already done by kobj during the initial loading
40440Sstevel@tonic-gate * of the kernel. This also gives us a chance
40450Sstevel@tonic-gate * to reallocate memory that belongs to boot.
40460Sstevel@tonic-gate */
40470Sstevel@tonic-gate void
kobj_sync(void)40480Sstevel@tonic-gate kobj_sync(void)
40490Sstevel@tonic-gate {
40500Sstevel@tonic-gate struct modctl_list *lp, **lpp;
40510Sstevel@tonic-gate
40520Sstevel@tonic-gate /*
40533446Smrj * The module path can be set in /etc/system via 'moddir' commands
40540Sstevel@tonic-gate */
40550Sstevel@tonic-gate if (default_path != NULL)
40563446Smrj kobj_module_path = default_path;
40570Sstevel@tonic-gate else
40583446Smrj default_path = kobj_module_path;
40590Sstevel@tonic-gate
40600Sstevel@tonic-gate ksyms_arena = vmem_create("ksyms", NULL, 0, sizeof (uint64_t),
40610Sstevel@tonic-gate segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
40620Sstevel@tonic-gate
40630Sstevel@tonic-gate ctf_arena = vmem_create("ctf", NULL, 0, sizeof (uint_t),
40640Sstevel@tonic-gate segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
40650Sstevel@tonic-gate
40660Sstevel@tonic-gate /*
40670Sstevel@tonic-gate * Move symbol tables from boot memory to ksyms_arena.
40680Sstevel@tonic-gate */
40690Sstevel@tonic-gate for (lpp = kobj_linkmaps; *lpp != NULL; lpp++) {
40700Sstevel@tonic-gate for (lp = *lpp; lp != NULL; lp = lp->modl_next)
40710Sstevel@tonic-gate kobj_export_module(mod(lp));
40720Sstevel@tonic-gate }
40730Sstevel@tonic-gate }
40740Sstevel@tonic-gate
40750Sstevel@tonic-gate caddr_t
kobj_segbrk(caddr_t * spp,size_t size,size_t align,caddr_t limit)40760Sstevel@tonic-gate kobj_segbrk(caddr_t *spp, size_t size, size_t align, caddr_t limit)
40770Sstevel@tonic-gate {
40780Sstevel@tonic-gate uintptr_t va, pva;
40790Sstevel@tonic-gate size_t alloc_pgsz = kobj_mmu_pagesize;
40800Sstevel@tonic-gate size_t alloc_align = BO_NO_ALIGN;
40810Sstevel@tonic-gate size_t alloc_size;
40820Sstevel@tonic-gate
40830Sstevel@tonic-gate /*
40840Sstevel@tonic-gate * If we are using "large" mappings for the kernel,
40850Sstevel@tonic-gate * request aligned memory from boot using the
40860Sstevel@tonic-gate * "large" pagesize.
40870Sstevel@tonic-gate */
40880Sstevel@tonic-gate if (lg_pagesize) {
40890Sstevel@tonic-gate alloc_align = lg_pagesize;
40900Sstevel@tonic-gate alloc_pgsz = lg_pagesize;
40910Sstevel@tonic-gate }
40926973Sjg
40936973Sjg #if defined(__sparc)
40946973Sjg /* account for redzone */
40956973Sjg if (limit)
40966973Sjg limit -= alloc_pgsz;
40976973Sjg #endif /* __sparc */
40986973Sjg
40990Sstevel@tonic-gate va = ALIGN((uintptr_t)*spp, align);
41000Sstevel@tonic-gate pva = P2ROUNDUP((uintptr_t)*spp, alloc_pgsz);
41010Sstevel@tonic-gate /*
41020Sstevel@tonic-gate * Need more pages?
41030Sstevel@tonic-gate */
41040Sstevel@tonic-gate if (va + size > pva) {
41053446Smrj uintptr_t npva;
41063446Smrj
41070Sstevel@tonic-gate alloc_size = P2ROUNDUP(size - (pva - va), alloc_pgsz);
41080Sstevel@tonic-gate /*
41090Sstevel@tonic-gate * Check for overlapping segments.
41100Sstevel@tonic-gate */
41113446Smrj if (limit && limit <= *spp + alloc_size) {
41120Sstevel@tonic-gate return ((caddr_t)0);
41133446Smrj }
41143446Smrj
41153446Smrj npva = (uintptr_t)BOP_ALLOC(ops, (caddr_t)pva,
41163912Slling alloc_size, alloc_align);
41173446Smrj
41183446Smrj if (npva == NULL) {
41193446Smrj _kobj_printf(ops, "BOP_ALLOC failed, 0x%lx bytes",
41200Sstevel@tonic-gate alloc_size);
41213446Smrj _kobj_printf(ops, " aligned %lx", alloc_align);
41220Sstevel@tonic-gate _kobj_printf(ops, " at 0x%lx\n", pva);
41233446Smrj return (NULL);
41240Sstevel@tonic-gate }
41250Sstevel@tonic-gate }
41260Sstevel@tonic-gate *spp = (caddr_t)(va + size);
41270Sstevel@tonic-gate
41280Sstevel@tonic-gate return ((caddr_t)va);
41290Sstevel@tonic-gate }
41300Sstevel@tonic-gate
41310Sstevel@tonic-gate /*
41320Sstevel@tonic-gate * Calculate the number of output hash buckets.
41330Sstevel@tonic-gate * We use the next prime larger than n / 4,
41340Sstevel@tonic-gate * so the average hash chain is about 4 entries.
41350Sstevel@tonic-gate * More buckets would just be a waste of memory.
41360Sstevel@tonic-gate */
41370Sstevel@tonic-gate uint_t
kobj_gethashsize(uint_t n)41380Sstevel@tonic-gate kobj_gethashsize(uint_t n)
41390Sstevel@tonic-gate {
41400Sstevel@tonic-gate int f;
41410Sstevel@tonic-gate int hsize = MAX(n / 4, 2);
41420Sstevel@tonic-gate
41430Sstevel@tonic-gate for (f = 2; f * f <= hsize; f++)
41440Sstevel@tonic-gate if (hsize % f == 0)
41450Sstevel@tonic-gate hsize += f = 1;
41460Sstevel@tonic-gate
41470Sstevel@tonic-gate return (hsize);
41480Sstevel@tonic-gate }
41490Sstevel@tonic-gate
41503912Slling /*
41513912Slling * Get the file size.
41523912Slling *
41533912Slling * Before root is mounted, files are compressed in the boot_archive ramdisk
41543912Slling * (in the memory). kobj_fstat would return the compressed file size.
41553912Slling * In order to get the uncompressed file size, read the file to the end and
41563912Slling * count its size.
41573912Slling */
41583912Slling int
kobj_get_filesize(struct _buf * file,uint64_t * size)41593912Slling kobj_get_filesize(struct _buf *file, uint64_t *size)
41603912Slling {
41617858SKrishnendu.Sadhukhan@Sun.COM int err = 0;
41627858SKrishnendu.Sadhukhan@Sun.COM ssize_t resid;
41637858SKrishnendu.Sadhukhan@Sun.COM uint32_t buf;
41647858SKrishnendu.Sadhukhan@Sun.COM
41653912Slling if (_modrootloaded) {
41663912Slling struct bootstat bst;
41673912Slling
41683912Slling if (kobj_fstat(file->_fd, &bst) != 0)
41693912Slling return (EIO);
41703912Slling *size = bst.st_size;
41717858SKrishnendu.Sadhukhan@Sun.COM
41728001SKrishnendu.Sadhukhan@Sun.COM if (file->_iscmp == CH_MAGIC_GZIP) {
41737858SKrishnendu.Sadhukhan@Sun.COM /*
41747858SKrishnendu.Sadhukhan@Sun.COM * Read the last 4 bytes of the compressed (gzip)
41757858SKrishnendu.Sadhukhan@Sun.COM * image to get the size of its uncompressed
41767858SKrishnendu.Sadhukhan@Sun.COM * version.
41777858SKrishnendu.Sadhukhan@Sun.COM */
41787858SKrishnendu.Sadhukhan@Sun.COM if ((err = vn_rdwr(UIO_READ, (struct vnode *)file->_fd,
41797858SKrishnendu.Sadhukhan@Sun.COM (char *)(&buf), 4, (offset_t)(*size - 4),
41807858SKrishnendu.Sadhukhan@Sun.COM UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid))
41817858SKrishnendu.Sadhukhan@Sun.COM != 0) {
41827858SKrishnendu.Sadhukhan@Sun.COM _kobj_printf(ops, "kobj_get_filesize: "
41837858SKrishnendu.Sadhukhan@Sun.COM "vn_rdwr() failed with error 0x%x\n", err);
41847858SKrishnendu.Sadhukhan@Sun.COM return (-1);
41857858SKrishnendu.Sadhukhan@Sun.COM }
41867858SKrishnendu.Sadhukhan@Sun.COM
41877858SKrishnendu.Sadhukhan@Sun.COM *size = (uint64_t)buf;
41887858SKrishnendu.Sadhukhan@Sun.COM }
41893912Slling } else {
41905648Ssetje
41915648Ssetje #if defined(_OBP)
41925648Ssetje struct bootstat bsb;
41935648Ssetje
41945648Ssetje if (file->_iscmp) {
41955648Ssetje struct comphdr *hdr = kobj_comphdr(file);
41965648Ssetje
41975648Ssetje *size = hdr->ch_fsize;
41985648Ssetje } else if (kobj_boot_fstat(file->_fd, &bsb) != 0)
41995648Ssetje return (EIO);
42005648Ssetje else
42015648Ssetje *size = bsb.st_size;
42025648Ssetje #else
42033912Slling char *buf;
42043912Slling int count;
42053912Slling uint64_t offset = 0;
42063912Slling
42073912Slling buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
42083912Slling do {
42093912Slling count = kobj_read_file(file, buf, MAXBSIZE, offset);
42103912Slling if (count < 0) {
42113912Slling kmem_free(buf, MAXBSIZE);
42123912Slling return (EIO);
42133912Slling }
42143912Slling offset += count;
42153912Slling } while (count == MAXBSIZE);
42163912Slling kmem_free(buf, MAXBSIZE);
42173912Slling
42183912Slling *size = offset;
42195648Ssetje #endif
42203912Slling }
42213912Slling
42223912Slling return (0);
42233912Slling }
42243912Slling
42250Sstevel@tonic-gate static char *
basename(char * s)42260Sstevel@tonic-gate basename(char *s)
42270Sstevel@tonic-gate {
42280Sstevel@tonic-gate char *p, *q;
42290Sstevel@tonic-gate
42300Sstevel@tonic-gate q = NULL;
42310Sstevel@tonic-gate p = s;
42320Sstevel@tonic-gate do {
42330Sstevel@tonic-gate if (*p == '/')
42340Sstevel@tonic-gate q = p;
42350Sstevel@tonic-gate } while (*p++);
42360Sstevel@tonic-gate return (q ? q + 1 : s);
42370Sstevel@tonic-gate }
42380Sstevel@tonic-gate
42390Sstevel@tonic-gate void
kobj_stat_get(kobj_stat_t * kp)42400Sstevel@tonic-gate kobj_stat_get(kobj_stat_t *kp)
42410Sstevel@tonic-gate {
42420Sstevel@tonic-gate *kp = kobj_stat;
42430Sstevel@tonic-gate }
42440Sstevel@tonic-gate
42450Sstevel@tonic-gate int
kobj_getpagesize()42460Sstevel@tonic-gate kobj_getpagesize()
42470Sstevel@tonic-gate {
42480Sstevel@tonic-gate return (lg_pagesize);
42490Sstevel@tonic-gate }
42500Sstevel@tonic-gate
42510Sstevel@tonic-gate void
kobj_textwin_alloc(struct module * mp)42520Sstevel@tonic-gate kobj_textwin_alloc(struct module *mp)
42530Sstevel@tonic-gate {
42540Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mod_lock));
42550Sstevel@tonic-gate
42560Sstevel@tonic-gate if (mp->textwin != NULL)
42570Sstevel@tonic-gate return;
42580Sstevel@tonic-gate
42590Sstevel@tonic-gate /*
42600Sstevel@tonic-gate * If the text is not contained in the heap, then it is not contained
42610Sstevel@tonic-gate * by a writable mapping. (Specifically, it's on the nucleus page.)
42620Sstevel@tonic-gate * We allocate a read/write mapping for this module's text to allow
42630Sstevel@tonic-gate * the text to be patched without calling hot_patch_kernel_text()
42640Sstevel@tonic-gate * (which is quite slow).
42650Sstevel@tonic-gate */
42660Sstevel@tonic-gate if (!vmem_contains(heaptext_arena, mp->text, mp->text_size)) {
42670Sstevel@tonic-gate uintptr_t text = (uintptr_t)mp->text;
42680Sstevel@tonic-gate uintptr_t size = (uintptr_t)mp->text_size;
42690Sstevel@tonic-gate uintptr_t i;
42700Sstevel@tonic-gate caddr_t va;
42710Sstevel@tonic-gate size_t sz = ((text + size + PAGESIZE - 1) & PAGEMASK) -
42720Sstevel@tonic-gate (text & PAGEMASK);
42730Sstevel@tonic-gate
42740Sstevel@tonic-gate va = mp->textwin_base = vmem_alloc(heap_arena, sz, VM_SLEEP);
42750Sstevel@tonic-gate
42760Sstevel@tonic-gate for (i = text & PAGEMASK; i < text + size; i += PAGESIZE) {
42770Sstevel@tonic-gate hat_devload(kas.a_hat, va, PAGESIZE,
42780Sstevel@tonic-gate hat_getpfnum(kas.a_hat, (caddr_t)i),
42790Sstevel@tonic-gate PROT_READ | PROT_WRITE,
42800Sstevel@tonic-gate HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
42810Sstevel@tonic-gate va += PAGESIZE;
42820Sstevel@tonic-gate }
42830Sstevel@tonic-gate
42840Sstevel@tonic-gate mp->textwin = mp->textwin_base + (text & PAGEOFFSET);
42850Sstevel@tonic-gate } else {
42860Sstevel@tonic-gate mp->textwin = mp->text;
42870Sstevel@tonic-gate }
42880Sstevel@tonic-gate }
42890Sstevel@tonic-gate
42900Sstevel@tonic-gate void
kobj_textwin_free(struct module * mp)42910Sstevel@tonic-gate kobj_textwin_free(struct module *mp)
42920Sstevel@tonic-gate {
42930Sstevel@tonic-gate uintptr_t text = (uintptr_t)mp->text;
42940Sstevel@tonic-gate uintptr_t tsize = (uintptr_t)mp->text_size;
42950Sstevel@tonic-gate size_t size = (((text + tsize + PAGESIZE - 1) & PAGEMASK) -
42960Sstevel@tonic-gate (text & PAGEMASK));
42970Sstevel@tonic-gate
42980Sstevel@tonic-gate mp->textwin = NULL;
42990Sstevel@tonic-gate
43000Sstevel@tonic-gate if (mp->textwin_base == NULL)
43010Sstevel@tonic-gate return;
43020Sstevel@tonic-gate
43030Sstevel@tonic-gate hat_unload(kas.a_hat, mp->textwin_base, size, HAT_UNLOAD_UNLOCK);
43040Sstevel@tonic-gate vmem_free(heap_arena, mp->textwin_base, size);
43050Sstevel@tonic-gate mp->textwin_base = NULL;
43060Sstevel@tonic-gate }
43070Sstevel@tonic-gate
43080Sstevel@tonic-gate static char *
find_libmacro(char * name)43090Sstevel@tonic-gate find_libmacro(char *name)
43100Sstevel@tonic-gate {
43110Sstevel@tonic-gate int lmi;
43120Sstevel@tonic-gate
43130Sstevel@tonic-gate for (lmi = 0; lmi < NLIBMACROS; lmi++) {
43140Sstevel@tonic-gate if (strcmp(name, libmacros[lmi].lmi_macroname) == 0)
43150Sstevel@tonic-gate return (libmacros[lmi].lmi_list);
43160Sstevel@tonic-gate }
43170Sstevel@tonic-gate return (NULL);
43180Sstevel@tonic-gate }
43190Sstevel@tonic-gate
43200Sstevel@tonic-gate /*
43210Sstevel@tonic-gate * Check for $MACRO in tail (string to expand) and expand it in path at pathend
43220Sstevel@tonic-gate * returns path if successful, else NULL
43230Sstevel@tonic-gate * Support multiple $MACROs expansion and the first valid path will be returned
43240Sstevel@tonic-gate * Caller's responsibility to provide enough space in path to expand
43250Sstevel@tonic-gate */
43260Sstevel@tonic-gate char *
expand_libmacro(char * tail,char * path,char * pathend)43270Sstevel@tonic-gate expand_libmacro(char *tail, char *path, char *pathend)
43280Sstevel@tonic-gate {
43290Sstevel@tonic-gate char c, *p, *p1, *p2, *path2, *endp;
43300Sstevel@tonic-gate int diff, lmi, macrolen, valid_macro, more_macro;
43310Sstevel@tonic-gate struct _buf *file;
43320Sstevel@tonic-gate
43330Sstevel@tonic-gate /*
43340Sstevel@tonic-gate * check for $MACROS between nulls or slashes
43350Sstevel@tonic-gate */
43360Sstevel@tonic-gate p = strchr(tail, '$');
43370Sstevel@tonic-gate if (p == NULL)
43380Sstevel@tonic-gate return (NULL);
43390Sstevel@tonic-gate for (lmi = 0; lmi < NLIBMACROS; lmi++) {
43400Sstevel@tonic-gate macrolen = libmacros[lmi].lmi_macrolen;
43410Sstevel@tonic-gate if (strncmp(p + 1, libmacros[lmi].lmi_macroname, macrolen) == 0)
43420Sstevel@tonic-gate break;
43430Sstevel@tonic-gate }
43440Sstevel@tonic-gate
43450Sstevel@tonic-gate valid_macro = 0;
43460Sstevel@tonic-gate if (lmi < NLIBMACROS) {
43470Sstevel@tonic-gate /*
43480Sstevel@tonic-gate * The following checks are used to restrict expansion of
43490Sstevel@tonic-gate * macros to those that form a full directory/file name
43500Sstevel@tonic-gate * and to keep the behavior same as before. If this
43510Sstevel@tonic-gate * restriction is removed or no longer valid in the future,
43520Sstevel@tonic-gate * the checks below can be deleted.
43530Sstevel@tonic-gate */
43540Sstevel@tonic-gate if ((p == tail) || (*(p - 1) == '/')) {
43550Sstevel@tonic-gate c = *(p + macrolen + 1);
43560Sstevel@tonic-gate if (c == '/' || c == '\0')
43570Sstevel@tonic-gate valid_macro = 1;
43580Sstevel@tonic-gate }
43590Sstevel@tonic-gate }
43600Sstevel@tonic-gate
43610Sstevel@tonic-gate if (!valid_macro) {
43620Sstevel@tonic-gate p2 = strchr(p, '/');
43630Sstevel@tonic-gate /*
43640Sstevel@tonic-gate * if no more macro to expand, then just copy whatever left
43650Sstevel@tonic-gate * and check whether it exists
43660Sstevel@tonic-gate */
43670Sstevel@tonic-gate if (p2 == NULL || strchr(p2, '$') == NULL) {
43680Sstevel@tonic-gate (void) strcpy(pathend, tail);
43690Sstevel@tonic-gate if ((file = kobj_open_path(path, 1, 1)) !=
43700Sstevel@tonic-gate (struct _buf *)-1) {
43710Sstevel@tonic-gate kobj_close_file(file);
43720Sstevel@tonic-gate return (path);
43730Sstevel@tonic-gate } else
43740Sstevel@tonic-gate return (NULL);
43750Sstevel@tonic-gate } else {
43760Sstevel@tonic-gate /*
43770Sstevel@tonic-gate * copy all chars before '/' and call expand_libmacro()
43780Sstevel@tonic-gate * again
43790Sstevel@tonic-gate */
43800Sstevel@tonic-gate diff = p2 - tail;
43810Sstevel@tonic-gate bcopy(tail, pathend, diff);
43820Sstevel@tonic-gate pathend += diff;
43830Sstevel@tonic-gate *(pathend) = '\0';
43840Sstevel@tonic-gate return (expand_libmacro(p2, path, pathend));
43850Sstevel@tonic-gate }
43860Sstevel@tonic-gate }
43870Sstevel@tonic-gate
43880Sstevel@tonic-gate more_macro = 0;
43890Sstevel@tonic-gate if (c != '\0') {
43900Sstevel@tonic-gate endp = p + macrolen + 1;
43910Sstevel@tonic-gate if (strchr(endp, '$') != NULL)
43920Sstevel@tonic-gate more_macro = 1;
43930Sstevel@tonic-gate } else
43940Sstevel@tonic-gate endp = NULL;
43950Sstevel@tonic-gate
43960Sstevel@tonic-gate /*
43970Sstevel@tonic-gate * copy lmi_list and split it into components.
43980Sstevel@tonic-gate * then put the part of tail before $MACRO into path
43990Sstevel@tonic-gate * at pathend
44000Sstevel@tonic-gate */
44010Sstevel@tonic-gate diff = p - tail;
44020Sstevel@tonic-gate if (diff > 0)
44030Sstevel@tonic-gate bcopy(tail, pathend, diff);
44040Sstevel@tonic-gate path2 = pathend + diff;
44050Sstevel@tonic-gate p1 = libmacros[lmi].lmi_list;
44060Sstevel@tonic-gate while (p1 && (*p1 != '\0')) {
44070Sstevel@tonic-gate p2 = strchr(p1, ':');
44080Sstevel@tonic-gate if (p2) {
44090Sstevel@tonic-gate diff = p2 - p1;
44100Sstevel@tonic-gate bcopy(p1, path2, diff);
44110Sstevel@tonic-gate *(path2 + diff) = '\0';
44120Sstevel@tonic-gate } else {
44130Sstevel@tonic-gate diff = strlen(p1);
44140Sstevel@tonic-gate bcopy(p1, path2, diff + 1);
44150Sstevel@tonic-gate }
44160Sstevel@tonic-gate /* copy endp only if there isn't any more macro to expand */
44170Sstevel@tonic-gate if (!more_macro && (endp != NULL))
44180Sstevel@tonic-gate (void) strcat(path2, endp);
44190Sstevel@tonic-gate file = kobj_open_path(path, 1, 1);
44200Sstevel@tonic-gate if (file != (struct _buf *)-1) {
44210Sstevel@tonic-gate kobj_close_file(file);
44220Sstevel@tonic-gate /*
44230Sstevel@tonic-gate * if more macros to expand then call expand_libmacro(),
44240Sstevel@tonic-gate * else return path which has the whole path
44250Sstevel@tonic-gate */
44260Sstevel@tonic-gate if (!more_macro || (expand_libmacro(endp, path,
44270Sstevel@tonic-gate path2 + diff) != NULL)) {
44280Sstevel@tonic-gate return (path);
44290Sstevel@tonic-gate }
44300Sstevel@tonic-gate }
44310Sstevel@tonic-gate if (p2)
44320Sstevel@tonic-gate p1 = ++p2;
44330Sstevel@tonic-gate else
44340Sstevel@tonic-gate return (NULL);
44350Sstevel@tonic-gate }
44360Sstevel@tonic-gate return (NULL);
44370Sstevel@tonic-gate }
44380Sstevel@tonic-gate
44390Sstevel@tonic-gate static void
tnf_add_notifyunload(kobj_notify_f * fp)44400Sstevel@tonic-gate tnf_add_notifyunload(kobj_notify_f *fp)
44410Sstevel@tonic-gate {
44420Sstevel@tonic-gate kobj_notify_list_t *entry;
44430Sstevel@tonic-gate
44440Sstevel@tonic-gate entry = kobj_alloc(sizeof (kobj_notify_list_t), KM_WAIT);
44450Sstevel@tonic-gate entry->kn_type = KOBJ_NOTIFY_MODUNLOADING;
44460Sstevel@tonic-gate entry->kn_func = fp;
44470Sstevel@tonic-gate (void) kobj_notify_add(entry);
44480Sstevel@tonic-gate }
44490Sstevel@tonic-gate
44500Sstevel@tonic-gate /* ARGSUSED */
44510Sstevel@tonic-gate static void
tnf_unsplice_probes(uint_t what,struct modctl * mod)44525648Ssetje tnf_unsplice_probes(uint_t what, struct modctl *mod)
44530Sstevel@tonic-gate {
44540Sstevel@tonic-gate tnf_probe_control_t **p;
44550Sstevel@tonic-gate tnf_tag_data_t **q;
44560Sstevel@tonic-gate struct module *mp = mod->mod_mp;
44570Sstevel@tonic-gate
44580Sstevel@tonic-gate if (!(mp->flags & KOBJ_TNF_PROBE))
44590Sstevel@tonic-gate return;
44600Sstevel@tonic-gate
44610Sstevel@tonic-gate for (p = &__tnf_probe_list_head; *p; )
44620Sstevel@tonic-gate if (kobj_addrcheck(mp, (char *)*p) == 0)
44630Sstevel@tonic-gate *p = (*p)->next;
44640Sstevel@tonic-gate else
44650Sstevel@tonic-gate p = &(*p)->next;
44660Sstevel@tonic-gate
44670Sstevel@tonic-gate for (q = &__tnf_tag_list_head; *q; )
44680Sstevel@tonic-gate if (kobj_addrcheck(mp, (char *)*q) == 0)
44690Sstevel@tonic-gate *q = (tnf_tag_data_t *)(*q)->tag_version;
44700Sstevel@tonic-gate else
44710Sstevel@tonic-gate q = (tnf_tag_data_t **)&(*q)->tag_version;
44720Sstevel@tonic-gate
44730Sstevel@tonic-gate tnf_changed_probe_list = 1;
44740Sstevel@tonic-gate }
44750Sstevel@tonic-gate
44760Sstevel@tonic-gate int
tnf_splice_probes(int boot_load,tnf_probe_control_t * plist,tnf_tag_data_t * tlist)44770Sstevel@tonic-gate tnf_splice_probes(int boot_load, tnf_probe_control_t *plist,
44780Sstevel@tonic-gate tnf_tag_data_t *tlist)
44790Sstevel@tonic-gate {
44800Sstevel@tonic-gate int result = 0;
44810Sstevel@tonic-gate static int add_notify = 1;
44820Sstevel@tonic-gate
44830Sstevel@tonic-gate if (plist) {
44840Sstevel@tonic-gate tnf_probe_control_t *pl;
44850Sstevel@tonic-gate
44860Sstevel@tonic-gate for (pl = plist; pl->next; )
44870Sstevel@tonic-gate pl = pl->next;
44880Sstevel@tonic-gate
44890Sstevel@tonic-gate if (!boot_load)
44900Sstevel@tonic-gate mutex_enter(&mod_lock);
44910Sstevel@tonic-gate tnf_changed_probe_list = 1;
44920Sstevel@tonic-gate pl->next = __tnf_probe_list_head;
44930Sstevel@tonic-gate __tnf_probe_list_head = plist;
44940Sstevel@tonic-gate if (!boot_load)
44950Sstevel@tonic-gate mutex_exit(&mod_lock);
44960Sstevel@tonic-gate result = 1;
44970Sstevel@tonic-gate }
44980Sstevel@tonic-gate
44990Sstevel@tonic-gate if (tlist) {
45000Sstevel@tonic-gate tnf_tag_data_t *tl;
45010Sstevel@tonic-gate
45020Sstevel@tonic-gate for (tl = tlist; tl->tag_version; )
45030Sstevel@tonic-gate tl = (tnf_tag_data_t *)tl->tag_version;
45040Sstevel@tonic-gate
45050Sstevel@tonic-gate if (!boot_load)
45060Sstevel@tonic-gate mutex_enter(&mod_lock);
45070Sstevel@tonic-gate tl->tag_version = (tnf_tag_version_t *)__tnf_tag_list_head;
45080Sstevel@tonic-gate __tnf_tag_list_head = tlist;
45090Sstevel@tonic-gate if (!boot_load)
45100Sstevel@tonic-gate mutex_exit(&mod_lock);
45110Sstevel@tonic-gate result = 1;
45120Sstevel@tonic-gate }
45130Sstevel@tonic-gate if (!boot_load && result && add_notify) {
45140Sstevel@tonic-gate tnf_add_notifyunload(tnf_unsplice_probes);
45150Sstevel@tonic-gate add_notify = 0;
45160Sstevel@tonic-gate }
45170Sstevel@tonic-gate return (result);
45180Sstevel@tonic-gate }
45190Sstevel@tonic-gate
45205648Ssetje char *kobj_file_buf;
45215648Ssetje int kobj_file_bufsize;
45225648Ssetje
45230Sstevel@tonic-gate /*
45240Sstevel@tonic-gate * This code is for the purpose of manually recording which files
45250Sstevel@tonic-gate * needs to go into the boot archive on any given system.
45260Sstevel@tonic-gate *
45270Sstevel@tonic-gate * To enable the code, set kobj_file_bufsize in /etc/system
45280Sstevel@tonic-gate * and reboot the system, then use mdb to look at kobj_file_buf.
45290Sstevel@tonic-gate */
45300Sstevel@tonic-gate static void
kobj_record_file(char * filename)45310Sstevel@tonic-gate kobj_record_file(char *filename)
45320Sstevel@tonic-gate {
45330Sstevel@tonic-gate static char *buf;
45340Sstevel@tonic-gate static int size = 0;
45350Sstevel@tonic-gate int n;
45360Sstevel@tonic-gate
45370Sstevel@tonic-gate if (kobj_file_bufsize == 0) /* don't bother */
45380Sstevel@tonic-gate return;
45390Sstevel@tonic-gate
45400Sstevel@tonic-gate if (kobj_file_buf == NULL) { /* allocate buffer */
45410Sstevel@tonic-gate size = kobj_file_bufsize;
45420Sstevel@tonic-gate buf = kobj_file_buf = kobj_alloc(size, KM_WAIT|KM_TMP);
45430Sstevel@tonic-gate }
45440Sstevel@tonic-gate
45450Sstevel@tonic-gate n = snprintf(buf, size, "%s\n", filename);
45460Sstevel@tonic-gate if (n > size)
45470Sstevel@tonic-gate n = size;
45480Sstevel@tonic-gate size -= n;
45490Sstevel@tonic-gate buf += n;
45500Sstevel@tonic-gate }
45510Sstevel@tonic-gate
45521544Seschrock static int
kobj_boot_fstat(int fd,struct bootstat * stp)45531544Seschrock kobj_boot_fstat(int fd, struct bootstat *stp)
45541544Seschrock {
45555648Ssetje #if defined(_OBP)
45561544Seschrock if (!standalone && _ioquiesced)
45571544Seschrock return (-1);
45581544Seschrock return (BOP_FSTAT(ops, fd, stp));
45591544Seschrock #else
45601544Seschrock return (BRD_FSTAT(bfs_ops, fd, stp));
45611544Seschrock #endif
45621544Seschrock }
45631544Seschrock
45640Sstevel@tonic-gate static int
kobj_boot_open(char * filename,int flags)45650Sstevel@tonic-gate kobj_boot_open(char *filename, int flags)
45660Sstevel@tonic-gate {
45675648Ssetje #if defined(_OBP)
45685648Ssetje
45690Sstevel@tonic-gate /*
45700Sstevel@tonic-gate * If io via bootops is quiesced, it means boot is no longer
45710Sstevel@tonic-gate * available to us. We make it look as if we can't open the
45720Sstevel@tonic-gate * named file - which is reasonably accurate.
45730Sstevel@tonic-gate */
45740Sstevel@tonic-gate if (!standalone && _ioquiesced)
45750Sstevel@tonic-gate return (-1);
45760Sstevel@tonic-gate
45775648Ssetje kobj_record_file(filename);
45785648Ssetje return (BOP_OPEN(filename, flags));
45790Sstevel@tonic-gate #else /* x86 */
45800Sstevel@tonic-gate kobj_record_file(filename);
45810Sstevel@tonic-gate return (BRD_OPEN(bfs_ops, filename, flags));
45820Sstevel@tonic-gate #endif
45830Sstevel@tonic-gate }
45840Sstevel@tonic-gate
45850Sstevel@tonic-gate static int
kobj_boot_close(int fd)45860Sstevel@tonic-gate kobj_boot_close(int fd)
45870Sstevel@tonic-gate {
45885648Ssetje #if defined(_OBP)
45890Sstevel@tonic-gate if (!standalone && _ioquiesced)
45900Sstevel@tonic-gate return (-1);
45910Sstevel@tonic-gate
45925648Ssetje return (BOP_CLOSE(fd));
45930Sstevel@tonic-gate #else /* x86 */
45940Sstevel@tonic-gate return (BRD_CLOSE(bfs_ops, fd));
45950Sstevel@tonic-gate #endif
45960Sstevel@tonic-gate }
45970Sstevel@tonic-gate
45980Sstevel@tonic-gate /*ARGSUSED*/
45990Sstevel@tonic-gate static int
kobj_boot_seek(int fd,off_t hi,off_t lo)46000Sstevel@tonic-gate kobj_boot_seek(int fd, off_t hi, off_t lo)
46010Sstevel@tonic-gate {
46025648Ssetje #if defined(_OBP)
46035648Ssetje return (BOP_SEEK(fd, lo) == -1 ? -1 : 0);
46040Sstevel@tonic-gate #else
46050Sstevel@tonic-gate return (BRD_SEEK(bfs_ops, fd, lo, SEEK_SET));
46060Sstevel@tonic-gate #endif
46070Sstevel@tonic-gate }
46080Sstevel@tonic-gate
46090Sstevel@tonic-gate static int
kobj_boot_read(int fd,caddr_t buf,size_t size)46100Sstevel@tonic-gate kobj_boot_read(int fd, caddr_t buf, size_t size)
46110Sstevel@tonic-gate {
46125648Ssetje #if defined(_OBP)
46135648Ssetje return (BOP_READ(fd, buf, size));
46140Sstevel@tonic-gate #else
46150Sstevel@tonic-gate return (BRD_READ(bfs_ops, fd, buf, size));
46160Sstevel@tonic-gate #endif
46170Sstevel@tonic-gate }
46185648Ssetje
46195648Ssetje static int
kobj_boot_compinfo(int fd,struct compinfo * cb)46205648Ssetje kobj_boot_compinfo(int fd, struct compinfo *cb)
46215648Ssetje {
46225648Ssetje return (boot_compinfo(fd, cb));
46235648Ssetje }
46247858SKrishnendu.Sadhukhan@Sun.COM
46257858SKrishnendu.Sadhukhan@Sun.COM /*
46267858SKrishnendu.Sadhukhan@Sun.COM * Check if the file is compressed (for now we handle only gzip).
46278001SKrishnendu.Sadhukhan@Sun.COM * It returns CH_MAGIC_GZIP if the file is compressed and 0 otherwise.
46287858SKrishnendu.Sadhukhan@Sun.COM */
46297858SKrishnendu.Sadhukhan@Sun.COM static int
kobj_is_compressed(intptr_t fd)46307858SKrishnendu.Sadhukhan@Sun.COM kobj_is_compressed(intptr_t fd)
46317858SKrishnendu.Sadhukhan@Sun.COM {
46327858SKrishnendu.Sadhukhan@Sun.COM struct vnode *vp = (struct vnode *)fd;
46337858SKrishnendu.Sadhukhan@Sun.COM ssize_t resid;
46347858SKrishnendu.Sadhukhan@Sun.COM uint16_t magic_buf;
46357858SKrishnendu.Sadhukhan@Sun.COM int err = 0;
46367858SKrishnendu.Sadhukhan@Sun.COM
46377858SKrishnendu.Sadhukhan@Sun.COM if ((err = vn_rdwr(UIO_READ, vp, (caddr_t)((intptr_t)&magic_buf),
46387858SKrishnendu.Sadhukhan@Sun.COM sizeof (magic_buf), (offset_t)(0),
46397858SKrishnendu.Sadhukhan@Sun.COM UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
46407858SKrishnendu.Sadhukhan@Sun.COM
46417858SKrishnendu.Sadhukhan@Sun.COM _kobj_printf(ops, "kobj_is_compressed: vn_rdwr() failed, "
46427858SKrishnendu.Sadhukhan@Sun.COM "error code 0x%x\n", err);
46437858SKrishnendu.Sadhukhan@Sun.COM return (0);
46447858SKrishnendu.Sadhukhan@Sun.COM }
46457858SKrishnendu.Sadhukhan@Sun.COM
46467858SKrishnendu.Sadhukhan@Sun.COM if (magic_buf == CH_MAGIC_GZIP)
46478001SKrishnendu.Sadhukhan@Sun.COM return (CH_MAGIC_GZIP);
46487858SKrishnendu.Sadhukhan@Sun.COM
46497858SKrishnendu.Sadhukhan@Sun.COM return (0);
46507858SKrishnendu.Sadhukhan@Sun.COM }
4651