1 /* $NetBSD: mkboot.c,v 1.6 2005/12/11 12:17:25 christos Exp $ */
3 /* $OpenBSD: mkboot.c,v 1.9 2001/05/17 00:57:55 pvalchev Exp $ */
6 * Copyright (c) 1990, 1993
7 * The Regents of the University of California. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)mkboot.c 8.1 (Berkeley) 7/15/93
38 static char copyright
[] =
39 "@(#) Copyright (c) 1990, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
44 static char rcsid
[] = "$OpenBSD: mkboot.c,v 1.9 2001/05/17 00:57:55 pvalchev Exp $";
48 #if HAVE_NBTOOL_CONFIG_H
49 #include "nbtool_config.h"
50 #include "../../sys/sys/bootblock.h"
52 #include <sys/bootblock.h>
55 #include <sys/param.h>
65 #include <elf/common.h>
66 #include <elf/external.h>
68 #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
69 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
70 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
71 (ehdr).e_ident[EI_MAG3] == ELFMAG3)
74 * Macros to get values from multi-byte ELF header fields. These assume
77 #define ELFGET16(x) (((x)[0] << 8) | (x)[1])
79 #define ELFGET32(x) (((x)[0] << 24) | ((x)[1] << 16) | \
80 ((x)[2] << 8) | (x)[3])
83 * Header prepended to each a.out file.
86 u_long a_midmag
; /* htonl(flags<<26 | mid<<16 | magic) */
87 u_long a_text
; /* text segment size */
88 u_long a_data
; /* initialized data size */
89 u_long a_bss
; /* uninitialized data size */
90 u_long a_syms
; /* symbol table size */
91 u_long a_entry
; /* entry point */
92 u_long a_trsize
; /* text relocation size */
93 u_long a_drsize
; /* data relocation size */
97 #define OMAGIC 0407 /* old impure format */
98 #define NMAGIC 0410 /* read-only text */
99 #define ZMAGIC 0413 /* demand load format */
100 #define QMAGIC 0314 /* "compact" demand load format; deprecated */
102 #define N_GETMAGIC(ex) \
103 ((((ex).a_midmag)&0xffff0000) ? \
104 (ntohl((u_int32_t)((ex).a_midmag))&0xffff) : ((ex).a_midmag))
109 int putfile(char *, int);
110 void __dead
usage(void);
111 void bcddate(char *, char *);
112 char *lifname(char *);
113 int cksum(int, int *, int);
116 int loadpoint
, verbose
;
121 * sector 0: LIF volume header (40 bytes)
123 * sector 2: LIF directory (8 x 32 == 256 bytes)
124 * sector 3-: LIF file 0, LIF file 1, etc.
125 * where sectors are 256 bytes.
128 * sector 0: LIF volume header (40 bytes)
130 * sector 2: LIF directory (8 x 32 == 256 bytes)
132 * sector 4-31: disklabel (~300 bytes right now)
133 * sector 32-: LIF file 0, LIF file 1, etc.
136 main(int argc
, char **argv
)
139 char buf
[HP700_LIF_FILESTART
];
140 struct hp700_lifvol
*lifv
= (struct hp700_lifvol
*)buf
;
141 struct hp700_lifdir
*lifd
= (struct hp700_lifdir
*)(buf
+ HP700_LIF_DIRSTART
);
143 while ((c
= getopt(argc
, argv
, "vl:")) != -1) {
149 sscanf(optarg
, "0x%x", &loadpoint
);
155 if (argc
- optind
< 2)
157 else if (argc
- optind
> 8)
158 errx(1, "too many boot programs (max 8 supported)");
160 to_file
= argv
[--argc
];
161 if ((to
= open(to_file
, O_RDWR
| O_TRUNC
| O_CREAT
, 0644)) < 0)
162 err(1, "%s: open", to_file
);
164 memset(buf
, 0, sizeof(buf
));
166 /* record volume info */
167 lifv
->vol_id
= htobe16(HP700_LIF_VOL_ID
);
168 strncpy(lifv
->vol_label
, "MKBOOT", 6);
169 lifv
->vol_addr
= htobe32(hp700_btolifs(HP700_LIF_DIRSTART
));
170 lifv
->vol_oct
= htobe16(HP700_LIF_VOL_OCT
);
171 lifv
->vol_dirsize
= htobe32(hp700_btolifs(HP700_LIF_DIRSIZE
));
172 lifv
->vol_version
= htobe16(1);
173 lifv
->vol_number
= htobe32(1);
174 lifv
->vol_lastvol
= htobe32(1);
175 lifv
->vol_length
= HP700_LIF_FILESTART
; /* ... so far. */
176 bcddate(to_file
, lifv
->vol_toc
);
177 lifv
->ipl_addr
= htobe32(HP700_LIF_FILESTART
);
182 for (pos
= HP700_LIF_FILESTART
; optind
< argc
; optind
++) {
184 /* output bootfile */
185 if (lseek(to
, pos
, SEEK_SET
) < 0)
186 err(1, "%s: lseek", to_file
);
187 lifd
[optind
].dir_addr
= htobe32(hp700_btolifs(pos
));
188 n
= hp700_btolifs(putfile(argv
[optind
], to
));
189 if (lifv
->ipl_entry
== 0) {
190 lifv
->ipl_entry
= htobe32(loadpoint
+ entry
);
191 lifv
->ipl_size
= htobe32(hp700_lifstob(n
));
192 lifd
[optind
].dir_type
= htobe16(HP700_LIF_DIR_ISL
);
193 lifd
[optind
].dir_implement
= 0;
195 lifd
[optind
].dir_type
= htobe16(HP700_LIF_DIR_TYPE
);
196 lifd
[optind
].dir_implement
= htobe32(loadpoint
+ entry
);
199 memcpy(lifd
[optind
].dir_name
, lifname(argv
[optind
]),
200 sizeof(lifd
[optind
].dir_name
));
201 lifd
[optind
].dir_length
= htobe32(n
);
202 bcddate(argv
[optind
], lifd
[optind
].dir_toc
);
203 lifd
[optind
].dir_flag
= htobe16(HP700_LIF_DIR_FLAG
);
205 lifv
->vol_length
+= n
;
206 pos
+= hp700_lifstob(n
);
209 /* terminate the directory */
210 lifd
[optind
].dir_type
= htobe16(0xffff);
212 /* byte-swap the length now that we're done computing it */
213 lifv
->vol_length
= htobe32(lifv
->vol_length
);
215 /* output volume/directory header info */
216 if (lseek(to
, HP700_LIF_VOLSTART
, SEEK_SET
) < 0)
217 err(1, "%s: lseek", to_file
);
218 if (write(to
, buf
, sizeof(buf
)) != sizeof(buf
))
219 err(1, "%s: write LIF volume", to_file
);
220 lseek(to
, 0, SEEK_END
);
223 err(1, "%s", to_file
);
229 putfile(char *from_file
, int to
)
234 int from
, check_sum
= 0;
235 struct hp700_lifload load
;
236 Elf32_External_Ehdr elf_header
;
237 Elf32_External_Phdr
*elf_segments
;
238 int i
, header_count
, memory_needed
, elf_load_image_segment
;
240 if ((from
= open(from_file
, O_RDONLY
)) < 0)
241 err(1, "%s", from_file
);
243 n
= read(from
, &ex
, sizeof(ex
));
245 err(1, "%s: reading file header", from_file
);
248 if (N_GETMAGIC(ex
) == OMAGIC
|| N_GETMAGIC(ex
) == NMAGIC
)
250 else if (IS_ELF(*(Elf32_External_Ehdr
*)&ex
)) {
252 if (lseek(from
, 0, SEEK_SET
) < 0)
254 n
= read(from
, &elf_header
, sizeof (elf_header
));
255 if (n
!= sizeof (elf_header
))
256 err(1, "%s: reading ELF header", from_file
);
257 header_count
= ELFGET16(elf_header
.e_phnum
);
258 memory_needed
= header_count
* sizeof (Elf32_External_Phdr
);
259 elf_segments
= malloc(memory_needed
);
260 if (elf_segments
== NULL
)
262 if (lseek(from
, ELFGET32(elf_header
.e_phoff
), SEEK_SET
) < 0)
264 n
= read(from
, elf_segments
, memory_needed
);
265 if (n
!= memory_needed
)
266 err(1, "%s: reading ELF segments", from_file
);
267 elf_load_image_segment
= -1;
268 for (i
= 0; i
< header_count
; i
++) {
269 if (ELFGET32(elf_segments
[i
].p_filesz
) &&
270 ELFGET32(elf_segments
[i
].p_flags
) & PF_X
) {
271 if (elf_load_image_segment
!= -1)
272 errx(1, "%s: more than one ELF program "
273 "segment", from_file
);
274 elf_load_image_segment
= i
;
277 if (elf_load_image_segment
== -1)
278 errx(1, "%s: no suitable ELF program segment",
280 entry
= ELFGET32(elf_header
.e_entry
) +
281 ELFGET32(elf_segments
[elf_load_image_segment
].p_offset
) -
282 ELFGET32(elf_segments
[elf_load_image_segment
].p_vaddr
);
283 } else if (*(uint8_t *)&ex
== 0x1f && ((uint8_t *)&ex
)[1] == 0x8b) {
286 errx(1, "%s: bad magic number", from_file
);
288 entry
+= sizeof(load
);
289 lseek(to
, sizeof(load
), SEEK_CUR
);
292 n
= sizeof(buf
) - sizeof(load
);
293 /* copy the whole file */
294 for (lseek(from
, 0, SEEK_SET
); ; n
= sizeof(buf
)) {
295 memset(buf
, 0, sizeof(buf
));
296 if ((n
= read(from
, buf
, n
)) < 0)
297 err(1, "%s", from_file
);
301 if (write(to
, buf
, n
) != n
)
302 err(1, "%s", to_file
);
305 check_sum
= cksum(check_sum
, (int *)buf
, n
);
309 load
.address
= htobe32(loadpoint
+ sizeof(load
));
310 load
.count
= htobe32(4 + total
);
311 check_sum
= cksum(check_sum
, (int *)&load
, sizeof(load
));
314 warnx("wrote %d bytes of file \'%s\'", total
, from_file
);
316 total
+= sizeof(load
);
317 /* insert the header */
318 lseek(to
, -total
, SEEK_CUR
);
319 if (write(to
, &load
, sizeof(load
)) != sizeof(load
))
320 err(1, "%s", to_file
);
321 lseek(to
, total
- sizeof(load
), SEEK_CUR
);
323 memset(buf
, 0, sizeof(buf
));
325 n
= sizeof(int) - total
% sizeof(int);
326 if (total
% sizeof(int)) {
327 if (write(to
, buf
, n
) != n
)
328 err(1, "%s", to_file
);
333 /* pad to the blocksize */
334 n
= sizeof(buf
) - total
% sizeof(buf
);
336 if (n
< sizeof(int)) {
338 total
+= sizeof(buf
);
342 /* TODO should pad here to the 65k boundary for tape boot */
345 warnx("checksum is 0x%08x", -check_sum
);
347 check_sum
= htobe32(-check_sum
);
348 if (write(to
, &check_sum
, sizeof(int)) != sizeof(int))
349 err(1, "%s", to_file
);
353 if (write(to
, buf
, n
) != n
)
354 err(1, "%s", to_file
);
357 err(1, "%s", from_file
);
363 cksum(int ck
, int *p
, int size
)
365 /* we assume size is int-aligned */
366 for (size
= (size
+ sizeof(int) - 1) / sizeof(int); size
--; p
++ )
376 "usage: %s [-v] [-l loadpoint] prog1 {progN} outfile\n",
384 static char lname
[10] = "XXXXXXXXXX";
388 cp
= strrchr(str
, '/');
392 for (i
= 0; i
< 9; i
++) {
394 lname
[i
] = toupper(*str
);
395 else if (isalnum(*str
) || *str
== '_')
408 bcddate(char *file
, char *toc
)
414 tm
= localtime(&statb
.st_ctime
);
416 *toc
= (tm
->tm_year
/ 10) << 4;
417 *toc
++ |= tm
->tm_year
% 10;
418 *toc
= ((tm
->tm_mon
+1) / 10) << 4;
419 *toc
++ |= (tm
->tm_mon
+1) % 10;
420 *toc
= (tm
->tm_mday
/ 10) << 4;
421 *toc
++ |= tm
->tm_mday
% 10;
422 *toc
= (tm
->tm_hour
/ 10) << 4;
423 *toc
++ |= tm
->tm_hour
% 10;
424 *toc
= (tm
->tm_min
/ 10) << 4;
425 *toc
++ |= tm
->tm_min
% 10;
426 *toc
= (tm
->tm_sec
/ 10) << 4;
427 *toc
|= tm
->tm_sec
% 10;