1 1.5 christos /* $NetBSD: fileload.c,v 1.5 2014/03/25 18:35:32 christos Exp $ */ 2 1.1 cherry 3 1.1 cherry /*- 4 1.1 cherry * Copyright (c) 1998 Michael Smith <msmith (at) freebsd.org> 5 1.1 cherry * All rights reserved. 6 1.1 cherry * 7 1.1 cherry * Redistribution and use in source and binary forms, with or without 8 1.1 cherry * modification, are permitted provided that the following conditions 9 1.1 cherry * are met: 10 1.1 cherry * 1. Redistributions of source code must retain the above copyright 11 1.1 cherry * notice, this list of conditions and the following disclaimer. 12 1.1 cherry * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cherry * notice, this list of conditions and the following disclaimer in the 14 1.1 cherry * documentation and/or other materials provided with the distribution. 15 1.1 cherry * 16 1.1 cherry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 cherry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 cherry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 cherry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 cherry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 cherry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 cherry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 cherry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 cherry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 cherry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 cherry * SUCH DAMAGE. 27 1.1 cherry */ 28 1.1 cherry 29 1.1 cherry #include <sys/cdefs.h> 30 1.1 cherry 31 1.1 cherry /* 32 1.1 cherry * file/module function dispatcher, support, etc. 33 1.1 cherry */ 34 1.1 cherry 35 1.1 cherry #include <lib/libsa/stand.h> 36 1.3 martin #include <lib/libsa/loadfile.h> 37 1.3 martin #include <lib/libkern/libkern.h> 38 1.1 cherry #include <sys/param.h> 39 1.1 cherry #include <sys/queue.h> 40 1.1 cherry 41 1.1 cherry #include "bootstrap.h" 42 1.1 cherry 43 1.1 cherry static int file_load(char *filename, vaddr_t dest, struct preloaded_file **result); 44 1.1 cherry static int file_havepath(const char *name); 45 1.1 cherry static void file_insert_tail(struct preloaded_file *mp); 46 1.1 cherry 47 1.1 cherry /* load address should be tweaked by first module loaded (kernel) */ 48 1.1 cherry static vaddr_t loadaddr = 0; 49 1.1 cherry 50 1.1 cherry struct preloaded_file *preloaded_files = NULL; 51 1.1 cherry 52 1.1 cherry /* 53 1.1 cherry * load a kernel from disk. 54 1.1 cherry * 55 1.1 cherry * kernels are loaded as: 56 1.1 cherry * 57 1.1 cherry * load <path> <options> 58 1.1 cherry */ 59 1.1 cherry 60 1.1 cherry int 61 1.1 cherry command_load(int argc, char *argv[]) 62 1.1 cherry { 63 1.1 cherry char *typestr; 64 1.4 christos int dofile, dokld, ch; 65 1.1 cherry 66 1.1 cherry dokld = dofile = 0; 67 1.1 cherry optind = 1; 68 1.1 cherry optreset = 1; 69 1.1 cherry typestr = NULL; 70 1.1 cherry if (argc == 1) { 71 1.5 christos command_seterr("no filename specified"); 72 1.1 cherry return(CMD_ERROR); 73 1.1 cherry } 74 1.1 cherry while ((ch = getopt(argc, argv, "k:")) != -1) { 75 1.1 cherry switch(ch) { 76 1.1 cherry case 'k': 77 1.1 cherry dokld = 1; 78 1.1 cherry break; 79 1.1 cherry case '?': 80 1.1 cherry default: 81 1.1 cherry /* getopt has already reported an error */ 82 1.1 cherry return(CMD_OK); 83 1.1 cherry } 84 1.1 cherry } 85 1.1 cherry argv += (optind - 1); 86 1.1 cherry argc -= (optind - 1); 87 1.1 cherry 88 1.1 cherry /* 89 1.1 cherry * Do we have explicit KLD load ? 90 1.1 cherry */ 91 1.1 cherry if (dokld || file_havepath(argv[1])) { 92 1.4 christos int error = file_loadkernel(argv[1], argc - 2, argv + 2); 93 1.1 cherry if (error == EEXIST) 94 1.5 christos command_seterr("warning: KLD '%s' already loaded", argv[1]); 95 1.4 christos return error == 0 ? CMD_OK : CMD_ERROR; 96 1.1 cherry } 97 1.4 christos return CMD_OK; 98 1.1 cherry } 99 1.1 cherry 100 1.1 cherry 101 1.1 cherry int 102 1.1 cherry command_unload(int argc, char *argv[]) 103 1.1 cherry { 104 1.1 cherry struct preloaded_file *fp; 105 1.1 cherry 106 1.1 cherry while (preloaded_files != NULL) { 107 1.1 cherry fp = preloaded_files; 108 1.1 cherry preloaded_files = preloaded_files->f_next; 109 1.1 cherry file_discard(fp); 110 1.1 cherry } 111 1.1 cherry loadaddr = 0; 112 1.1 cherry unsetenv("kernelname"); 113 1.1 cherry return(CMD_OK); 114 1.1 cherry } 115 1.1 cherry 116 1.1 cherry 117 1.1 cherry int 118 1.1 cherry command_lskern(int argc, char *argv[]) 119 1.1 cherry { 120 1.1 cherry struct preloaded_file *fp; 121 1.1 cherry char lbuf[80]; 122 1.1 cherry int ch, verbose; 123 1.1 cherry 124 1.1 cherry verbose = 0; 125 1.1 cherry optind = 1; 126 1.1 cherry optreset = 1; 127 1.1 cherry 128 1.1 cherry pager_open(); 129 1.1 cherry for (fp = preloaded_files; fp; fp = fp->f_next) { 130 1.5 christos snprintf(lbuf, sizeof(lbuf), " %p: %s (%s, 0x%lx)\n", 131 1.1 cherry (void *) fp->f_addr, fp->f_name, fp->f_type, (long) fp->f_size); 132 1.1 cherry pager_output(lbuf); 133 1.1 cherry if (fp->f_args != NULL) { 134 1.1 cherry pager_output(" args: "); 135 1.1 cherry pager_output(fp->f_args); 136 1.1 cherry pager_output("\n"); 137 1.1 cherry } 138 1.1 cherry } 139 1.1 cherry pager_close(); 140 1.1 cherry return(CMD_OK); 141 1.1 cherry } 142 1.1 cherry 143 1.1 cherry /* 144 1.1 cherry * File level interface, functions file_* 145 1.1 cherry */ 146 1.1 cherry int 147 1.1 cherry file_load(char *filename, vaddr_t dest, struct preloaded_file **result) 148 1.1 cherry { 149 1.1 cherry struct preloaded_file *fp; 150 1.1 cherry int error; 151 1.1 cherry int i; 152 1.1 cherry 153 1.1 cherry error = EFTYPE; 154 1.1 cherry for (i = 0, fp = NULL; file_formats[i] && fp == NULL; i++) { 155 1.1 cherry error = (file_formats[i]->l_load)(filename, dest, &fp); 156 1.1 cherry if (error == 0) { 157 1.1 cherry fp->f_loader = i; /* remember the loader */ 158 1.1 cherry *result = fp; 159 1.1 cherry break; 160 1.1 cherry } 161 1.1 cherry if (error == EFTYPE) 162 1.1 cherry continue; /* Unknown to this handler? */ 163 1.1 cherry if (error) { 164 1.5 christos command_seterr("can't load file '%s': %s", 165 1.1 cherry filename, strerror(error)); 166 1.1 cherry break; 167 1.1 cherry } 168 1.1 cherry } 169 1.1 cherry return (error); 170 1.1 cherry } 171 1.1 cherry 172 1.1 cherry /* 173 1.1 cherry * Load specified KLD. If path is omitted, then try to locate it via 174 1.1 cherry * search path. 175 1.1 cherry */ 176 1.1 cherry int 177 1.1 cherry file_loadkernel(char *filename, int argc, char *argv[]) 178 1.1 cherry { 179 1.1 cherry struct preloaded_file *fp, *last_file; 180 1.1 cherry int err; 181 1.1 cherry 182 1.1 cherry /* 183 1.1 cherry * Check if KLD already loaded 184 1.1 cherry */ 185 1.1 cherry fp = file_findfile(filename, NULL); 186 1.1 cherry if (fp) { 187 1.5 christos command_seterr("warning: KLD '%s' already loaded", filename); 188 1.1 cherry free(filename); 189 1.1 cherry return (0); 190 1.1 cherry } 191 1.1 cherry for (last_file = preloaded_files; 192 1.1 cherry last_file != NULL && last_file->f_next != NULL; 193 1.1 cherry last_file = last_file->f_next) 194 1.1 cherry ; 195 1.1 cherry 196 1.1 cherry do { 197 1.1 cherry err = file_load(filename, loadaddr, &fp); 198 1.1 cherry if (err) 199 1.1 cherry break; 200 1.1 cherry fp->f_args = unargv(argc, argv); 201 1.1 cherry loadaddr = fp->f_addr + fp->f_size; 202 1.1 cherry file_insert_tail(fp); /* Add to the list of loaded files */ 203 1.1 cherry } while(0); 204 1.1 cherry if (err == EFTYPE) 205 1.5 christos command_seterr("don't know how to load module '%s'", filename); 206 1.1 cherry if (err && fp) 207 1.1 cherry file_discard(fp); 208 1.1 cherry free(filename); 209 1.1 cherry return (err); 210 1.1 cherry } 211 1.1 cherry 212 1.1 cherry /* 213 1.1 cherry * Find a file matching (name) and (type). 214 1.1 cherry * NULL may be passed as a wildcard to either. 215 1.1 cherry */ 216 1.1 cherry struct preloaded_file * 217 1.1 cherry file_findfile(char *name, char *type) 218 1.1 cherry { 219 1.1 cherry struct preloaded_file *fp; 220 1.1 cherry 221 1.1 cherry for (fp = preloaded_files; fp != NULL; fp = fp->f_next) { 222 1.1 cherry if (((name == NULL) || !strcmp(name, fp->f_name)) && 223 1.1 cherry ((type == NULL) || !strcmp(type, fp->f_type))) 224 1.1 cherry break; 225 1.1 cherry } 226 1.1 cherry return (fp); 227 1.1 cherry } 228 1.1 cherry 229 1.1 cherry /* 230 1.1 cherry * Check if file name have any qualifiers 231 1.1 cherry */ 232 1.1 cherry static int 233 1.1 cherry file_havepath(const char *name) 234 1.1 cherry { 235 1.1 cherry const char *cp; 236 1.1 cherry 237 1.1 cherry archsw.arch_getdev(NULL, name, &cp); 238 1.1 cherry return (cp != name || strchr(name, '/') != NULL); 239 1.1 cherry } 240 1.1 cherry 241 1.1 cherry /* 242 1.1 cherry * Throw a file away 243 1.1 cherry */ 244 1.1 cherry void 245 1.1 cherry file_discard(struct preloaded_file *fp) 246 1.1 cherry { 247 1.1 cherry if (fp == NULL) 248 1.1 cherry return; 249 1.1 cherry if (fp->f_name != NULL) 250 1.1 cherry free(fp->f_name); 251 1.1 cherry if (fp->f_type != NULL) 252 1.1 cherry free(fp->f_type); 253 1.1 cherry if (fp->f_args != NULL) 254 1.1 cherry free(fp->f_args); 255 1.1 cherry if (fp->marks != NULL) 256 1.1 cherry free(fp->marks); 257 1.1 cherry free(fp); 258 1.1 cherry } 259 1.1 cherry 260 1.1 cherry /* 261 1.1 cherry * Allocate a new file; must be used instead of malloc() 262 1.1 cherry * to ensure safe initialisation. 263 1.1 cherry */ 264 1.1 cherry struct preloaded_file * 265 1.1 cherry file_alloc(void) 266 1.1 cherry { 267 1.1 cherry struct preloaded_file *fp; 268 1.1 cherry 269 1.1 cherry if ((fp = alloc(sizeof(struct preloaded_file))) != NULL) { 270 1.2 cegger memset(fp, 0, sizeof(struct preloaded_file)); 271 1.3 martin /* 272 1.1 cherry if (fp->marks = alloc(sizeof(u_long))) { 273 1.2 cegger memset(fp->marks, 0, sizeof(u_long)); 274 1.1 cherry } 275 1.3 martin */ 276 1.1 cherry } 277 1.1 cherry return (fp); 278 1.1 cherry } 279 1.1 cherry 280 1.1 cherry /* 281 1.1 cherry * Add a module to the chain 282 1.1 cherry */ 283 1.1 cherry static void 284 1.1 cherry file_insert_tail(struct preloaded_file *fp) 285 1.1 cherry { 286 1.1 cherry struct preloaded_file *cm; 287 1.1 cherry 288 1.1 cherry /* Append to list of loaded file */ 289 1.1 cherry fp->f_next = NULL; 290 1.1 cherry if (preloaded_files == NULL) { 291 1.1 cherry preloaded_files = fp; 292 1.1 cherry } else { 293 1.1 cherry for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) 294 1.1 cherry ; 295 1.1 cherry cm->f_next = fp; 296 1.1 cherry } 297 1.1 cherry } 298 1.1 cherry 299