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