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