1 /* $OpenBSD: mkuboot.c,v 1.6 2015/10/12 06:24:28 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <err.h> 22 #include <fcntl.h> 23 #include <stdint.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <time.h> 28 #include <unistd.h> 29 #include <zlib.h> 30 #include <sys/exec_elf.h> 31 32 #define IH_OS_OPENBSD 1 /* OpenBSD */ 33 #define IH_OS_LINUX 5 /* Linux */ 34 35 #define IH_ARCH_ALPHA 1 /* Alpha */ 36 #define IH_ARCH_ARM 2 /* ARM */ 37 #define IH_ARCH_I386 3 /* Intel x86 */ 38 #define IH_ARCH_IA64 4 /* IA64 */ 39 #define IH_ARCH_MIPS 5 /* MIPS */ 40 #define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ 41 #define IH_ARCH_PPC 7 /* PowerPC */ 42 #define IH_ARCH_SH 9 /* SuperH */ 43 #define IH_ARCH_SPARC 10 /* Sparc */ 44 #define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ 45 #define IH_ARCH_M68K 12 /* M68K */ 46 47 #define IH_TYPE_STANDALONE 1 /* Standalone */ 48 #define IH_TYPE_KERNEL 2 /* OS Kernel Image */ 49 #define IH_TYPE_SCRIPT 6 /* Script file */ 50 51 #define IH_COMP_NONE 0 /* No compression */ 52 53 #define IH_MAGIC 0x27051956 /* Image Magic Number */ 54 #define IH_NMLEN 32 /* Image Name Length */ 55 56 struct image_header { 57 uint32_t ih_magic; 58 uint32_t ih_hcrc; 59 uint32_t ih_time; 60 uint32_t ih_size; 61 uint32_t ih_load; 62 uint32_t ih_ep; 63 uint32_t ih_dcrc; 64 uint8_t ih_os; 65 uint8_t ih_arch; 66 uint8_t ih_type; 67 uint8_t ih_comp; 68 uint8_t ih_name[IH_NMLEN]; 69 }; 70 71 extern char *__progname; 72 73 extern u_long elf32_copy_elf(int, const char *, int, const char *, u_long, 74 struct image_header *); 75 extern u_long elf64_copy_elf(int, const char *, int, const char *, u_long, 76 struct image_header *); 77 78 u_long copy_data(int, const char *, int, const char *, u_long, 79 struct image_header *, Elf_Word); 80 u_long (*copy_elf)(int, const char *, int, const char *, u_long, 81 struct image_header *); 82 83 u_long copy_mem(void *, int, const char *, u_long, struct image_header *, 84 Elf_Word); 85 u_long copy_raw(int, const char *, int, const char *, u_long, 86 struct image_header *); 87 u_long fill_zeroes(int, const char *, u_long, struct image_header *, Elf_Word); 88 int is_elf(int, const char *); 89 void usage(void); 90 91 struct arch_map { 92 int id; 93 const char *arch; 94 }; 95 96 static const struct arch_map archmap[] = { 97 { IH_ARCH_ALPHA, "alpha" }, 98 { IH_ARCH_IA64, "amd64" }, 99 { IH_ARCH_ARM, "arm" }, 100 { IH_ARCH_I386, "i386" }, 101 { IH_ARCH_M68K, "m68k" }, 102 { IH_ARCH_MIPS, "mips" }, 103 { IH_ARCH_MIPS64, "mips64" }, 104 { IH_ARCH_PPC, "powerpc" }, 105 { IH_ARCH_SPARC, "sparc" }, 106 { IH_ARCH_SPARC64, "sparc64" }, 107 { IH_ARCH_SH, "superh" }, 108 { 0, NULL } 109 }; 110 111 struct type_map { 112 int id; 113 const char *type; 114 }; 115 static const struct type_map typemap[] = { 116 { IH_TYPE_STANDALONE, "standalone" }, 117 { IH_TYPE_KERNEL, "kernel" }, 118 { IH_TYPE_SCRIPT, "script" }, 119 { 0, NULL } 120 }; 121 122 struct os_map { 123 int id; 124 const char *arch; 125 }; 126 127 static const struct os_map osmap[] = { 128 { IH_OS_OPENBSD, "OpenBSD" }, 129 { IH_OS_LINUX, "Linux" }, 130 { 0, NULL } 131 }; 132 133 134 int 135 main(int argc, char *argv[]) 136 { 137 struct image_header ih; 138 struct stat sb; 139 const struct arch_map *mapptr; 140 const struct os_map *osmapptr; 141 const struct type_map *typemapptr; 142 const char *iname, *oname; 143 const char *arch = MACHINE_ARCH; 144 const char *os = "OpenBSD"; 145 const char *type = "kernel"; 146 const char *imgname = "boot"; 147 int ifd, ofd; 148 uint32_t fsize; 149 u_long crc; 150 int c, ep, load; 151 152 ep = load = 0; 153 while ((c = getopt(argc, argv, "a:e:l:n:o:t:")) != -1) { 154 switch (c) { 155 case 'a': 156 arch = optarg; 157 break; 158 case 'e': 159 sscanf(optarg, "0x%x", &ep); 160 break; 161 case 'l': 162 sscanf(optarg, "0x%x", &load); 163 break; 164 case 'n': 165 imgname = optarg; 166 break; 167 case 'o': 168 os = optarg; 169 break; 170 case 't': 171 type = optarg; 172 break; 173 default: 174 usage(); 175 } 176 } 177 178 for (mapptr = archmap; mapptr->arch; mapptr++) 179 if (strcasecmp(arch, mapptr->arch) == 0) 180 break; 181 182 if (mapptr->arch == NULL) { 183 printf("unknown arch '%s'\n", arch); 184 usage(); 185 } 186 187 for (osmapptr = osmap; osmapptr->arch; osmapptr++) 188 if (strcasecmp(os, osmapptr->arch) == 0) 189 break; 190 191 if (osmapptr->arch == NULL) { 192 printf("unknown OS '%s'\n", os); 193 usage(); 194 } 195 196 for (typemapptr = typemap; typemapptr->type; typemapptr++) 197 if (strcasecmp(type, typemapptr->type) == 0) 198 break; 199 200 if (typemapptr->type == NULL) { 201 printf("unknown type '%s'\n", os); 202 usage(); 203 } 204 205 if (argc - optind != 2) 206 usage(); 207 208 iname = argv[optind++]; 209 oname = argv[optind++]; 210 211 /* Initialize U-Boot header. */ 212 bzero(&ih, sizeof ih); 213 ih.ih_magic = htobe32(IH_MAGIC); 214 ih.ih_time = htobe32(time(NULL)); 215 ih.ih_load = htobe32(load); 216 ih.ih_ep = htobe32(ep); 217 ih.ih_os = osmapptr->id; 218 ih.ih_arch = mapptr->id; 219 ih.ih_type = typemapptr->id; 220 ih.ih_comp = IH_COMP_NONE; 221 strlcpy((char *)ih.ih_name, imgname, sizeof ih.ih_name); 222 223 ifd = open(iname, O_RDONLY); 224 if (ifd < 0) 225 err(1, "%s", iname); 226 if (fstat(ifd, &sb) == -1) 227 err(1, "%s", iname); 228 229 ofd = open(oname, O_RDWR | O_TRUNC | O_CREAT, 0644); 230 if (ofd < 0) 231 err(1, "%s", oname); 232 233 if (pledge("stdio", NULL) == -1) 234 err(1, "pledge"); 235 236 /* Write initial header. */ 237 if (write(ofd, &ih, sizeof ih) != sizeof ih) 238 err(1, "%s", oname); 239 240 /* Write data, calculating the data CRC as we go. */ 241 crc = crc32(0L, Z_NULL, 0); 242 243 if (ih.ih_type == IH_TYPE_SCRIPT) { 244 /* scripts have two extra words of size/pad */ 245 fsize = htobe32(sb.st_size); 246 crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize)); 247 if (write(ofd, &fsize, sizeof fsize) != sizeof fsize) 248 err(1, "%s", oname); 249 fsize = 0; 250 crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize)); 251 if (write(ofd, &fsize, sizeof fsize) != sizeof fsize) 252 err(1, "%s", oname); 253 } 254 255 if (is_elf(ifd, iname)) 256 crc = copy_elf(ifd, iname, ofd, oname, crc, &ih); 257 else 258 crc = copy_raw(ifd, iname, ofd, oname, crc, &ih); 259 ih.ih_dcrc = htobe32(crc); 260 261 if (ih.ih_type == IH_TYPE_SCRIPT) { 262 ih.ih_size += 8; /* two extra pad words */ 263 } 264 265 ih.ih_size = htobe32(ih.ih_size); 266 267 /* Calculate header CRC. */ 268 crc = crc32(0, (Bytef *)&ih, sizeof ih); 269 ih.ih_hcrc = htobe32(crc); 270 271 /* Write finalized header. */ 272 if (lseek(ofd, 0, SEEK_SET) != 0) 273 err(1, "%s", oname); 274 if (write(ofd, &ih, sizeof ih) != sizeof ih) 275 err(1, "%s", oname); 276 277 return(0); 278 } 279 280 int 281 is_elf(int ifd, const char *iname) 282 { 283 ssize_t nbytes; 284 Elf_Ehdr ehdr; 285 286 nbytes = read(ifd, &ehdr, sizeof ehdr); 287 if (nbytes == -1) 288 err(1, "%s", iname); 289 if (lseek(ifd, 0, SEEK_SET) != 0) 290 err(1, "%s", iname); 291 292 if (nbytes != sizeof ehdr || !IS_ELF(ehdr)) 293 return 0; 294 295 if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) 296 copy_elf = elf32_copy_elf; 297 else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) 298 copy_elf = elf64_copy_elf; 299 else 300 err(1, "%s: invalid elf, not 32 or 64 bit", iname); 301 return 1; 302 } 303 304 u_long 305 copy_data(int ifd, const char *iname, int ofd, const char *oname, u_long crc, 306 struct image_header *ih, Elf_Word size) 307 { 308 ssize_t nbytes, chunk; 309 char buf[BUFSIZ]; 310 311 while (size != 0) { 312 chunk = size > BUFSIZ ? BUFSIZ : size; 313 nbytes = read(ifd, buf, chunk); 314 if (nbytes != chunk) 315 err(1, "%s", iname); 316 if (write(ofd, buf, nbytes) != nbytes) 317 err(1, "%s", oname); 318 crc = crc32(crc, (Bytef *)buf, nbytes); 319 ih->ih_size += nbytes; 320 size -= nbytes; 321 } 322 323 return crc; 324 } 325 326 u_long 327 copy_mem(void *mem, int ofd, const char *oname, u_long crc, 328 struct image_header *ih, Elf_Word size) 329 { 330 ssize_t nbytes; 331 char *memp = (char *)mem; 332 333 while (size != 0) { 334 nbytes = size > BUFSIZ ? BUFSIZ : size; 335 if (write(ofd, memp, nbytes) != nbytes) 336 err(1, "%s", oname); 337 crc = crc32(crc, (Bytef *)memp, nbytes); 338 memp += nbytes; 339 ih->ih_size += nbytes; 340 size -= nbytes; 341 } 342 343 return crc; 344 } 345 346 u_long 347 fill_zeroes(int ofd, const char *oname, u_long crc, struct image_header *ih, 348 Elf_Word size) 349 { 350 ssize_t nbytes, chunk; 351 char buf[BUFSIZ]; 352 353 memset(buf, 0, BUFSIZ); 354 while (size != 0) { 355 chunk = size > BUFSIZ ? BUFSIZ : size; 356 nbytes = write(ofd, buf, chunk); 357 if (nbytes != chunk) 358 err(1, "%s", oname); 359 crc = crc32(crc, (Bytef *)buf, nbytes); 360 ih->ih_size += nbytes; 361 size -= nbytes; 362 } 363 364 return crc; 365 } 366 367 u_long 368 copy_raw(int ifd, const char *iname, int ofd, const char *oname, u_long crc, 369 struct image_header *ih) 370 { 371 ssize_t nbytes; 372 char buf[BUFSIZ]; 373 374 while ((nbytes = read(ifd, buf, sizeof buf)) != 0) { 375 if (nbytes == -1) 376 err(1, "%s", iname); 377 if (write(ofd, buf, nbytes) != nbytes) 378 err(1, "%s", oname); 379 crc = crc32(crc, (Bytef *)buf, nbytes); 380 ih->ih_size += nbytes; 381 } 382 383 return crc; 384 } 385 386 void 387 usage(void) 388 { 389 const struct arch_map *mapptr; 390 const struct os_map *osmapptr; 391 392 (void)fprintf(stderr, 393 "usage: %s [-a arch] [-e entry] [-l loadaddr] [-n name] [-o os] " 394 "[-t type] infile outfile\n", __progname); 395 (void)fprintf(stderr, 396 "arch is one of:"); 397 for (mapptr = archmap; mapptr->arch; mapptr++) 398 (void)fprintf(stderr, " %s", mapptr->arch); 399 (void)fprintf(stderr, "\n"); 400 (void)fprintf(stderr, 401 "os is one of:"); 402 for (osmapptr = osmap; osmapptr->arch; osmapptr++) 403 (void)fprintf(stderr, " %s", osmapptr->arch); 404 (void)fprintf(stderr, "\n"); 405 406 exit(1); 407 } 408