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