xref: /netbsd-src/sys/arch/ia64/stand/common/fileload.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
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 
42 static int			file_load(char *filename, vaddr_t dest, struct preloaded_file **result);
43 static int			file_havepath(const char *name);
44 static void			file_insert_tail(struct preloaded_file *mp);
45 
46 /* load address should be tweaked by first module loaded (kernel) */
47 static vaddr_t	loadaddr = 0;
48 
49 struct 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 
59 int
60 command_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 
99 int
100 command_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 
115 int
116 command_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  */
144 int
145 file_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  */
174 int
175 file_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  */
214 struct preloaded_file *
215 file_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  */
230 static int
231 file_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  */
242 void
243 file_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  */
262 struct preloaded_file *
263 file_alloc(void)
264 {
265     struct preloaded_file	*fp;
266 
267     if ((fp = alloc(sizeof(struct preloaded_file))) != NULL) {
268 	bzero(fp, sizeof(struct preloaded_file));
269 
270 	if (fp->marks = alloc(sizeof(u_long))) {
271 		bzero(fp->marks, sizeof(u_long));
272 	}
273     }
274     return (fp);
275 }
276 
277 /*
278  * Add a module to the chain
279  */
280 static void
281 file_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