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