19890ff8Toomas Soome/*
2199767fToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3199767fToomas Soome * All rights reserved.
4199767fToomas Soome *
5199767fToomas Soome * Redistribution and use in source and binary forms, with or without
6199767fToomas Soome * modification, are permitted provided that the following conditions
7199767fToomas Soome * are met:
8199767fToomas Soome * 1. Redistributions of source code must retain the above copyright
9199767fToomas Soome *    notice, this list of conditions and the following disclaimer.
10199767fToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
11199767fToomas Soome *    notice, this list of conditions and the following disclaimer in the
12199767fToomas Soome *    documentation and/or other materials provided with the distribution.
13199767fToomas Soome *
14199767fToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767fToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767fToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767fToomas Soome * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767fToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767fToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767fToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767fToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767fToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767fToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767fToomas Soome * SUCH DAMAGE.
25199767fToomas Soome */
26199767fToomas Soome
27199767fToomas Soome#include <sys/cdefs.h>
28199767fToomas Soome
29199767fToomas Soome/*
30199767fToomas Soome * file/module function dispatcher, support, etc.
31199767fToomas Soome */
32199767fToomas Soome
33199767fToomas Soome#include <stand.h>
34199767fToomas Soome#include <string.h>
35199767fToomas Soome#include <sys/param.h>
36199767fToomas Soome#include <sys/linker.h>
37199767fToomas Soome#include <sys/module.h>
38199767fToomas Soome#include <sys/queue.h>
39199767fToomas Soome#include <sys/stdint.h>
409890ff8Toomas Soome#include <sys/tem_impl.h>
419890ff8Toomas Soome#include <sys/font.h>
42a103f15Toomas Soome#include <sys/sha1.h>
4306469a5Toomas Soome#include <libcrypto.h>
44199767fToomas Soome
45199767fToomas Soome#include "bootstrap.h"
46199767fToomas Soome
47a103f15Toomas Soome#if defined(EFI)
48a103f15Toomas Soome#define	PTOV(pa)	((void *)pa)
49a103f15Toomas Soome#else
50a103f15Toomas Soome#include "../i386/btx/lib/btxv86.h"
51a103f15Toomas Soome#endif
52a103f15Toomas Soome
53199767fToomas Soome#define	MDIR_REMOVED	0x0001
54199767fToomas Soome#define	MDIR_NOHINTS	0x0002
55199767fToomas Soome
56199767fToomas Soomestruct moduledir {
57199767fToomas Soome	char	*d_path;	/* path of modules directory */
580eb1a43Toomas Soome	uchar_t	*d_hints;	/* content of linker.hints file */
59199767fToomas Soome	int	d_hintsz;	/* size of hints data */
60199767fToomas Soome	int	d_flags;
61199767fToomas Soome	STAILQ_ENTRY(moduledir) d_link;
62199767fToomas Soome};
63199767fToomas Soome
640eb1a43Toomas Soomestatic int file_load(char *, vm_offset_t, struct preloaded_file **);
650eb1a43Toomas Soomestatic int file_load_dependencies(struct preloaded_file *);
660eb1a43Toomas Soomestatic char *file_search(const char *, const char **);
670eb1a43Toomas Soomestatic struct kernel_module *file_findmodule(struct preloaded_file *, char *,
680eb1a43Toomas Soome    struct mod_depend *);
690eb1a43Toomas Soomestatic int file_havepath(const char *);
700eb1a43Toomas Soomestatic char *mod_searchmodule(char *, struct mod_depend *);
710eb1a43Toomas Soomestatic void file_insert_tail(struct preloaded_file *);
72a8412dcToomas Soomestatic void file_remove(struct preloaded_file *);
730eb1a43Toomas Soomestruct file_metadata *metadata_next(struct file_metadata *, int);
740eb1a43Toomas Soomestatic void moduledir_readhints(struct moduledir *);
750eb1a43Toomas Soomestatic void moduledir_rebuild(void);
76199767fToomas Soome
77199767fToomas Soome/* load address should be tweaked by first module loaded (kernel) */
780eb1a43Toomas Soomestatic vm_offset_t loadaddr = 0;
79199767fToomas Soome
80199767fToomas Soome#if defined(LOADER_FDT_SUPPORT)
810eb1a43Toomas Soomestatic const char *default_searchpath = "/boot/kernel;/boot/modules;/boot/dtb";
82199767fToomas Soome#else
830eb1a43Toomas Soomestatic const char *default_searchpath = "/platform/i86pc";
84199767fToomas Soome#endif
85199767fToomas Soome
860eb1a43Toomas Soomestatic STAILQ_HEAD(, moduledir) moduledir_list =
870eb1a43Toomas Soome    STAILQ_HEAD_INITIALIZER(moduledir_list);
88199767fToomas Soome
89199767fToomas Soomestruct preloaded_file *preloaded_files = NULL;
90199767fToomas Soome
91199767fToomas Soomestatic const char *kld_ext_list[] = {
920eb1a43Toomas Soome	".ko",
930eb1a43Toomas Soome	"",
940eb1a43Toomas Soome	".debug",
950eb1a43Toomas Soome	NULL
96199767fToomas Soome};
97199767fToomas Soome
98199767fToomas Soome
99199767fToomas Soome/*
100199767fToomas Soome * load an object, either a disk file or code module.
101199767fToomas Soome *
102199767fToomas Soome * To load a file, the syntax is:
103199767fToomas Soome *
104199767fToomas Soome * load -t <type> <path>
105199767fToomas Soome *
106199767fToomas Soome * code modules are loaded as:
107199767fToomas Soome *
108199767fToomas Soome * load <path> <options>
109199767fToomas Soome */
110199767fToomas Soome
111199767fToomas SoomeCOMMAND_SET(load, "load", "load a kernel or module", command_load);
112199767fToomas Soome
113199767fToomas Soomestatic int
114199767fToomas Soomecommand_load(int argc, char *argv[])
115199767fToomas Soome{
1160eb1a43Toomas Soome	char *typestr;
1170eb1a43Toomas Soome	int dofile, dokld, ch, error;
1180eb1a43Toomas Soome
1190eb1a43Toomas Soome	dokld = dofile = 0;
1200eb1a43Toomas Soome	optind = 1;
1210eb1a43Toomas Soome	optreset = 1;
1220eb1a43Toomas Soome	typestr = NULL;
1230eb1a43Toomas Soome	if (argc == 1) {
1240eb1a43Toomas Soome		command_errmsg = "no filename specified";
1250eb1a43Toomas Soome		return (CMD_CRIT);
126199767fToomas Soome	}
1270eb1a43Toomas Soome	while ((ch = getopt(argc, argv, "kt:")) != -1) {
1280eb1a43Toomas Soome		switch (ch) {
1290eb1a43Toomas Soome		case 'k':
1300eb1a43Toomas Soome			dokld = 1;
1310eb1a43Toomas Soome			break;
1320eb1a43Toomas Soome		case 't':
1330eb1a43Toomas Soome			typestr = optarg;
1340eb1a43Toomas Soome			dofile = 1;
1350eb1a43Toomas Soome			break;
1360eb1a43Toomas Soome		case '?':
1370eb1a43Toomas Soome		default:
1380eb1a43Toomas Soome			/* getopt has already reported an error */
1390eb1a43Toomas Soome			return (CMD_OK);
1400eb1a43Toomas Soome		}
141199767fToomas Soome	}
1420eb1a43Toomas Soome	argv += (optind - 1);
1430eb1a43Toomas Soome	argc -= (optind - 1);
144199767fToomas Soome
1450eb1a43Toomas Soome	printf("Loading %s...\n", argv[1]);
1460eb1a43Toomas Soome	/*
1470eb1a43Toomas Soome	 * Request to load a raw file?
1480eb1a43Toomas Soome	 */
1490eb1a43Toomas Soome	if (dofile) {
1500eb1a43Toomas Soome		struct preloaded_file *fp;
151199767fToomas Soome
1520eb1a43Toomas Soome		if ((typestr == NULL) || (*typestr == 0)) {
1530eb1a43Toomas Soome			command_errmsg = "invalid load type";
1540eb1a43Toomas Soome			return (CMD_CRIT);
1550eb1a43Toomas Soome		}
156199767fToomas Soome
1570eb1a43Toomas Soome		if (file_findfile(argv[1], typestr) != NULL) {
1580eb1a43Toomas Soome			snprintf(command_errbuf, sizeof (command_errbuf),
1590eb1a43Toomas Soome			    "warning: file '%s' already loaded", argv[1]);
1600eb1a43Toomas Soome			return (CMD_WARN);
1610eb1a43Toomas Soome		}
162199767fToomas Soome
1630eb1a43Toomas Soome		fp = file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1);
1640eb1a43Toomas Soome		if (fp != NULL)
1650eb1a43Toomas Soome			return (CMD_OK);
1669890ff8Toomas Soome
1670eb1a43Toomas Soome		/* Failing to load mfs_root is never going to end well! */
1680eb1a43Toomas Soome		if (strcmp("mfs_root", typestr) == 0)
1690eb1a43Toomas Soome			return (CMD_FATAL);
170199767fToomas Soome
1710eb1a43Toomas Soome		return (CMD_ERROR);
1720eb1a43Toomas Soome	}
1730eb1a43Toomas Soome	/*
1740eb1a43Toomas Soome	 * Do we have explicit KLD load ?
1750eb1a43Toomas Soome	 */
1760eb1a43Toomas Soome	if (dokld || file_havepath(argv[1])) {
1770eb1a43Toomas Soome		error = mod_loadkld(argv[1], argc - 2, argv + 2);
1780eb1a43Toomas Soome		if (error == EEXIST) {
1790eb1a43Toomas Soome			snprintf(command_errbuf, sizeof (command_errbuf),
1800eb1a43Toomas Soome			    "warning: KLD '%s' already loaded", argv[1]);
1810eb1a43Toomas Soome			return (CMD_WARN);
1820eb1a43Toomas Soome		}
183199767fToomas Soome
1840eb1a43Toomas Soome		return (error == 0 ? CMD_OK : CMD_CRIT);
1850eb1a43Toomas Soome	}
1860eb1a43Toomas Soome	/*
1870eb1a43Toomas Soome	 * Looks like a request for a module.
1880eb1a43Toomas Soome	 */
1890eb1a43Toomas Soome	error = mod_load(argv[1], NULL, argc - 2, argv + 2);
1900eb1a43Toomas Soome	if (error == EEXIST) {
1910eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
1920eb1a43Toomas Soome		    "warning: module '%s' already loaded", argv[1]);
1930eb1a43Toomas Soome		return (CMD_WARN);
194199767fToomas Soome	}
1950eb1a43Toomas Soome
1960eb1a43Toomas Soome	return (error == 0 ? CMD_OK : CMD_CRIT);
197199767fToomas Soome}
198199767fToomas Soome
199199767fToomas Soomevoid
200199767fToomas Soomeunload(void)
201199767fToomas Soome{
2020eb1a43Toomas Soome	struct preloaded_file *fp;
2030eb1a43Toomas Soome
2040eb1a43Toomas Soome	while (preloaded_files != NULL) {
2050eb1a43Toomas Soome		fp = preloaded_files;
2060eb1a43Toomas Soome		preloaded_files = preloaded_files->f_next;
2070eb1a43Toomas Soome		file_discard(fp);
2080eb1a43Toomas Soome	}
2090eb1a43Toomas Soome	loadaddr = 0;
2100eb1a43Toomas Soome	unsetenv("kernelname");
211199767fToomas Soome}
212199767fToomas Soome
213199767fToomas SoomeCOMMAND_SET(unload, "unload", "unload all modules", command_unload);
214199767fToomas Soome
215199767fToomas Soomestatic int
2160eb1a43Toomas Soomecommand_unload(int argc __unused, char *argv[] __unused)
217199767fToomas Soome{
2180eb1a43Toomas Soome	unload();
2190eb1a43Toomas Soome	return (CMD_OK);
220199767fToomas Soome}
221199767fToomas Soome
222199767fToomas SoomeCOMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
223199767fToomas Soome
224199767fToomas Soomestatic int
225199767fToomas Soomecommand_lsmod(int argc, char *argv[])
226199767fToomas Soome{
2270eb1a43Toomas Soome	struct preloaded_file *fp;
2280eb1a43Toomas Soome	struct kernel_module *mp;
2290eb1a43Toomas Soome	struct file_metadata *md;
2300eb1a43Toomas Soome	char lbuf[80];
2310eb1a43Toomas Soome	int ch, verbose, hash, ret = 0;
2320eb1a43Toomas Soome
2330eb1a43Toomas Soome	verbose = 0;
2340eb1a43Toomas Soome	hash = 0;
2350eb1a43Toomas Soome	optind = 1;
2360eb1a43Toomas Soome	optreset = 1;
2370eb1a43Toomas Soome	while ((ch = getopt(argc, argv, "vs")) != -1) {
2380eb1a43Toomas Soome		switch (ch) {
2390eb1a43Toomas Soome		case 'v':
2400eb1a43Toomas Soome			verbose = 1;
2410eb1a43Toomas Soome			break;
2420eb1a43Toomas Soome		case 's':
2430eb1a43Toomas Soome			hash = 1;
2440eb1a43Toomas Soome			break;
2450eb1a43Toomas Soome		case '?':
2460eb1a43Toomas Soome		default:
2470eb1a43Toomas Soome			/* getopt has already reported an error */
2480eb1a43Toomas Soome			return (CMD_OK);
2490eb1a43Toomas Soome		}
250199767fToomas Soome	}
2510eb1a43Toomas Soome
2520eb1a43Toomas Soome	pager_open();
2530eb1a43Toomas Soome	for (fp = preloaded_files; fp; fp = fp->f_next) {
2540eb1a43Toomas Soome		sprintf(lbuf, " %p: ", (void *) fp->f_addr);
2550eb1a43Toomas Soome		pager_output(lbuf);
2560eb1a43Toomas Soome		pager_output(fp->f_name);
2570eb1a43Toomas Soome		sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size);
258a103f15Toomas Soome		if (pager_output(lbuf))
259a103f15Toomas Soome			break;
2600eb1a43Toomas Soome		if (fp->f_args != NULL) {
2610eb1a43Toomas Soome			pager_output("    args: ");
2620eb1a43Toomas Soome			pager_output(fp->f_args);
2630eb1a43Toomas Soome			if (pager_output("\n"))
2640eb1a43Toomas Soome				break;
2650eb1a43Toomas Soome			if (strcmp(fp->f_type, "hash") == 0) {
2660eb1a43Toomas Soome				pager_output("    contents: ");
267e10751aToomas Soome				strlcpy(lbuf, PTOV(fp->f_addr), sizeof (lbuf));
2680eb1a43Toomas Soome				if (pager_output(lbuf))
2690eb1a43Toomas Soome					break;
2700eb1a43Toomas Soome			}
2710eb1a43Toomas Soome		}
272a103f15Toomas Soome
2730eb1a43Toomas Soome		if (hash == 1) {
2740eb1a43Toomas Soome			void *ptr = PTOV(fp->f_addr);
275a103f15Toomas Soome
2760eb1a43Toomas Soome			pager_output("  hash: ");
2770eb1a43Toomas Soome			sha1(ptr, fp->f_size, (uint8_t *)lbuf);
2780eb1a43Toomas Soome			for (int i = 0; i < SHA1_DIGEST_LENGTH; i++)
2790eb1a43Toomas Soome				printf("%02x", (int)(lbuf[i] & 0xff));
2800eb1a43Toomas Soome			if (pager_output("\n"))
2810eb1a43Toomas Soome				break;
2820eb1a43Toomas Soome		}
283a103f15Toomas Soome
2840eb1a43Toomas Soome		if (fp->f_modules) {
2850eb1a43Toomas Soome			pager_output("  modules: ");
2860eb1a43Toomas Soome			for (mp = fp->f_modules; mp; mp = mp->m_next) {
2870eb1a43Toomas Soome				sprintf(lbuf, "%s.%d ", mp->m_name,
2880eb1a43Toomas Soome				    mp->m_version);
2890eb1a43Toomas Soome				pager_output(lbuf);
2900eb1a43Toomas Soome			}
2910eb1a43Toomas Soome			if (pager_output("\n"))
2920eb1a43Toomas Soome				break;
2930eb1a43Toomas Soome		}
2940eb1a43Toomas Soome		if (verbose) {
2950eb1a43Toomas Soome			/*
2960eb1a43Toomas Soome			 * XXX could add some formatting smarts here to
2970eb1a43Toomas Soome			 * display some better
2980eb1a43Toomas Soome			 */
2990eb1a43Toomas Soome			for (md = fp->f_metadata; md != NULL;
3000eb1a43Toomas Soome			    md = md->md_next) {
3010eb1a43Toomas Soome				sprintf(lbuf, "      0x%04x, 0x%lx\n",
3020eb1a43Toomas Soome				    md->md_type, (long)md->md_size);
3030eb1a43Toomas Soome				if ((ret = pager_output(lbuf)))
3040eb1a43Toomas Soome					break;
3050eb1a43Toomas Soome			}
3060eb1a43Toomas Soome		}
3070eb1a43Toomas Soome		if (ret != 0)
3080eb1a43Toomas Soome			break;
309199767fToomas Soome	}
3100eb1a43Toomas Soome	pager_close();
3110eb1a43Toomas Soome	return (CMD_OK);
312199767fToomas Soome}
313199767fToomas Soome
314199767fToomas Soome/*
315199767fToomas Soome * File level interface, functions file_*
316199767fToomas Soome */
317199767fToomas Soomeint
318199767fToomas Soomefile_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
319199767fToomas Soome{
3200eb1a43Toomas Soome	static int last_file_format = 0;
3210eb1a43Toomas Soome	struct preloaded_file *fp;
3220eb1a43Toomas Soome	int error;
3230eb1a43Toomas Soome	int i;
3240eb1a43Toomas Soome
3250eb1a43Toomas Soome	if (preloaded_files == NULL)
3260eb1a43Toomas Soome		last_file_format = 0;
3270eb1a43Toomas Soome
3280eb1a43Toomas Soome	if (archsw.arch_loadaddr != NULL)
3290eb1a43Toomas Soome		dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
3300eb1a43Toomas Soome
3310eb1a43Toomas Soome	error = EFTYPE;
3320eb1a43Toomas Soome	for (i = last_file_format, fp = NULL;
3330eb1a43Toomas Soome	    file_formats[i] && fp == NULL; i++) {
3340eb1a43Toomas Soome		error = (file_formats[i]->l_load)(filename, dest, &fp);
3350eb1a43Toomas Soome		if (error == 0) {
3360eb1a43Toomas Soome			/* remember the loader */
3370eb1a43Toomas Soome			fp->f_loader = last_file_format = i;
3380eb1a43Toomas Soome			*result = fp;
3390eb1a43Toomas Soome			break;
3400eb1a43Toomas Soome		} else if (last_file_format == i && i != 0) {
3410eb1a43Toomas Soome			/* Restart from the beginning */
3420eb1a43Toomas Soome			i = -1;
3430eb1a43Toomas Soome			last_file_format = 0;
3440eb1a43Toomas Soome			fp = NULL;
3450eb1a43Toomas Soome			continue;
3460eb1a43Toomas Soome		}
3470eb1a43Toomas Soome		if (error == EFTYPE)
3480eb1a43Toomas Soome			continue;	/* Unknown to this handler? */
3490eb1a43Toomas Soome		if (error) {
3500eb1a43Toomas Soome			snprintf(command_errbuf, sizeof (command_errbuf),
3510eb1a43Toomas Soome			    "can't load file '%s': %s", filename,
3520eb1a43Toomas Soome			    strerror(error));
3530eb1a43Toomas Soome			break;
3540eb1a43Toomas Soome		}
355199767fToomas Soome	}
3560eb1a43Toomas Soome	return (error);
357199767fToomas Soome}
358199767fToomas Soome
359199767fToomas Soomestatic int
360199767fToomas Soomefile_load_dependencies(struct preloaded_file *base_file)
361199767fToomas Soome{
3620eb1a43Toomas Soome	struct file_metadata *md;
3630eb1a43Toomas Soome	struct preloaded_file *fp;
3640eb1a43Toomas Soome	struct mod_depend *verinfo;
3650eb1a43Toomas Soome	struct kernel_module *mp;
3660eb1a43Toomas Soome	char *dmodname;
3670eb1a43Toomas Soome	int error;
3680eb1a43Toomas Soome
3690eb1a43Toomas Soome	md = file_findmetadata(base_file, MODINFOMD_DEPLIST);
3700eb1a43Toomas Soome	if (md == NULL)
3710eb1a43Toomas Soome		return (0);
3720eb1a43Toomas Soome	error = 0;
3730eb1a43Toomas Soome	do {
3740eb1a43Toomas Soome		verinfo = (struct mod_depend *)md->md_data;
3750eb1a43Toomas Soome		dmodname = (char *)(verinfo + 1);
3760eb1a43Toomas Soome		if (file_findmodule(NULL, dmodname, verinfo) == NULL) {
3770eb1a43Toomas Soome			printf("loading required module '%s'\n", dmodname);
3780eb1a43Toomas Soome			error = mod_load(dmodname, verinfo, 0, NULL);
3790eb1a43Toomas Soome			if (error)
3800eb1a43Toomas Soome				break;
3810eb1a43Toomas Soome			/*
3820eb1a43Toomas Soome			 * If module loaded via kld name which isn't listed
3830eb1a43Toomas Soome			 * in the linker.hints file, we should check if it have
3840eb1a43Toomas Soome			 * required version.
3850eb1a43Toomas Soome			 */
3860eb1a43Toomas Soome			mp = file_findmodule(NULL, dmodname, verinfo);
3870eb1a43Toomas Soome			if (mp == NULL) {
3880eb1a43Toomas Soome				snprintf(command_errbuf,
3890eb1a43Toomas Soome				    sizeof (command_errbuf),
3900eb1a43Toomas Soome				    "module '%s' exists but with wrong version",
3910eb1a43Toomas Soome				    dmodname);
3920eb1a43Toomas Soome				error = ENOENT;
3930eb1a43Toomas Soome				break;
3940eb1a43Toomas Soome			}
3950eb1a43Toomas Soome		}
3960eb1a43Toomas Soome		md = metadata_next(md, MODINFOMD_DEPLIST);
3970eb1a43Toomas Soome	} while (md);
3980eb1a43Toomas Soome	if (!error)
3990eb1a43Toomas Soome		return (0);
4000eb1a43Toomas Soome	/* Load failed; discard everything */
4010eb1a43Toomas Soome	while (base_file != NULL) {
4020eb1a43Toomas Soome		fp = base_file;
4030eb1a43Toomas Soome		base_file = base_file->f_next;
4040eb1a43Toomas Soome		file_discard(fp);
405199767fToomas Soome	}
4060eb1a43Toomas Soome	return (error);
407199767fToomas Soome}
408199767fToomas Soome
409199767fToomas Soome/*
41076608ffToomas Soome * Calculate the size of the environment module.
41176608ffToomas Soome * The environment is list of name=value C strings, ending with a '\0' byte.
41276608ffToomas Soome */
41376608ffToomas Soomestatic size_t
41476608ffToomas Soomeenv_get_size(void)
41576608ffToomas Soome{
41676608ffToomas Soome	size_t size = 0;
41776608ffToomas Soome	struct env_var *ep;
41876608ffToomas Soome
41976608ffToomas Soome	/* Traverse the environment. */
42076608ffToomas Soome	for (ep = environ; ep != NULL; ep = ep->ev_next) {
42176608ffToomas Soome		size += strlen(ep->ev_name);
42276608ffToomas Soome		size++;		/* "=" */
42376608ffToomas Soome		if (ep->ev_value != NULL)
42476608ffToomas Soome			size += strlen(ep->ev_value);
42576608ffToomas Soome		size++;		/* nul byte */
42676608ffToomas Soome	}
42776608ffToomas Soome	size++;			/* nul byte */
42876608ffToomas Soome	return (size);
42976608ffToomas Soome}
43076608ffToomas Soome
431a103f15Toomas Soomestatic void
432a103f15Toomas Soomemodule_hash(struct preloaded_file *fp, void *addr, size_t size)
433a103f15Toomas Soome{
434a103f15Toomas Soome	uint8_t hash[SHA1_DIGEST_LENGTH];
435a103f15Toomas Soome	char ascii[2 * SHA1_DIGEST_LENGTH + 1];
436a103f15Toomas Soome	int i;
437a103f15Toomas Soome
438a103f15Toomas Soome	sha1(addr, size, hash);
439a103f15Toomas Soome	for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
440a103f15Toomas Soome		snprintf(ascii + 2 * i, sizeof (ascii) - 2 * i, "%02x",
441a103f15Toomas Soome		    hash[i] & 0xff);
442a103f15Toomas Soome	}
443a103f15Toomas Soome	/* Out of memory here is not fatal issue. */
444a103f15Toomas Soome	asprintf(&fp->f_args, "hash=%s", ascii);
445a103f15Toomas Soome}
446a103f15Toomas Soome
44776608ffToomas Soome/*
44876608ffToomas Soome * Create virtual module for environment variables.
44976608ffToomas Soome * This module should be created as late as possible before executing
45076608ffToomas Soome * the OS kernel, or we may miss some environment variable updates.
45176608ffToomas Soome */
45276608ffToomas Soomevoid
45376608ffToomas Soomebuild_environment_module(void)
45476608ffToomas Soome{
45576608ffToomas Soome	struct preloaded_file *fp;
45676608ffToomas Soome	size_t size;
45776608ffToomas Soome	char *name = "environment";
45876608ffToomas Soome	vm_offset_t laddr;
45976608ffToomas Soome
46076608ffToomas Soome	/* We can't load first */
46176608ffToomas Soome	if ((file_findfile(NULL, NULL)) == NULL) {
46276608ffToomas Soome		printf("Can not load environment module: %s\n",
46376608ffToomas Soome		    "the kernel is not loaded");
46476608ffToomas Soome		return;
46576608ffToomas Soome	}
46676608ffToomas Soome
4679890ff8Toomas Soome	tem_save_state();	/* Ask tem to save it's state in env. */
46876608ffToomas Soome	size = env_get_size();
46976608ffToomas Soome
47076608ffToomas Soome	fp = file_alloc();
47176608ffToomas Soome	if (fp != NULL) {
47276608ffToomas Soome		fp->f_name = strdup(name);
47376608ffToomas Soome		fp->f_type = strdup(name);
47476608ffToomas Soome	}
47576608ffToomas Soome
47676608ffToomas Soome	if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
47776608ffToomas Soome		printf("Can not load environment module: %s\n",
47876608ffToomas Soome		    "out of memory");
47908e3b8cToomas Soome		file_discard(fp);
48076608ffToomas Soome		return;
48176608ffToomas Soome	}
48276608ffToomas Soome
48376608ffToomas Soome
48476608ffToomas Soome	if (archsw.arch_loadaddr != NULL)
48576608ffToomas Soome		loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
48676608ffToomas Soome
48776608ffToomas Soome	if (loadaddr == 0) {
48876608ffToomas Soome		printf("Can not load environment module: %s\n",
48976608ffToomas Soome		    "out of memory");
49076608ffToomas Soome		file_discard(fp);
49176608ffToomas Soome		return;
49276608ffToomas Soome	}
49376608ffToomas Soome
49476608ffToomas Soome	laddr = bi_copyenv(loadaddr);
49576608ffToomas Soome	/* Looks OK so far; populate control structure */
496a103f15Toomas Soome	module_hash(fp, PTOV(loadaddr), laddr - loadaddr);
49776608ffToomas Soome	fp->f_loader = -1;
49876608ffToomas Soome	fp->f_addr = loadaddr;
49976608ffToomas Soome	fp->f_size = laddr - loadaddr;
50076608ffToomas Soome
50176608ffToomas Soome	/* recognise space consumption */
50276608ffToomas Soome	loadaddr = laddr;
50376608ffToomas Soome
50476608ffToomas Soome	file_insert_tail(fp);
50576608ffToomas Soome}
50676608ffToomas Soome
5079890ff8Toomas Soomevoid
5089890ff8Toomas Soomebuild_font_module(void)
5099890ff8Toomas Soome{
5109890ff8Toomas Soome	bitmap_data_t *bd;
5119890ff8Toomas Soome	struct font *fd;
5129890ff8Toomas Soome	struct preloaded_file *fp;
5139890ff8Toomas Soome	size_t size;
5149890ff8Toomas Soome	uint32_t checksum;
5159890ff8Toomas Soome	int i;
5169890ff8Toomas Soome	char *name = "console-font";
5179890ff8Toomas Soome	vm_offset_t laddr;
5189890ff8Toomas Soome	struct font_info fi;
5199890ff8Toomas Soome	struct fontlist *fl;
5209890ff8Toomas Soome
5219890ff8Toomas Soome	if (STAILQ_EMPTY(&fonts))
5229890ff8Toomas Soome		return;
5239890ff8Toomas Soome
5249890ff8Toomas Soome	/* We can't load first */
5259890ff8Toomas Soome	if ((file_findfile(NULL, NULL)) == NULL) {
5269890ff8Toomas Soome		printf("Can not load font module: %s\n",
5279890ff8Toomas Soome		    "the kernel is not loaded");
5289890ff8Toomas Soome		return;
5299890ff8Toomas Soome	}
5309890ff8Toomas Soome
5319890ff8Toomas Soome	/* helper pointers */
5329890ff8Toomas Soome	bd = NULL;
5339890ff8Toomas Soome	STAILQ_FOREACH(fl, &fonts, font_next) {
5349890ff8Toomas Soome		if (fl->font_data->font != NULL) {
5359890ff8Toomas Soome			bd = fl->font_data;
5369890ff8Toomas Soome			break;
5379890ff8Toomas Soome		}
5389890ff8Toomas Soome	}
5399890ff8Toomas Soome	if (bd == NULL)
5409890ff8Toomas Soome		return;
5419890ff8Toomas Soome	fd = bd->font;
5429890ff8Toomas Soome
5439890ff8Toomas Soome	fi.fi_width = fd->vf_width;
5449890ff8Toomas Soome	checksum = fi.fi_width;
5459890ff8Toomas Soome	fi.fi_height = fd->vf_height;
5469890ff8Toomas Soome	checksum += fi.fi_height;
5479890ff8Toomas Soome	fi.fi_bitmap_size = bd->uncompressed_size;
5489890ff8Toomas Soome	checksum += fi.fi_bitmap_size;
5499890ff8Toomas Soome
5509890ff8Toomas Soome	size = roundup2(sizeof (struct font_info), 8);
5519890ff8Toomas Soome	for (i = 0; i < VFNT_MAPS; i++) {
5529890ff8Toomas Soome		fi.fi_map_count[i] = fd->vf_map_count[i];
5539890ff8Toomas Soome		checksum += fi.fi_map_count[i];
5549890ff8Toomas Soome		size += fd->vf_map_count[i] * sizeof (struct font_map);
5559890ff8Toomas Soome		size += roundup2(size, 8);
5569890ff8Toomas Soome	}
5579890ff8Toomas Soome	size += bd->uncompressed_size;
5589890ff8Toomas Soome
5599890ff8Toomas Soome	fi.fi_checksum = -checksum;
5609890ff8Toomas Soome
5619890ff8Toomas Soome	fp = file_alloc();
5629890ff8Toomas Soome	if (fp != NULL) {
5639890ff8Toomas Soome		fp->f_name = strdup(name);
5649890ff8Toomas Soome		fp->f_type = strdup(name);
5659890ff8Toomas Soome	}
5669890ff8Toomas Soome
5679890ff8Toomas Soome	if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
5689890ff8Toomas Soome		printf("Can not load font module: %s\n",
5699890ff8Toomas Soome		    "out of memory");
57008e3b8cToomas Soome		file_discard(fp);
5719890ff8Toomas Soome		return;
5729890ff8Toomas Soome	}
5739890ff8Toomas Soome
5749890ff8Toomas Soome	if (archsw.arch_loadaddr != NULL)
5759890ff8Toomas Soome		loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
5769890ff8Toomas Soome
5779890ff8Toomas Soome	if (loadaddr == 0) {
5789890ff8Toomas Soome		printf("Can not load font module: %s\n",
5799890ff8Toomas Soome		    "out of memory");
5809890ff8Toomas Soome		file_discard(fp);
5819890ff8Toomas Soome		return;
5829890ff8Toomas Soome	}
5839890ff8Toomas Soome
5849890ff8Toomas Soome	laddr = loadaddr;
5859890ff8Toomas Soome	laddr += archsw.arch_copyin(&fi, laddr, sizeof (struct font_info));
5869890ff8Toomas Soome	laddr = roundup2(laddr, 8);
5879890ff8Toomas Soome
5889890ff8Toomas Soome	/* Copy maps. */
5899890ff8Toomas Soome	for (i = 0; i < VFNT_MAPS; i++) {
5909890ff8Toomas Soome		if (fd->vf_map_count[i] != 0) {
5919890ff8Toomas Soome			laddr += archsw.arch_copyin(fd->vf_map[i], laddr,
5929890ff8Toomas Soome			    fd->vf_map_count[i] * sizeof (struct font_map));
5939890ff8Toomas Soome			laddr = roundup2(laddr, 8);
5949890ff8Toomas Soome		}
5959890ff8Toomas Soome	}
5969890ff8Toomas Soome
5979890ff8Toomas Soome	/* Copy the bitmap. */
5989890ff8Toomas Soome	laddr += archsw.arch_copyin(fd->vf_bytes, laddr, fi.fi_bitmap_size);
5999890ff8Toomas Soome
6009890ff8Toomas Soome	/* Looks OK so far; populate control structure */
601a103f15Toomas Soome	module_hash(fp, PTOV(loadaddr), laddr - loadaddr);
6029890ff8Toomas Soome	fp->f_loader = -1;
6039890ff8Toomas Soome	fp->f_addr = loadaddr;
6049890ff8Toomas Soome	fp->f_size = laddr - loadaddr;
6059890ff8Toomas Soome
6069890ff8Toomas Soome	/* recognise space consumption */
6079890ff8Toomas Soome	loadaddr = laddr;
6089890ff8Toomas Soome
6099890ff8Toomas Soome	file_insert_tail(fp);
6109890ff8Toomas Soome}
6119890ff8Toomas Soome
61276608ffToomas Soome/*
613199767fToomas Soome * We've been asked to load (fname) as (type), so just suck it in,
614199767fToomas Soome * no arguments or anything.
615199767fToomas Soome */
616199767fToomas Soomestruct preloaded_file *
617199767fToomas Soomefile_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
618199767fToomas Soome{
6190eb1a43Toomas Soome	struct preloaded_file *fp;
6200eb1a43Toomas Soome	char *name;
6210eb1a43Toomas Soome	int fd, got;
6220eb1a43Toomas Soome	vm_offset_t laddr;
6230eb1a43Toomas Soome	struct stat st;
6240eb1a43Toomas Soome
6250eb1a43Toomas Soome	/* We can't load first */
6260eb1a43Toomas Soome	if ((file_findfile(NULL, NULL)) == NULL) {
6270eb1a43Toomas Soome		command_errmsg = "can't load file before kernel";
6280eb1a43Toomas Soome		return (NULL);
629199767fToomas Soome	}
630199767fToomas Soome
6310eb1a43Toomas Soome	/* locate the file on the load path */
6320eb1a43Toomas Soome	name = file_search(fname, NULL);
6330eb1a43Toomas Soome	if (name == NULL) {
6340eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
6350eb1a43Toomas Soome		    "can't find '%s'", fname);
6360eb1a43Toomas Soome		return (NULL);
6370eb1a43Toomas Soome	}
6380eb1a43Toomas Soome
6390eb1a43Toomas Soome	if ((fd = open(name, O_RDONLY)) < 0) {
6400eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
6410eb1a43Toomas Soome		    "can't open '%s': %s", name, strerror(errno));
6420eb1a43Toomas Soome		free(name);
6430eb1a43Toomas Soome		return (NULL);
6440eb1a43Toomas Soome	}
6450eb1a43Toomas Soome	if (fstat(fd, &st) < 0) {
6460eb1a43Toomas Soome		close(fd);
6470eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
6480eb1a43Toomas Soome		    "stat error '%s': %s", name, strerror(errno));
6490eb1a43Toomas Soome		free(name);
6500eb1a43Toomas Soome		return (NULL);
6510eb1a43Toomas Soome	}
6520eb1a43Toomas Soome
6530eb1a43Toomas Soome	if (archsw.arch_loadaddr != NULL)
6540eb1a43Toomas Soome		loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
6550eb1a43Toomas Soome	if (loadaddr == 0) {
6560eb1a43Toomas Soome		close(fd);
6570eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
6580eb1a43Toomas Soome		    "no memory to load %s", name);
6590eb1a43Toomas Soome		free(name);
6600eb1a43Toomas Soome		return (NULL);
6610eb1a43Toomas Soome	}
6620eb1a43Toomas Soome
6630eb1a43Toomas Soome	laddr = loadaddr;
6640eb1a43Toomas Soome	for (;;) {
6650eb1a43Toomas Soome		/* read in 4k chunks; size is not really important */
6660eb1a43Toomas Soome		got = archsw.arch_readin(fd, laddr, 4096);
6670eb1a43Toomas Soome		if (got == 0)			/* end of file */
6680eb1a43Toomas Soome			break;
6690eb1a43Toomas Soome		if (got < 0) {			/* error */
6700eb1a43Toomas Soome			snprintf(command_errbuf, sizeof (command_errbuf),
6710eb1a43Toomas Soome			    "error reading '%s': %s", name, strerror(errno));
6720eb1a43Toomas Soome			free(name);
6730eb1a43Toomas Soome			close(fd);
674873f5d0Toomas Soome			if (archsw.arch_free_loadaddr != NULL &&
675873f5d0Toomas Soome			    st.st_size != 0) {
6760eb1a43Toomas Soome				archsw.arch_free_loadaddr(loadaddr,
6770eb1a43Toomas Soome				    (uint64_t)
6780eb1a43Toomas Soome				    (roundup2(st.st_size, PAGE_SIZE) >> 12));
6790eb1a43Toomas Soome			}
6800eb1a43Toomas Soome			return (NULL);
6810eb1a43Toomas Soome		}
6820eb1a43Toomas Soome		laddr += got;
6830eb1a43Toomas Soome	}
6840eb1a43Toomas Soome
6850eb1a43Toomas Soome	/* Looks OK so far; create & populate control structure */
6860eb1a43Toomas Soome	fp = file_alloc();
6870eb1a43Toomas Soome	if (fp == NULL) {
688873f5d0Toomas Soome		if (archsw.arch_free_loadaddr != NULL && st.st_size != 0)
6890eb1a43Toomas Soome			archsw.arch_free_loadaddr(loadaddr,
6900eb1a43Toomas Soome			    (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12));
6910eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
6920eb1a43Toomas Soome		    "no memory to load %s", name);
6930eb1a43Toomas Soome		free(name);
6940eb1a43Toomas Soome		close(fd);
6950eb1a43Toomas Soome		return (NULL);
6960eb1a43Toomas Soome	}
6970eb1a43Toomas Soome
6980eb1a43Toomas Soome	fp->f_name = name;
6990eb1a43Toomas Soome	fp->f_args = unargv(argc, argv);
7000eb1a43Toomas Soome	fp->f_type = strdup(type);
7010eb1a43Toomas Soome	fp->f_metadata = NULL;
7020eb1a43Toomas Soome	fp->f_loader = -1;
7030eb1a43Toomas Soome	fp->f_addr = loadaddr;
7040eb1a43Toomas Soome	fp->f_size = laddr - loadaddr;
7050eb1a43Toomas Soome
7060eb1a43Toomas Soome	if (fp->f_type == NULL ||
7070eb1a43Toomas Soome	    (argc != 0 && fp->f_args == NULL)) {
7080eb1a43Toomas Soome		close(fd);
7090eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
7100eb1a43Toomas Soome		    "no memory to load %s", name);
7110eb1a43Toomas Soome		file_discard(fp);
7120eb1a43Toomas Soome		return (NULL);
7130eb1a43Toomas Soome	}
7140eb1a43Toomas Soome	/* recognise space consumption */
7150eb1a43Toomas Soome	loadaddr = laddr;
7160eb1a43Toomas Soome
7170eb1a43Toomas Soome	/* Add to the list of loaded files */
7180eb1a43Toomas Soome	if (insert != 0)
7190eb1a43Toomas Soome		file_insert_tail(fp);
7200eb1a43Toomas Soome	close(fd);
7210eb1a43Toomas Soome	return (fp);
722199767fToomas Soome}
723199767fToomas Soome
724199767fToomas Soome/*
725199767fToomas Soome * Load the module (name), pass it (argc),(argv), add container file
726199767fToomas Soome * to the list of loaded files.
727199767fToomas Soome * If module is already loaded just assign new argc/argv.
728199767fToomas Soome */
729199767fToomas Soomeint
730199767fToomas Soomemod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
731199767fToomas Soome{
7320eb1a43Toomas Soome	struct kernel_module *mp;
7330eb1a43Toomas Soome	int err;
7340eb1a43Toomas Soome	char *filename;
7350eb1a43Toomas Soome
7360eb1a43Toomas Soome	if (file_havepath(modname)) {
7370eb1a43Toomas Soome		printf("Warning: mod_load() called instead of mod_loadkld() "
7380eb1a43Toomas Soome		    "for module '%s'\n", modname);
7390eb1a43Toomas Soome		return (mod_loadkld(modname, argc, argv));
7400eb1a43Toomas Soome	}
7410eb1a43Toomas Soome	/* see if module is already loaded */
7420eb1a43Toomas Soome	mp = file_findmodule(NULL, modname, verinfo);
7430eb1a43Toomas Soome	if (mp != NULL) {
7440eb1a43Toomas Soome		free(mp->m_args);
7450eb1a43Toomas Soome		mp->m_args = unargv(argc, argv);
7460eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
7470eb1a43Toomas Soome		    "warning: module '%s' already loaded", mp->m_name);
7480eb1a43Toomas Soome		return (0);
7490eb1a43Toomas Soome	}
7500eb1a43Toomas Soome	/* locate file with the module on the search path */
7510eb1a43Toomas Soome	filename = mod_searchmodule(modname, verinfo);
7520eb1a43Toomas Soome	if (filename == NULL) {
7530eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
7540eb1a43Toomas Soome		    "can't find '%s'", modname);
7550eb1a43Toomas Soome		return (ENOENT);
7560eb1a43Toomas Soome	}
7570eb1a43Toomas Soome	err = mod_loadkld(filename, argc, argv);
7580eb1a43Toomas Soome	free(filename);
7590eb1a43Toomas Soome	return (err);
760199767fToomas Soome}
761199767fToomas Soome
762199767fToomas Soome/*
763199767fToomas Soome * Load specified KLD. If path is omitted, then try to locate it via
764199767fToomas Soome * search path.
765199767fToomas Soome */
766199767fToomas Soomeint
767199767fToomas Soomemod_loadkld(const char *kldname, int argc, char *argv[])
768199767fToomas Soome{
769a8412dcToomas Soome	struct preloaded_file *fp;
7700eb1a43Toomas Soome	int err;
7710eb1a43Toomas Soome	char *filename;
772a8412dcToomas Soome	vm_offset_t loadaddr_saved;
7730eb1a43Toomas Soome
7740eb1a43Toomas Soome	/*
7750eb1a43Toomas Soome	 * Get fully qualified KLD name
7760eb1a43Toomas Soome	 */
7770eb1a43Toomas Soome	filename = file_search(kldname, kld_ext_list);
7780eb1a43Toomas Soome	if (filename == NULL) {
7790eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
7800eb1a43Toomas Soome		    "can't find '%s'", kldname);
7810eb1a43Toomas Soome		return (ENOENT);
782199767fToomas Soome	}
7830eb1a43Toomas Soome	/*
7840eb1a43Toomas Soome	 * Check if KLD already loaded
7850eb1a43Toomas Soome	 */
7860eb1a43Toomas Soome	fp = file_findfile(filename, NULL);
7870eb1a43Toomas Soome	if (fp != NULL) {
7880eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
7890eb1a43Toomas Soome		    "warning: KLD '%s' already loaded", filename);
7900eb1a43Toomas Soome		free(filename);
7910eb1a43Toomas Soome		return (0);
7920eb1a43Toomas Soome	}
7930eb1a43Toomas Soome
7940eb1a43Toomas Soome	do {
7950eb1a43Toomas Soome		err = file_load(filename, loadaddr, &fp);
7960eb1a43Toomas Soome		if (err)
7970eb1a43Toomas Soome			break;
7980eb1a43Toomas Soome		fp->f_args = unargv(argc, argv);
799a8412dcToomas Soome		loadaddr_saved = loadaddr;
8000eb1a43Toomas Soome		loadaddr = fp->f_addr + fp->f_size;
8010eb1a43Toomas Soome		file_insert_tail(fp);	/* Add to the list of loaded files */
8020eb1a43Toomas Soome		if (file_load_dependencies(fp) != 0) {
8030eb1a43Toomas Soome			err = ENOENT;
804a8412dcToomas Soome			file_remove(fp);
805a8412dcToomas Soome			loadaddr = loadaddr_saved;
8060eb1a43Toomas Soome			fp = NULL;
8070eb1a43Toomas Soome			break;
8080eb1a43Toomas Soome		}
8090eb1a43Toomas Soome	} while (0);
8100eb1a43Toomas Soome	if (err == EFTYPE) {
8110eb1a43Toomas Soome		snprintf(command_errbuf, sizeof (command_errbuf),
8120eb1a43Toomas Soome		    "don't know how to load module '%s'", filename);
8130eb1a43Toomas Soome	}
8140eb1a43Toomas Soome	if (err)
8150eb1a43Toomas Soome		file_discard(fp);
8160eb1a43Toomas Soome	free(filename);
8170eb1a43Toomas Soome	return (err);
818199767fToomas Soome}
819199767fToomas Soome
820199767fToomas Soome/*
821199767fToomas Soome * Find a file matching (name) and (type).
822199767fToomas Soome * NULL may be passed as a wildcard to either.
823199767fToomas Soome */
824199767fToomas Soomestruct preloaded_file *
825199767fToomas Soomefile_findfile(const char *name, const char *type)
826199767fToomas Soome{
8270eb1a43Toomas Soome	struct preloaded_file *fp;
8280eb1a43Toomas Soome
8290eb1a43Toomas Soome	for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
8300eb1a43Toomas Soome		if (((name == NULL) || strcmp(name, fp->f_name) == 0) &&
8310eb1a43Toomas Soome		    ((type == NULL) || strcmp(type, fp->f_type) == 0))
8320eb1a43Toomas Soome			break;
8330eb1a43Toomas Soome	}
8340eb1a43Toomas Soome	return (fp);
835199767fToomas Soome}
836199767fToomas Soome
837199767fToomas Soome/*
838199767fToomas Soome * Find a module matching (name) inside of given file.
839199767fToomas Soome * NULL may be passed as a wildcard.
840199767fToomas Soome */
841199767fToomas Soomestruct kernel_module *
842199767fToomas Soomefile_findmodule(struct preloaded_file *fp, char *modname,
8430eb1a43Toomas Soome    struct mod_depend *verinfo)
844199767fToomas Soome{
8450eb1a43Toomas Soome	struct kernel_module *mp, *best;
8460eb1a43Toomas Soome	int bestver, mver;
8470eb1a43Toomas Soome
8480eb1a43Toomas Soome	if (fp == NULL) {
8490eb1a43Toomas Soome		for (fp = preloaded_files; fp; fp = fp->f_next) {
8500eb1a43Toomas Soome			mp = file_findmodule(fp, modname, verinfo);
8510eb1a43Toomas Soome			if (mp != NULL)
8520eb1a43Toomas Soome				return (mp);
8530eb1a43Toomas Soome		}
8540eb1a43Toomas Soome		return (NULL);
855199767fToomas Soome	}
8560eb1a43Toomas Soome	best = NULL;
8570eb1a43Toomas Soome	bestver = 0;
8580eb1a43Toomas Soome	for (mp = fp->f_modules; mp; mp = mp->m_next) {
8590eb1a43Toomas Soome		if (strcmp(modname, mp->m_name) == 0) {
8600eb1a43Toomas Soome			if (verinfo == NULL)
8610eb1a43Toomas Soome				return (mp);
8620eb1a43Toomas Soome			mver = mp->m_version;
8630eb1a43Toomas Soome			if (mver == verinfo->md_ver_preferred)
8640eb1a43Toomas Soome				return (mp);
8650eb1a43Toomas Soome			if (mver >= verinfo->md_ver_minimum &&
8660eb1a43Toomas Soome			    mver <= verinfo->md_ver_maximum &&
8670eb1a43Toomas Soome			    mver > bestver) {
8680eb1a43Toomas Soome				best = mp;
8690eb1a43Toomas Soome				bestver = mver;
8700eb1a43Toomas Soome			}
8710eb1a43Toomas Soome		}
872199767fToomas Soome	}
8730eb1a43Toomas Soome	return (best);
874199767fToomas Soome}
875199767fToomas Soome/*
876199767fToomas Soome * Make a copy of (size) bytes of data from (p), and associate them as
877199767fToomas Soome * metadata of (type) to the module (mp).
878199767fToomas Soome */
879199767fToomas Soomevoid
880199767fToomas Soomefile_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
881199767fToomas Soome{
88208e3b8cToomas Soome	struct file_metadata	*md;
88308e3b8cToomas Soome
88408e3b8cToomas Soome	md = malloc(sizeof (struct file_metadata) - sizeof (md->md_data) +
88508e3b8cToomas Soome	    size);
88608e3b8cToomas Soome	if (md != NULL) {
88708e3b8cToomas Soome		md->md_size = size;
88808e3b8cToomas Soome		md->md_type = type;
88908e3b8cToomas Soome		bcopy(p, md->md_data, size);
89008e3b8cToomas Soome		md->md_next = fp->f_metadata;
89108e3b8cToomas Soome	}
89208e3b8cToomas Soome	fp->f_metadata = md;
893199767fToomas Soome}
894199767fToomas Soome
895199767fToomas Soome/*
896199767fToomas Soome * Find a metadata object of (type) associated with the file (fp)
897199767fToomas Soome */
898199767fToomas Soomestruct file_metadata *
899199767fToomas Soomefile_findmetadata(struct preloaded_file *fp, int type)
900199767fToomas Soome{
9010eb1a43Toomas Soome	struct file_metadata *md;
902199767fToomas Soome
9030eb1a43Toomas Soome	for (md = fp->f_metadata; md != NULL; md = md->md_next)
9040eb1a43Toomas Soome		if (md->md_type == type)
9050eb1a43Toomas Soome			break;
9060eb1a43Toomas Soome	return (md);
907199767fToomas Soome}
908199767fToomas Soome
909199767fToomas Soomestruct file_metadata *
910199767fToomas Soomemetadata_next(struct file_metadata *md, int type)
911199767fToomas Soome{
9120eb1a43Toomas Soome
9130eb1a43Toomas Soome	if (md == NULL)
9140eb1a43Toomas Soome		return (NULL);
9150eb1a43Toomas Soome	while ((md = md->md_next) != NULL)
9160eb1a43Toomas Soome		if (md->md_type == type)
9170eb1a43Toomas Soome			break;
9180eb1a43Toomas Soome	return (md);
919199767fToomas Soome}
920199767fToomas Soome
921199767fToomas Soomestatic const char *emptyextlist[] = { "", NULL };
922199767fToomas Soome
923199767fToomas Soome/*
924199767fToomas Soome * Check if the given file is in place and return full path to it.
925199767fToomas Soome */
926199767fToomas Soomestatic char *
9270eb1a43Toomas Soomefile_lookup(const char *path, const char *name, int namelen,
9280eb1a43Toomas Soome    const char **extlist)
929199767fToomas Soome{
9300eb1a43Toomas Soome	struct stat st;
9310eb1a43Toomas Soome	char *result, *cp;
9320eb1a43Toomas Soome	const char **cpp;
9330eb1a43Toomas Soome	int pathlen, extlen, len;
9340eb1a43Toomas Soome
9350eb1a43Toomas Soome	pathlen = strlen(path);
9360eb1a43Toomas Soome	extlen = 0;
9370eb1a43Toomas Soome	if (extlist == NULL)
9380eb1a43Toomas Soome		extlist = emptyextlist;
9390eb1a43Toomas Soome	for (cpp = extlist; *cpp; cpp++) {
9400eb1a43Toomas Soome		len = strlen(*cpp);
9410eb1a43Toomas Soome		if (len > extlen)
9420eb1a43Toomas Soome			extlen = len;
9430eb1a43Toomas Soome	}
9440eb1a43Toomas Soome	result = malloc(pathlen + namelen + extlen + 2);
9450eb1a43Toomas Soome	if (result == NULL)
9460eb1a43Toomas Soome		return (NULL);
9470eb1a43Toomas Soome	bcopy(path, result, pathlen);
9480eb1a43Toomas Soome	if (pathlen > 0 && result[pathlen - 1] != '/')
9490eb1a43Toomas Soome		result[pathlen++] = '/';
9500eb1a43Toomas Soome	cp = result + pathlen;
951