1/*	$NetBSD: fileload.c,v 1.1 2006/04/07 14:21:29 cherry Exp $	*/
2
3/*-
4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30
31/*
32 * file/module function dispatcher, support, etc.
33 */
34
35#include <lib/libsa/stand.h>
36#include <sys/param.h>
37#include <sys/lkm.h>
38#include <sys/queue.h>
39
40#include "bootstrap.h"
41
42static int			file_load(char *filename, vaddr_t dest, struct preloaded_file **result);
43static int			file_havepath(const char *name);
44static void			file_insert_tail(struct preloaded_file *mp);
45
46/* load address should be tweaked by first module loaded (kernel) */
47static vaddr_t	loadaddr = 0;
48
49struct preloaded_file *preloaded_files = NULL;
50
51/*
52 * load a kernel from disk.
53 *
54 * kernels are loaded as:
55 *
56 * load <path> <options>
57 */
58
59int
60command_load(int argc, char *argv[])
61{
62    char	*typestr;
63    int		dofile, dokld, ch, error;
64
65    dokld = dofile = 0;
66    optind = 1;
67    optreset = 1;
68    typestr = NULL;
69    if (argc == 1) {
70	command_errmsg = "no filename specified";
71	return(CMD_ERROR);
72    }
73    while ((ch = getopt(argc, argv, "k:")) != -1) {
74	switch(ch) {
75	case 'k':
76	    dokld = 1;
77	    break;
78	case '?':
79	default:
80	    /* getopt has already reported an error */
81	    return(CMD_OK);
82	}
83    }
84    argv += (optind - 1);
85    argc -= (optind - 1);
86
87    /*
88     * Do we have explicit KLD load ?
89     */
90    if (dokld || file_havepath(argv[1])) {
91	error = file_loadkernel(argv[1], argc - 2, argv + 2);
92	if (error == EEXIST)
93	    sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]);
94    }
95    return (error == 0 ? CMD_OK : CMD_ERROR);
96}
97
98
99int
100command_unload(int argc, char *argv[])
101{
102    struct preloaded_file	*fp;
103
104    while (preloaded_files != NULL) {
105	fp = preloaded_files;
106	preloaded_files = preloaded_files->f_next;
107	file_discard(fp);
108    }
109    loadaddr = 0;
110    unsetenv("kernelname");
111    return(CMD_OK);
112}
113
114
115int
116command_lskern(int argc, char *argv[])
117{
118    struct preloaded_file	*fp;
119    char			lbuf[80];
120    int				ch, verbose;
121
122    verbose = 0;
123    optind = 1;
124    optreset = 1;
125
126    pager_open();
127    for (fp = preloaded_files; fp; fp = fp->f_next) {
128	sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
129		(void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
130	pager_output(lbuf);
131	if (fp->f_args != NULL) {
132	    pager_output("    args: ");
133	    pager_output(fp->f_args);
134	    pager_output("\n");
135	}
136    }
137    pager_close();
138    return(CMD_OK);
139}
140
141/*
142 * File level interface, functions file_*
143 */
144int
145file_load(char *filename, vaddr_t dest, struct preloaded_file **result)
146{
147    struct preloaded_file *fp;
148    int error;
149    int i;
150
151    error = EFTYPE;
152    for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
153	error = (file_formats[i]->l_load)(filename, dest, &fp);
154	if (error == 0) {
155	    fp->f_loader = i;		/* remember the loader */
156	    *result = fp;
157	    break;
158	}
159	if (error == EFTYPE)
160	    continue;		/* Unknown to this handler? */
161	if (error) {
162	    sprintf(command_errbuf, "can't load file '%s': %s",
163		filename, strerror(error));
164	    break;
165	}
166    }
167    return (error);
168}
169
170/*
171 * Load specified KLD. If path is omitted, then try to locate it via
172 * search path.
173 */
174int
175file_loadkernel(char *filename, int argc, char *argv[])
176{
177    struct preloaded_file	*fp, *last_file;
178    int				err;
179
180    /*
181     * Check if KLD already loaded
182     */
183    fp = file_findfile(filename, NULL);
184    if (fp) {
185	sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
186	free(filename);
187	return (0);
188    }
189    for (last_file = preloaded_files;
190	 last_file != NULL && last_file->f_next != NULL;
191	 last_file = last_file->f_next)
192	;
193
194    do {
195	err = file_load(filename, loadaddr, &fp);
196	if (err)
197	    break;
198	fp->f_args = unargv(argc, argv);
199	loadaddr = fp->f_addr + fp->f_size;
200	file_insert_tail(fp);		/* Add to the list of loaded files */
201    } while(0);
202    if (err == EFTYPE)
203	sprintf(command_errbuf, "don't know how to load module '%s'", filename);
204    if (err && fp)
205	file_discard(fp);
206    free(filename);
207    return (err);
208}
209
210/*
211 * Find a file matching (name) and (type).
212 * NULL may be passed as a wildcard to either.
213 */
214struct preloaded_file *
215file_findfile(char *name, char *type)
216{
217    struct preloaded_file *fp;
218
219    for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
220	if (((name == NULL) || !strcmp(name, fp->f_name)) &&
221	    ((type == NULL) || !strcmp(type, fp->f_type)))
222	    break;
223    }
224    return (fp);
225}
226
227/*
228 * Check if file name have any qualifiers
229 */
230static int
231file_havepath(const char *name)
232{
233    const char		*cp;
234
235    archsw.arch_getdev(NULL, name, &cp);
236    return (cp != name || strchr(name, '/') != NULL);
237}
238
239/*
240 * Throw a file away
241 */
242void
243file_discard(struct preloaded_file *fp)
244{
245    if (fp == NULL)
246	return;
247    if (fp->f_name != NULL)
248	free(fp->f_name);
249    if (fp->f_type != NULL)
250        free(fp->f_type);
251    if (fp->f_args != NULL)
252        free(fp->f_args);
253    if (fp->marks != NULL)
254	free(fp->marks);
255    free(fp);
256}
257
258/*
259 * Allocate a new file; must be used instead of malloc()
260 * to ensure safe initialisation.
261 */
262struct preloaded_file *
263file_alloc(void)
264{
265    struct preloaded_file	*fp;
266
267    if ((fp = alloc(sizeof(struct preloaded_file))) != NULL) {
268	memset(fp, 0, sizeof(struct preloaded_file));
269
270	if (fp->marks = alloc(sizeof(u_long))) {
271		memset(fp->marks, 0, sizeof(u_long));
272	}
273    }
274    return (fp);
275}
276
277/*
278 * Add a module to the chain
279 */
280static void
281file_insert_tail(struct preloaded_file *fp)
282{
283    struct preloaded_file	*cm;
284
285    /* Append to list of loaded file */
286    fp->f_next = NULL;
287    if (preloaded_files == NULL) {
288	preloaded_files = fp;
289    } else {
290	for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
291	    ;
292	cm->f_next = fp;
293    }
294}
295
296