1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
2 /* $OpenBSD: loadfile.c,v 1.14 2007/06/26 10:32:50 tom Exp $ */
3
4 /*-
5 * Copyright (c) 1997 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center and by Christos Zoulas.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*
42 * Copyright (c) 1992, 1993
43 * The Regents of the University of California. All rights reserved.
44 *
45 * This code is derived from software contributed to Berkeley by
46 * Ralph Campbell.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 *
72 * @(#)boot.c 8.1 (Berkeley) 6/10/93
73 */
74
75 #ifdef _STANDALONE
76 #include <lib/libkern/libkern.h>
77 #include <lib/libsa/stand.h>
78 #else
79 #include <stdio.h>
80 #include <string.h>
81 #include <errno.h>
82 #include <stdlib.h>
83 #include <unistd.h>
84 #include <fcntl.h>
85 #include <err.h>
86 #endif
87
88 #include <sys/param.h>
89 #include <sys/exec.h>
90
91 #include "loadfile.h"
92
93 #ifdef BOOT_ECOFF
94 #include <sys/exec_ecoff.h>
95 static int coff_exec(int, struct ecoff_exechdr *, u_long *, int);
96 #endif
97 #ifdef BOOT_AOUT
98 #include <sys/exec_aout.h>
99 static int aout_exec(int, struct exec *, u_long *, int);
100 #endif
101
102 #ifdef BOOT_ELF
103 #include <sys/exec_elf.h>
104 #if defined(BOOT_ELF32) && defined(BOOT_ELF64)
105 /*
106 * Both defined, so elf32_exec() and elf64_exec() need to be separately
107 * created (can't do it by including loadfile_elf.c here).
108 */
109 int elf32_exec(int, Elf32_Ehdr *, u_long *, int);
110 int elf64_exec(int, Elf64_Ehdr *, u_long *, int);
111 #else
112 #include "loadfile_elf.c"
113 #endif
114 #endif
115
116 /*
117 * Open 'filename', read in program and return -1 on error otherwise fd,
118 * with file still open.
119 * Also fills in marks.
120 */
121 int
122 loadfile(const char *fname, u_long *marks, int flags)
123 {
124 union {
125 #ifdef BOOT_ECOFF
126 struct ecoff_exechdr coff;
127 #endif
128 #if defined(BOOT_ELF32) || (defined(BOOT_ELF) && ELFSIZE == 32)
129 Elf32_Ehdr elf32;
130 #endif
131 #if defined(BOOT_ELF64) || (defined(BOOT_ELF) && ELFSIZE == 64)
132 Elf64_Ehdr elf64;
133 #endif
134 #ifdef BOOT_AOUT
135 struct exec aout;
136 #endif
137
138 } hdr;
139 ssize_t nr;
140 int fd, rval;
141
142 /* Open the file. */
143 if ((fd = open(fname, 0)) < 0) {
144 WARN(("open %s", fname ? fname : "<default>"));
145 return -1;
146 }
147
148 /* Read the exec header. */
149 if ((nr = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) {
150 WARN(("read header"));
151 goto err;
152 }
153
154 #ifdef BOOT_ECOFF
155 if (!ECOFF_BADMAG(&hdr.coff)) {
156 rval = coff_exec(fd, &hdr.coff, marks, flags);
157 } else
158 #endif
159 #if defined(BOOT_ELF32) || (defined(BOOT_ELF) && ELFSIZE == 32)
160 if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
161 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
162 rval = elf32_exec(fd, &hdr.elf32, marks, flags);
163 } else
164 #endif
165 #if defined(BOOT_ELF64) || (defined(BOOT_ELF) && ELFSIZE == 64)
166 if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
167 hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
168 rval = elf64_exec(fd, &hdr.elf64, marks, flags);
169 } else
170 #endif
171 #ifdef BOOT_AOUT
172 if (OKMAGIC(N_GETMAGIC(hdr.aout))
173 #ifndef NO_MID_CHECK
174 && N_GETMID(hdr.aout) == MID_MACHINE
175 #endif
176 ) {
177 rval = aout_exec(fd, &hdr.aout, marks, flags);
178 } else
179 #endif
180 {
181 rval = 1;
182 errno = EFTYPE;
183 WARN(("%s", fname ? fname : "<default>"));
184 }
185
186 if (rval == 0) {
187 PROGRESS(("=0x%lx\n", marks[MARK_END] - marks[MARK_START]));
188 return fd;
189 }
190 err:
191 (void)close(fd);
192 return -1;
193 }
194
195 #ifdef BOOT_ECOFF
196 static int
197 coff_exec(int fd, struct ecoff_exechdr *coff, u_long *marks, int flags)
198 {
199 paddr_t offset = marks[MARK_START];
200 paddr_t minp = ~0, maxp = 0, pos;
201
202 /* Read in text. */
203 if (lseek(fd, ECOFF_TXTOFF(coff), SEEK_SET) == -1) {
204 WARN(("lseek text"));
205 return 1;
206 }
207
208 if (coff->a.tsize != 0) {
209 if (flags & LOAD_TEXT) {
210 PROGRESS(("%lu", coff->a.tsize));
211 if (READ(fd, coff->a.text_start, coff->a.tsize) !=
212 coff->a.tsize) {
213 return 1;
214 }
215 }
216 else {
217 if (lseek(fd, coff->a.tsize, SEEK_CUR) == -1) {
218 WARN(("read text"));
219 return 1;
220 }
221 }
222 if (flags & (COUNT_TEXT|LOAD_TEXT)) {
223 pos = coff->a.text_start;
224 if (minp > pos)
225 minp = pos;
226 pos += coff->a.tsize;
227 if (maxp < pos)
228 maxp = pos;
229 }
230 }
231
232 /* Read in data. */
233 if (coff->a.dsize != 0) {
234 if (flags & LOAD_DATA) {
235 PROGRESS(("+%lu", coff->a.dsize));
236 if (READ(fd, coff->a.data_start, coff->a.dsize) !=
237 coff->a.dsize) {
238 WARN(("read data"));
239 return 1;
240 }
241 }
242 if (flags & (COUNT_DATA|LOAD_DATA)) {
243 pos = coff->a.data_start;
244 if (minp > pos)
245 minp = pos;
246 pos += coff->a.dsize;
247 if (maxp < pos)
248 maxp = pos;
249 }
250 }
251
252 /* Zero out bss. */
253 if (coff->a.bsize != 0) {
254 if (flags & LOAD_BSS) {
255 PROGRESS(("+%lu", coff->a.bsize));
256 BZERO(coff->a.bss_start, coff->a.bsize);
257 }
258 if (flags & (COUNT_BSS|LOAD_BSS)) {
259 pos = coff->a.bss_start;
260 if (minp > pos)
261 minp = pos;
262 pos = coff->a.bsize;
263 if (maxp < pos)
264 maxp = pos;
265 }
266 }
267
268 marks[MARK_START] = LOADADDR(minp);
269 marks[MARK_ENTRY] = LOADADDR(coff->a.entry);
270 marks[MARK_NSYM] = 1; /* XXX: Kernel needs >= 0 */
271 marks[MARK_SYM] = LOADADDR(maxp);
272 marks[MARK_END] = LOADADDR(maxp);
273 return 0;
274 }
275 #endif /* BOOT_ECOFF */
276
277 #ifdef BOOT_AOUT
278 static int
279 aout_exec(int fd, struct exec *x, u_long *marks, int flags)
280 {
281 u_long entry = x->a_entry;
282 paddr_t aoutp = 0;
283 paddr_t minp, maxp;
284 int cc;
285 paddr_t offset = marks[MARK_START];
286 u_long magic = N_GETMAGIC(*x);
287 int sub;
288
289 /* In OMAGIC and NMAGIC, exec header isn't part of text segment */
290 if (magic == OMAGIC || magic == NMAGIC)
291 sub = 0;
292 else
293 sub = sizeof(*x);
294
295 minp = maxp = ALIGNENTRY(entry);
296
297 if (lseek(fd, sizeof(*x), SEEK_SET) == -1) {
298 WARN(("lseek text"));
299 return 1;
300 }
301
302 /*
303 * Leave a copy of the exec header before the text.
304 * The kernel may use this to verify that the
305 * symbols were loaded by this boot program.
306 */
307 if (magic == OMAGIC || magic == NMAGIC) {
308 if (flags & LOAD_HDR && maxp >= sizeof(*x))
309 BCOPY(x, maxp - sizeof(*x), sizeof(*x));
310 }
311 else {
312 if (flags & LOAD_HDR)
313 BCOPY(x, maxp, sizeof(*x));
314 if (flags & (LOAD_HDR|COUNT_HDR))
315 maxp += sizeof(*x);
316 }
317
318 /*
319 * Read in the text segment.
320 */
321 if (flags & LOAD_TEXT) {
322 PROGRESS(("%ld", x->a_text));
323
324 if (READ(fd, maxp, x->a_text - sub) != x->a_text - sub) {
325 WARN(("read text"));
326 return 1;
327 }
328 } else {
329 if (lseek(fd, x->a_text - sub, SEEK_CUR) == -1) {
330 WARN(("seek text"));
331 return 1;
332 }
333 }
334 if (flags & (LOAD_TEXT|COUNT_TEXT))
335 maxp += x->a_text - sub;
336
337 /*
338 * Provide alignment if required
339 */
340 if (magic == ZMAGIC || magic == NMAGIC) {
341 int size = -(unsigned int)maxp & (__LDPGSZ - 1);
342
343 if (flags & LOAD_TEXTA) {
344 PROGRESS(("/%d", size));
345 BZERO(maxp, size);
346 }
347
348 if (flags & (LOAD_TEXTA|COUNT_TEXTA))
349 maxp += size;
350 }
351
352 /*
353 * Read in the data segment.
354 */
355 if (flags & LOAD_DATA) {
356 PROGRESS(("+%ld", x->a_data));
357
358 if (READ(fd, maxp, x->a_data) != x->a_data) {
359 WARN(("read data"));
360 return 1;
361 }
362 }
363 else {
364 if (lseek(fd, x->a_data, SEEK_CUR) == -1) {
365 WARN(("seek data"));
366 return 1;
367 }
368 }
369 if (flags & (LOAD_DATA|COUNT_DATA))
370 maxp += x->a_data;
371
372 /*
373 * Zero out the BSS section.
374 * (Kernel doesn't care, but do it anyway.)
375 */
376 if (flags & LOAD_BSS) {
377 PROGRESS(("+%ld", x->a_bss));
378
379 BZERO(maxp, x->a_bss);
380 }
381
382 if (flags & (LOAD_BSS|COUNT_BSS))
383 maxp += x->a_bss;
384
385 /*
386 * Read in the symbol table and strings.
387 * (Always set the symtab size word.)
388 */
389 if (flags & LOAD_SYM)
390 BCOPY(&x->a_syms, maxp, sizeof(x->a_syms));
391
392 if (flags & (LOAD_SYM|COUNT_SYM)) {
393 maxp += sizeof(x->a_syms);
394 aoutp = maxp;
395 }
396
397 if (x->a_syms > 0) {
398 /* Symbol table and string table length word. */
399
400 if (flags & LOAD_SYM) {
401 PROGRESS(("+[%ld", x->a_syms));
402
403 if (READ(fd, maxp, x->a_syms) != x->a_syms) {
404 WARN(("read symbols"));
405 return 1;
406 }
407 } else {
408 if (lseek(fd, x->a_syms, SEEK_CUR) == -1) {
409 WARN(("seek symbols"));
410 return 1;
411 }
412 }
413 if (flags & (LOAD_SYM|COUNT_SYM))
414 maxp += x->a_syms;
415
416 if (read(fd, &cc, sizeof(cc)) != sizeof(cc)) {
417 WARN(("read string table"));
418 return 1;
419 }
420
421 if (flags & LOAD_SYM) {
422 BCOPY(&cc, maxp, sizeof(cc));
423
424 /* String table. Length word includes itself. */
425
426 PROGRESS(("+%d]", cc));
427 }
428 if (flags & (LOAD_SYM|COUNT_SYM))
429 maxp += sizeof(cc);
430
431 cc -= sizeof(int);
432 if (cc <= 0) {
433 WARN(("symbol table too short"));
434 return 1;
435 }
436
437 if (flags & LOAD_SYM) {
438 if (READ(fd, maxp, cc) != cc) {
439 WARN(("read strings"));
440 return 1;
441 }
442 } else {
443 if (lseek(fd, cc, SEEK_CUR) == -1) {
444 WARN(("seek strings"));
445 return 1;
446 }
447 }
448 if (flags & (LOAD_SYM|COUNT_SYM))
449 maxp += cc;
450 }
451
452 marks[MARK_START] = LOADADDR(minp);
453 marks[MARK_ENTRY] = LOADADDR(entry);
454 marks[MARK_NSYM] = x->a_syms;
455 marks[MARK_SYM] = LOADADDR(aoutp);
456 marks[MARK_END] = LOADADDR(maxp);
457 return 0;
458 }
459 #endif /* BOOT_AOUT */