fileload.c revision 1.3 1 /* $NetBSD: fileload.c,v 1.3 2012/12/27 20:21:51 martin Exp $ */
2
3 /*-
4 * Copyright (c) 1998 Michael Smith <msmith (at) 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 <lib/libsa/loadfile.h>
37 #include <lib/libkern/libkern.h>
38 #include <sys/param.h>
39 #include <sys/queue.h>
40
41 #include "bootstrap.h"
42
43 static int file_load(char *filename, vaddr_t dest, struct preloaded_file **result);
44 static int file_havepath(const char *name);
45 static void file_insert_tail(struct preloaded_file *mp);
46
47 /* load address should be tweaked by first module loaded (kernel) */
48 static vaddr_t loadaddr = 0;
49
50 struct preloaded_file *preloaded_files = NULL;
51
52 /*
53 * load a kernel from disk.
54 *
55 * kernels are loaded as:
56 *
57 * load <path> <options>
58 */
59
60 int
61 command_load(int argc, char *argv[])
62 {
63 char *typestr;
64 int dofile, dokld, ch, error;
65
66 dokld = dofile = 0;
67 optind = 1;
68 optreset = 1;
69 typestr = NULL;
70 if (argc == 1) {
71 command_errmsg = "no filename specified";
72 return(CMD_ERROR);
73 }
74 while ((ch = getopt(argc, argv, "k:")) != -1) {
75 switch(ch) {
76 case 'k':
77 dokld = 1;
78 break;
79 case '?':
80 default:
81 /* getopt has already reported an error */
82 return(CMD_OK);
83 }
84 }
85 argv += (optind - 1);
86 argc -= (optind - 1);
87
88 /*
89 * Do we have explicit KLD load ?
90 */
91 if (dokld || file_havepath(argv[1])) {
92 error = file_loadkernel(argv[1], argc - 2, argv + 2);
93 if (error == EEXIST)
94 sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]);
95 }
96 return (error == 0 ? CMD_OK : CMD_ERROR);
97 }
98
99
100 int
101 command_unload(int argc, char *argv[])
102 {
103 struct preloaded_file *fp;
104
105 while (preloaded_files != NULL) {
106 fp = preloaded_files;
107 preloaded_files = preloaded_files->f_next;
108 file_discard(fp);
109 }
110 loadaddr = 0;
111 unsetenv("kernelname");
112 return(CMD_OK);
113 }
114
115
116 int
117 command_lskern(int argc, char *argv[])
118 {
119 struct preloaded_file *fp;
120 char lbuf[80];
121 int ch, verbose;
122
123 verbose = 0;
124 optind = 1;
125 optreset = 1;
126
127 pager_open();
128 for (fp = preloaded_files; fp; fp = fp->f_next) {
129 sprintf(lbuf, " %p: %s (%s, 0x%lx)\n",
130 (void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
131 pager_output(lbuf);
132 if (fp->f_args != NULL) {
133 pager_output(" args: ");
134 pager_output(fp->f_args);
135 pager_output("\n");
136 }
137 }
138 pager_close();
139 return(CMD_OK);
140 }
141
142 /*
143 * File level interface, functions file_*
144 */
145 int
146 file_load(char *filename, vaddr_t dest, struct preloaded_file **result)
147 {
148 struct preloaded_file *fp;
149 int error;
150 int i;
151
152 error = EFTYPE;
153 for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
154 error = (file_formats[i]->l_load)(filename, dest, &fp);
155 if (error == 0) {
156 fp->f_loader = i; /* remember the loader */
157 *result = fp;
158 break;
159 }
160 if (error == EFTYPE)
161 continue; /* Unknown to this handler? */
162 if (error) {
163 sprintf(command_errbuf, "can't load file '%s': %s",
164 filename, strerror(error));
165 break;
166 }
167 }
168 return (error);
169 }
170
171 /*
172 * Load specified KLD. If path is omitted, then try to locate it via
173 * search path.
174 */
175 int
176 file_loadkernel(char *filename, int argc, char *argv[])
177 {
178 struct preloaded_file *fp, *last_file;
179 int err;
180
181 /*
182 * Check if KLD already loaded
183 */
184 fp = file_findfile(filename, NULL);
185 if (fp) {
186 sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename);
187 free(filename);
188 return (0);
189 }
190 for (last_file = preloaded_files;
191 last_file != NULL && last_file->f_next != NULL;
192 last_file = last_file->f_next)
193 ;
194
195 do {
196 err = file_load(filename, loadaddr, &fp);
197 if (err)
198 break;
199 fp->f_args = unargv(argc, argv);
200 loadaddr = fp->f_addr + fp->f_size;
201 file_insert_tail(fp); /* Add to the list of loaded files */
202 } while(0);
203 if (err == EFTYPE)
204 sprintf(command_errbuf, "don't know how to load module '%s'", filename);
205 if (err && fp)
206 file_discard(fp);
207 free(filename);
208 return (err);
209 }
210
211 /*
212 * Find a file matching (name) and (type).
213 * NULL may be passed as a wildcard to either.
214 */
215 struct preloaded_file *
216 file_findfile(char *name, char *type)
217 {
218 struct preloaded_file *fp;
219
220 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
221 if (((name == NULL) || !strcmp(name, fp->f_name)) &&
222 ((type == NULL) || !strcmp(type, fp->f_type)))
223 break;
224 }
225 return (fp);
226 }
227
228 /*
229 * Check if file name have any qualifiers
230 */
231 static int
232 file_havepath(const char *name)
233 {
234 const char *cp;
235
236 archsw.arch_getdev(NULL, name, &cp);
237 return (cp != name || strchr(name, '/') != NULL);
238 }
239
240 /*
241 * Throw a file away
242 */
243 void
244 file_discard(struct preloaded_file *fp)
245 {
246 if (fp == NULL)
247 return;
248 if (fp->f_name != NULL)
249 free(fp->f_name);
250 if (fp->f_type != NULL)
251 free(fp->f_type);
252 if (fp->f_args != NULL)
253 free(fp->f_args);
254 if (fp->marks != NULL)
255 free(fp->marks);
256 free(fp);
257 }
258
259 /*
260 * Allocate a new file; must be used instead of malloc()
261 * to ensure safe initialisation.
262 */
263 struct preloaded_file *
264 file_alloc(void)
265 {
266 struct preloaded_file *fp;
267
268 if ((fp = alloc(sizeof(struct preloaded_file))) != NULL) {
269 memset(fp, 0, sizeof(struct preloaded_file));
270 /*
271 if (fp->marks = alloc(sizeof(u_long))) {
272 memset(fp->marks, 0, sizeof(u_long));
273 }
274 */
275 }
276 return (fp);
277 }
278
279 /*
280 * Add a module to the chain
281 */
282 static void
283 file_insert_tail(struct preloaded_file *fp)
284 {
285 struct preloaded_file *cm;
286
287 /* Append to list of loaded file */
288 fp->f_next = NULL;
289 if (preloaded_files == NULL) {
290 preloaded_files = fp;
291 } else {
292 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
293 ;
294 cm->f_next = fp;
295 }
296 }
297
298