1 /* $NetBSD: fileload.c,v 1.5 2014/03/25 18:35:32 christos 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 <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
command_load(int argc,char * argv[])61 command_load(int argc, char *argv[])
62 {
63 char *typestr;
64 int dofile, dokld, ch;
65
66 dokld = dofile = 0;
67 optind = 1;
68 optreset = 1;
69 typestr = NULL;
70 if (argc == 1) {
71 command_seterr("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 int error = file_loadkernel(argv[1], argc - 2, argv + 2);
93 if (error == EEXIST)
94 command_seterr("warning: KLD '%s' already loaded", argv[1]);
95 return error == 0 ? CMD_OK : CMD_ERROR;
96 }
97 return CMD_OK;
98 }
99
100
101 int
command_unload(int argc,char * argv[])102 command_unload(int argc, char *argv[])
103 {
104 struct preloaded_file *fp;
105
106 while (preloaded_files != NULL) {
107 fp = preloaded_files;
108 preloaded_files = preloaded_files->f_next;
109 file_discard(fp);
110 }
111 loadaddr = 0;
112 unsetenv("kernelname");
113 return(CMD_OK);
114 }
115
116
117 int
command_lskern(int argc,char * argv[])118 command_lskern(int argc, char *argv[])
119 {
120 struct preloaded_file *fp;
121 char lbuf[80];
122 int ch, verbose;
123
124 verbose = 0;
125 optind = 1;
126 optreset = 1;
127
128 pager_open();
129 for (fp = preloaded_files; fp; fp = fp->f_next) {
130 snprintf(lbuf, sizeof(lbuf), " %p: %s (%s, 0x%lx)\n",
131 (void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size);
132 pager_output(lbuf);
133 if (fp->f_args != NULL) {
134 pager_output(" args: ");
135 pager_output(fp->f_args);
136 pager_output("\n");
137 }
138 }
139 pager_close();
140 return(CMD_OK);
141 }
142
143 /*
144 * File level interface, functions file_*
145 */
146 int
file_load(char * filename,vaddr_t dest,struct preloaded_file ** result)147 file_load(char *filename, vaddr_t dest, struct preloaded_file **result)
148 {
149 struct preloaded_file *fp;
150 int error;
151 int i;
152
153 error = EFTYPE;
154 for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) {
155 error = (file_formats[i]->l_load)(filename, dest, &fp);
156 if (error == 0) {
157 fp->f_loader = i; /* remember the loader */
158 *result = fp;
159 break;
160 }
161 if (error == EFTYPE)
162 continue; /* Unknown to this handler? */
163 if (error) {
164 command_seterr("can't load file '%s': %s",
165 filename, strerror(error));
166 break;
167 }
168 }
169 return (error);
170 }
171
172 /*
173 * Load specified KLD. If path is omitted, then try to locate it via
174 * search path.
175 */
176 int
file_loadkernel(char * filename,int argc,char * argv[])177 file_loadkernel(char *filename, int argc, char *argv[])
178 {
179 struct preloaded_file *fp, *last_file;
180 int err;
181
182 /*
183 * Check if KLD already loaded
184 */
185 fp = file_findfile(filename, NULL);
186 if (fp) {
187 command_seterr("warning: KLD '%s' already loaded", filename);
188 free(filename);
189 return (0);
190 }
191 for (last_file = preloaded_files;
192 last_file != NULL && last_file->f_next != NULL;
193 last_file = last_file->f_next)
194 ;
195
196 do {
197 err = file_load(filename, loadaddr, &fp);
198 if (err)
199 break;
200 fp->f_args = unargv(argc, argv);
201 loadaddr = fp->f_addr + fp->f_size;
202 file_insert_tail(fp); /* Add to the list of loaded files */
203 } while(0);
204 if (err == EFTYPE)
205 command_seterr("don't know how to load module '%s'", filename);
206 if (err && fp)
207 file_discard(fp);
208 free(filename);
209 return (err);
210 }
211
212 /*
213 * Find a file matching (name) and (type).
214 * NULL may be passed as a wildcard to either.
215 */
216 struct preloaded_file *
file_findfile(char * name,char * type)217 file_findfile(char *name, char *type)
218 {
219 struct preloaded_file *fp;
220
221 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
222 if (((name == NULL) || !strcmp(name, fp->f_name)) &&
223 ((type == NULL) || !strcmp(type, fp->f_type)))
224 break;
225 }
226 return (fp);
227 }
228
229 /*
230 * Check if file name have any qualifiers
231 */
232 static int
file_havepath(const char * name)233 file_havepath(const char *name)
234 {
235 const char *cp;
236
237 archsw.arch_getdev(NULL, name, &cp);
238 return (cp != name || strchr(name, '/') != NULL);
239 }
240
241 /*
242 * Throw a file away
243 */
244 void
file_discard(struct preloaded_file * fp)245 file_discard(struct preloaded_file *fp)
246 {
247 if (fp == NULL)
248 return;
249 if (fp->f_name != NULL)
250 free(fp->f_name);
251 if (fp->f_type != NULL)
252 free(fp->f_type);
253 if (fp->f_args != NULL)
254 free(fp->f_args);
255 if (fp->marks != NULL)
256 free(fp->marks);
257 free(fp);
258 }
259
260 /*
261 * Allocate a new file; must be used instead of malloc()
262 * to ensure safe initialisation.
263 */
264 struct preloaded_file *
file_alloc(void)265 file_alloc(void)
266 {
267 struct preloaded_file *fp;
268
269 if ((fp = alloc(sizeof(struct preloaded_file))) != NULL) {
270 memset(fp, 0, sizeof(struct preloaded_file));
271 /*
272 if (fp->marks = alloc(sizeof(u_long))) {
273 memset(fp->marks, 0, sizeof(u_long));
274 }
275 */
276 }
277 return (fp);
278 }
279
280 /*
281 * Add a module to the chain
282 */
283 static void
file_insert_tail(struct preloaded_file * fp)284 file_insert_tail(struct preloaded_file *fp)
285 {
286 struct preloaded_file *cm;
287
288 /* Append to list of loaded file */
289 fp->f_next = NULL;
290 if (preloaded_files == NULL) {
291 preloaded_files = fp;
292 } else {
293 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
294 ;
295 cm->f_next = fp;
296 }
297 }
298
299