1 1.5 gutterid /* $NetBSD: mkboot.c,v 1.5 2024/10/31 01:21:12 gutteridge Exp $ */ 2 1.1 skrll 3 1.1 skrll /* $OpenBSD: mkboot.c,v 1.9 2001/05/17 00:57:55 pvalchev Exp $ */ 4 1.1 skrll 5 1.1 skrll /* 6 1.1 skrll * Copyright (c) 1990, 1993 7 1.1 skrll * The Regents of the University of California. All rights reserved. 8 1.1 skrll * 9 1.1 skrll * Redistribution and use in source and binary forms, with or without 10 1.1 skrll * modification, are permitted provided that the following conditions 11 1.1 skrll * are met: 12 1.1 skrll * 1. Redistributions of source code must retain the above copyright 13 1.1 skrll * notice, this list of conditions and the following disclaimer. 14 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 skrll * notice, this list of conditions and the following disclaimer in the 16 1.1 skrll * documentation and/or other materials provided with the distribution. 17 1.1 skrll * 3. Neither the name of the University nor the names of its contributors 18 1.1 skrll * may be used to endorse or promote products derived from this software 19 1.1 skrll * without specific prior written permission. 20 1.1 skrll * 21 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 1.1 skrll * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 skrll * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 skrll * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 1.1 skrll * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 skrll * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 skrll * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 skrll * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 skrll * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 skrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 skrll * SUCH DAMAGE. 32 1.1 skrll * 33 1.1 skrll * @(#)mkboot.c 8.1 (Berkeley) 7/15/93 34 1.1 skrll */ 35 1.1 skrll 36 1.1 skrll #if 0 37 1.1 skrll #ifndef lint 38 1.1 skrll static char copyright[] = 39 1.1 skrll "@(#) Copyright (c) 1990, 1993\n\ 40 1.1 skrll The Regents of the University of California. All rights reserved.\n"; 41 1.1 skrll #endif /* not lint */ 42 1.1 skrll 43 1.1 skrll #ifndef lint 44 1.1 skrll static char rcsid[] = "$OpenBSD: mkboot.c,v 1.9 2001/05/17 00:57:55 pvalchev Exp $"; 45 1.1 skrll #endif /* not lint */ 46 1.1 skrll #endif 47 1.1 skrll 48 1.1 skrll #if HAVE_NBTOOL_CONFIG_H 49 1.1 skrll #include "nbtool_config.h" 50 1.1 skrll #include "../../sys/sys/bootblock.h" 51 1.1 skrll #else 52 1.1 skrll #include <sys/bootblock.h> 53 1.1 skrll #endif 54 1.1 skrll 55 1.1 skrll #include <sys/param.h> 56 1.5 gutterid #include <sys/endian.h> 57 1.1 skrll #include <sys/file.h> 58 1.1 skrll #include <sys/stat.h> 59 1.1 skrll #include <string.h> 60 1.1 skrll #include <stdlib.h> 61 1.1 skrll #include <unistd.h> 62 1.1 skrll #include <time.h> 63 1.1 skrll #include <err.h> 64 1.1 skrll 65 1.1 skrll /* BFD ELF headers */ 66 1.1 skrll #include <elf/common.h> 67 1.1 skrll #include <elf/external.h> 68 1.1 skrll 69 1.1 skrll #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ 70 1.1 skrll (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ 71 1.1 skrll (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ 72 1.1 skrll (ehdr).e_ident[EI_MAG3] == ELFMAG3) 73 1.1 skrll 74 1.1 skrll /* 75 1.1 skrll * Macros to get values from multi-byte ELF header fields. These assume 76 1.1 skrll * a big-endian image. 77 1.1 skrll */ 78 1.1 skrll #define ELFGET16(x) (((x)[0] << 8) | (x)[1]) 79 1.1 skrll 80 1.1 skrll #define ELFGET32(x) (((x)[0] << 24) | ((x)[1] << 16) | \ 81 1.1 skrll ((x)[2] << 8) | (x)[3]) 82 1.1 skrll 83 1.1 skrll /* 84 1.1 skrll * Header prepended to each a.out file. 85 1.1 skrll */ 86 1.1 skrll struct exec { 87 1.5 gutterid u_long a_midmag; /* htobe32(flags<<26 | mid<<16 | magic) */ 88 1.1 skrll u_long a_text; /* text segment size */ 89 1.1 skrll u_long a_data; /* initialized data size */ 90 1.1 skrll u_long a_bss; /* uninitialized data size */ 91 1.1 skrll u_long a_syms; /* symbol table size */ 92 1.1 skrll u_long a_entry; /* entry point */ 93 1.1 skrll u_long a_trsize; /* text relocation size */ 94 1.1 skrll u_long a_drsize; /* data relocation size */ 95 1.1 skrll }; 96 1.1 skrll 97 1.1 skrll /* a_magic */ 98 1.1 skrll #define OMAGIC 0407 /* old impure format */ 99 1.1 skrll #define NMAGIC 0410 /* read-only text */ 100 1.1 skrll #define ZMAGIC 0413 /* demand load format */ 101 1.1 skrll #define QMAGIC 0314 /* "compact" demand load format; deprecated */ 102 1.1 skrll 103 1.1 skrll #define N_GETMAGIC(ex) \ 104 1.1 skrll ((((ex).a_midmag)&0xffff0000) ? \ 105 1.5 gutterid (be32toh((uint32_t)((ex).a_midmag))&0xffff) : ((ex).a_midmag)) 106 1.1 skrll 107 1.1 skrll #include <stdio.h> 108 1.1 skrll #include <ctype.h> 109 1.1 skrll 110 1.1 skrll int putfile(char *, int); 111 1.1 skrll void __dead usage(void); 112 1.1 skrll void bcddate(char *, char *); 113 1.1 skrll char *lifname(char *); 114 1.1 skrll int cksum(int, int *, int); 115 1.1 skrll 116 1.1 skrll char *to_file; 117 1.1 skrll int loadpoint, verbose; 118 1.1 skrll u_long entry; 119 1.3 christos time_t repro_epoch = 0; 120 1.1 skrll 121 1.1 skrll /* 122 1.1 skrll * Old Format: 123 1.1 skrll * sector 0: LIF volume header (40 bytes) 124 1.1 skrll * sector 1: <unused> 125 1.1 skrll * sector 2: LIF directory (8 x 32 == 256 bytes) 126 1.1 skrll * sector 3-: LIF file 0, LIF file 1, etc. 127 1.1 skrll * where sectors are 256 bytes. 128 1.1 skrll * 129 1.1 skrll * New Format: 130 1.1 skrll * sector 0: LIF volume header (40 bytes) 131 1.1 skrll * sector 1: <unused> 132 1.1 skrll * sector 2: LIF directory (8 x 32 == 256 bytes) 133 1.1 skrll * sector 3: <unused> 134 1.1 skrll * sector 4-31: disklabel (~300 bytes right now) 135 1.1 skrll * sector 32-: LIF file 0, LIF file 1, etc. 136 1.1 skrll */ 137 1.1 skrll int 138 1.1 skrll main(int argc, char **argv) 139 1.1 skrll { 140 1.1 skrll int to, n, pos, c; 141 1.1 skrll char buf[HPPA_LIF_FILESTART]; 142 1.1 skrll struct hppa_lifvol *lifv = (struct hppa_lifvol *)buf; 143 1.1 skrll struct hppa_lifdir *lifd = (struct hppa_lifdir *)(buf + HPPA_LIF_DIRSTART); 144 1.1 skrll 145 1.3 christos while ((c = getopt(argc, argv, "l:t:v")) != -1) { 146 1.1 skrll switch (c) { 147 1.3 christos case 'l': 148 1.3 christos loadpoint = strtol(optarg, NULL, 0); 149 1.3 christos break; 150 1.3 christos case 't': 151 1.3 christos repro_epoch = atoll(optarg); 152 1.3 christos break; 153 1.1 skrll case 'v': 154 1.1 skrll verbose++; 155 1.1 skrll break; 156 1.1 skrll default: 157 1.1 skrll usage(); 158 1.1 skrll } 159 1.1 skrll } 160 1.1 skrll if (argc - optind < 2) 161 1.1 skrll usage(); 162 1.1 skrll else if (argc - optind > 8) 163 1.1 skrll errx(1, "too many boot programs (max 8 supported)"); 164 1.1 skrll 165 1.1 skrll to_file = argv[--argc]; 166 1.1 skrll if ((to = open(to_file, O_RDWR | O_TRUNC | O_CREAT, 0644)) < 0) 167 1.1 skrll err(1, "%s: open", to_file); 168 1.1 skrll 169 1.1 skrll memset(buf, 0, sizeof(buf)); 170 1.1 skrll 171 1.1 skrll /* record volume info */ 172 1.1 skrll lifv->vol_id = htobe16(HPPA_LIF_VOL_ID); 173 1.1 skrll strncpy(lifv->vol_label, "MKBOOT", 6); 174 1.1 skrll lifv->vol_addr = htobe32(hppa_btolifs(HPPA_LIF_DIRSTART)); 175 1.1 skrll lifv->vol_oct = htobe16(HPPA_LIF_VOL_OCT); 176 1.1 skrll lifv->vol_dirsize = htobe32(hppa_btolifs(HPPA_LIF_DIRSIZE)); 177 1.1 skrll lifv->vol_version = htobe16(1); 178 1.1 skrll lifv->vol_number = htobe32(1); 179 1.1 skrll lifv->vol_lastvol = htobe32(1); 180 1.1 skrll lifv->vol_length = HPPA_LIF_FILESTART; /* ... so far. */ 181 1.1 skrll bcddate(to_file, lifv->vol_toc); 182 1.1 skrll lifv->ipl_addr = htobe32(HPPA_LIF_FILESTART); 183 1.1 skrll 184 1.1 skrll argv += optind; 185 1.1 skrll argc -= optind; 186 1.1 skrll optind = 0; 187 1.1 skrll for (pos = HPPA_LIF_FILESTART; optind < argc; optind++) { 188 1.1 skrll 189 1.1 skrll /* output bootfile */ 190 1.1 skrll if (lseek(to, pos, SEEK_SET) < 0) 191 1.1 skrll err(1, "%s: lseek", to_file); 192 1.1 skrll lifd[optind].dir_addr = htobe32(hppa_btolifs(pos)); 193 1.1 skrll n = hppa_btolifs(putfile(argv[optind], to)); 194 1.1 skrll if (lifv->ipl_entry == 0) { 195 1.1 skrll lifv->ipl_entry = htobe32(loadpoint + entry); 196 1.1 skrll lifv->ipl_size = htobe32(hppa_lifstob(n)); 197 1.1 skrll lifd[optind].dir_type = htobe16(HPPA_LIF_DIR_ISL); 198 1.1 skrll lifd[optind].dir_implement = 0; 199 1.1 skrll } else { 200 1.1 skrll lifd[optind].dir_type = htobe16(HPPA_LIF_DIR_TYPE); 201 1.1 skrll lifd[optind].dir_implement = htobe32(loadpoint + entry); 202 1.1 skrll } 203 1.1 skrll 204 1.1 skrll memcpy(lifd[optind].dir_name, lifname(argv[optind]), 205 1.1 skrll sizeof(lifd[optind].dir_name)); 206 1.1 skrll lifd[optind].dir_length = htobe32(n); 207 1.1 skrll bcddate(argv[optind], lifd[optind].dir_toc); 208 1.1 skrll lifd[optind].dir_flag = htobe16(HPPA_LIF_DIR_FLAG); 209 1.1 skrll 210 1.1 skrll lifv->vol_length += n; 211 1.1 skrll pos += hppa_lifstob(n); 212 1.1 skrll } 213 1.1 skrll 214 1.1 skrll /* terminate the directory */ 215 1.1 skrll lifd[optind].dir_type = htobe16(0xffff); 216 1.1 skrll 217 1.1 skrll /* byte-swap the length now that we're done computing it */ 218 1.1 skrll lifv->vol_length = htobe32(lifv->vol_length); 219 1.1 skrll 220 1.1 skrll /* output volume/directory header info */ 221 1.1 skrll if (lseek(to, HPPA_LIF_VOLSTART, SEEK_SET) < 0) 222 1.1 skrll err(1, "%s: lseek", to_file); 223 1.1 skrll if (write(to, buf, sizeof(buf)) != sizeof(buf)) 224 1.1 skrll err(1, "%s: write LIF volume", to_file); 225 1.1 skrll lseek(to, 0, SEEK_END); 226 1.1 skrll 227 1.1 skrll if (close(to) < 0) 228 1.1 skrll err(1, "%s", to_file); 229 1.1 skrll 230 1.1 skrll return(0); 231 1.1 skrll } 232 1.1 skrll 233 1.1 skrll int 234 1.1 skrll putfile(char *from_file, int to) 235 1.1 skrll { 236 1.1 skrll struct exec ex; 237 1.1 skrll char buf[2048]; 238 1.1 skrll int n, total; 239 1.1 skrll int from, check_sum = 0; 240 1.1 skrll struct hppa_lifload load; 241 1.1 skrll Elf32_External_Ehdr elf_header; 242 1.2 christos Elf32_External_Phdr *elf_segments = NULL; 243 1.1 skrll int i, header_count, memory_needed, elf_load_image_segment; 244 1.1 skrll 245 1.1 skrll if ((from = open(from_file, O_RDONLY)) < 0) 246 1.1 skrll err(1, "%s", from_file); 247 1.1 skrll 248 1.1 skrll n = read(from, &ex, sizeof(ex)); 249 1.1 skrll if (n != sizeof(ex)) 250 1.1 skrll err(1, "%s: reading file header", from_file); 251 1.1 skrll 252 1.1 skrll entry = ex.a_entry; 253 1.1 skrll if (N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC) 254 1.1 skrll entry += sizeof(ex); 255 1.1 skrll else if (IS_ELF(*(Elf32_External_Ehdr *)&ex)) { 256 1.1 skrll 257 1.1 skrll if (lseek(from, 0, SEEK_SET) < 0) 258 1.1 skrll err(1, "lseek"); 259 1.1 skrll n = read(from, &elf_header, sizeof (elf_header)); 260 1.1 skrll if (n != sizeof (elf_header)) 261 1.1 skrll err(1, "%s: reading ELF header", from_file); 262 1.1 skrll header_count = ELFGET16(elf_header.e_phnum); 263 1.1 skrll memory_needed = header_count * sizeof (Elf32_External_Phdr); 264 1.1 skrll elf_segments = malloc(memory_needed); 265 1.1 skrll if (elf_segments == NULL) 266 1.1 skrll err(1, "malloc"); 267 1.1 skrll if (lseek(from, ELFGET32(elf_header.e_phoff), SEEK_SET) < 0) 268 1.1 skrll err(1, "lseek"); 269 1.1 skrll n = read(from, elf_segments, memory_needed); 270 1.1 skrll if (n != memory_needed) 271 1.1 skrll err(1, "%s: reading ELF segments", from_file); 272 1.1 skrll elf_load_image_segment = -1; 273 1.1 skrll for (i = 0; i < header_count; i++) { 274 1.1 skrll if (ELFGET32(elf_segments[i].p_filesz) && 275 1.1 skrll ELFGET32(elf_segments[i].p_flags) & PF_X) { 276 1.1 skrll if (elf_load_image_segment != -1) 277 1.1 skrll errx(1, "%s: more than one ELF program " 278 1.1 skrll "segment", from_file); 279 1.1 skrll elf_load_image_segment = i; 280 1.1 skrll } 281 1.1 skrll } 282 1.1 skrll if (elf_load_image_segment == -1) 283 1.1 skrll errx(1, "%s: no suitable ELF program segment", 284 1.1 skrll from_file); 285 1.1 skrll entry = ELFGET32(elf_header.e_entry) + 286 1.1 skrll ELFGET32(elf_segments[elf_load_image_segment].p_offset) - 287 1.1 skrll ELFGET32(elf_segments[elf_load_image_segment].p_vaddr); 288 1.1 skrll } else if (*(uint8_t *)&ex == 0x1f && ((uint8_t *)&ex)[1] == 0x8b) { 289 1.1 skrll entry = 0; 290 1.1 skrll } else 291 1.1 skrll errx(1, "%s: bad magic number", from_file); 292 1.1 skrll 293 1.1 skrll entry += sizeof(load); 294 1.1 skrll lseek(to, sizeof(load), SEEK_CUR); 295 1.1 skrll 296 1.1 skrll total = 0; 297 1.1 skrll n = sizeof(buf) - sizeof(load); 298 1.1 skrll /* copy the whole file */ 299 1.1 skrll for (lseek(from, 0, SEEK_SET); ; n = sizeof(buf)) { 300 1.1 skrll memset(buf, 0, sizeof(buf)); 301 1.1 skrll if ((n = read(from, buf, n)) < 0) 302 1.1 skrll err(1, "%s", from_file); 303 1.1 skrll else if (n == 0) 304 1.1 skrll break; 305 1.1 skrll 306 1.1 skrll if (write(to, buf, n) != n) 307 1.1 skrll err(1, "%s", to_file); 308 1.1 skrll 309 1.1 skrll total += n; 310 1.1 skrll check_sum = cksum(check_sum, (int *)buf, n); 311 1.1 skrll } 312 1.1 skrll 313 1.1 skrll /* load header */ 314 1.1 skrll load.address = htobe32(loadpoint + sizeof(load)); 315 1.1 skrll load.count = htobe32(4 + total); 316 1.1 skrll check_sum = cksum(check_sum, (int *)&load, sizeof(load)); 317 1.1 skrll 318 1.1 skrll if (verbose) 319 1.1 skrll warnx("wrote %d bytes of file \'%s\'", total, from_file); 320 1.1 skrll 321 1.1 skrll total += sizeof(load); 322 1.1 skrll /* insert the header */ 323 1.1 skrll lseek(to, -total, SEEK_CUR); 324 1.1 skrll if (write(to, &load, sizeof(load)) != sizeof(load)) 325 1.1 skrll err(1, "%s", to_file); 326 1.1 skrll lseek(to, total - sizeof(load), SEEK_CUR); 327 1.1 skrll 328 1.1 skrll memset(buf, 0, sizeof(buf)); 329 1.1 skrll /* pad to int */ 330 1.1 skrll n = sizeof(int) - total % sizeof(int); 331 1.1 skrll if (total % sizeof(int)) { 332 1.1 skrll if (write(to, buf, n) != n) 333 1.1 skrll err(1, "%s", to_file); 334 1.1 skrll else 335 1.1 skrll total += n; 336 1.1 skrll } 337 1.1 skrll 338 1.1 skrll /* pad to the blocksize */ 339 1.1 skrll n = sizeof(buf) - total % sizeof(buf); 340 1.1 skrll 341 1.1 skrll if (n < sizeof(int)) { 342 1.1 skrll n += sizeof(buf); 343 1.1 skrll total += sizeof(buf); 344 1.1 skrll } else 345 1.1 skrll total += n; 346 1.1 skrll 347 1.1 skrll /* TODO should pad here to the 65k boundary for tape boot */ 348 1.1 skrll 349 1.1 skrll if (verbose) 350 1.1 skrll warnx("checksum is 0x%08x", -check_sum); 351 1.1 skrll 352 1.1 skrll check_sum = htobe32(-check_sum); 353 1.1 skrll if (write(to, &check_sum, sizeof(int)) != sizeof(int)) 354 1.1 skrll err(1, "%s", to_file); 355 1.1 skrll 356 1.1 skrll n -= sizeof(int); 357 1.1 skrll 358 1.1 skrll if (write(to, buf, n) != n) 359 1.1 skrll err(1, "%s", to_file); 360 1.1 skrll 361 1.1 skrll if (close(from) < 0) 362 1.1 skrll err(1, "%s", from_file); 363 1.1 skrll 364 1.2 christos free(elf_segments); 365 1.1 skrll return total; 366 1.1 skrll } 367 1.1 skrll 368 1.1 skrll int 369 1.1 skrll cksum(int ck, int *p, int size) 370 1.1 skrll { 371 1.1 skrll /* we assume size is int-aligned */ 372 1.1 skrll for (size = (size + sizeof(int) - 1) / sizeof(int); size--; p++ ) 373 1.1 skrll ck += be32toh(*p); 374 1.1 skrll 375 1.1 skrll return ck; 376 1.1 skrll } 377 1.1 skrll 378 1.1 skrll void __dead 379 1.1 skrll usage(void) 380 1.1 skrll { 381 1.1 skrll fprintf(stderr, 382 1.3 christos "Usage: %s [-v] [-l <loadpoint>] [-t <timestamp>] prog1 {progN} outfile\n", 383 1.3 christos getprogname()); 384 1.1 skrll exit(1); 385 1.1 skrll } 386 1.1 skrll 387 1.1 skrll char * 388 1.1 skrll lifname(char *str) 389 1.1 skrll { 390 1.1 skrll static char lname[10] = "XXXXXXXXXX"; 391 1.1 skrll char *cp; 392 1.1 skrll int i; 393 1.1 skrll 394 1.1 skrll cp = strrchr(str, '/'); 395 1.1 skrll if (cp != NULL) { 396 1.1 skrll str = cp + 1; 397 1.1 skrll } 398 1.1 skrll for (i = 0; i < 9; i++) { 399 1.1 skrll if (islower(*str)) 400 1.1 skrll lname[i] = toupper(*str); 401 1.1 skrll else if (isalnum(*str) || *str == '_') 402 1.1 skrll lname[i] = *str; 403 1.1 skrll else 404 1.1 skrll break; 405 1.1 skrll str++; 406 1.1 skrll } 407 1.1 skrll for ( ; i < 10; i++) 408 1.1 skrll lname[i] = ' '; 409 1.1 skrll return(lname); 410 1.1 skrll } 411 1.1 skrll 412 1.1 skrll 413 1.1 skrll void 414 1.1 skrll bcddate(char *file, char *toc) 415 1.1 skrll { 416 1.1 skrll struct stat statb; 417 1.1 skrll struct tm *tm; 418 1.1 skrll 419 1.3 christos if (repro_epoch) 420 1.3 christos tm = gmtime(&repro_epoch); 421 1.3 christos else { 422 1.3 christos stat(file, &statb); 423 1.3 christos tm = localtime(&statb.st_ctime); 424 1.3 christos } 425 1.1 skrll tm->tm_year %= 100; 426 1.1 skrll *toc = (tm->tm_year / 10) << 4; 427 1.1 skrll *toc++ |= tm->tm_year % 10; 428 1.1 skrll *toc = ((tm->tm_mon+1) / 10) << 4; 429 1.1 skrll *toc++ |= (tm->tm_mon+1) % 10; 430 1.1 skrll *toc = (tm->tm_mday / 10) << 4; 431 1.1 skrll *toc++ |= tm->tm_mday % 10; 432 1.1 skrll *toc = (tm->tm_hour / 10) << 4; 433 1.1 skrll *toc++ |= tm->tm_hour % 10; 434 1.1 skrll *toc = (tm->tm_min / 10) << 4; 435 1.1 skrll *toc++ |= tm->tm_min % 10; 436 1.1 skrll *toc = (tm->tm_sec / 10) << 4; 437 1.1 skrll *toc |= tm->tm_sec % 10; 438 1.1 skrll } 439