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