1 /* $OpenBSD: mkuboot.c,v 1.4 2014/05/18 21:18:07 miod 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 227 ofd = open(oname, O_RDWR | O_TRUNC | O_CREAT, 0644); 228 if (ofd < 0) 229 err(1, "%s", oname); 230 231 if (stat(iname, &sb) == -1) { 232 err(1, "%s", oname); 233 } 234 235 /* Write initial header. */ 236 if (write(ofd, &ih, sizeof ih) != sizeof ih) 237 err(1, "%s", oname); 238 239 /* Write data, calculating the data CRC as we go. */ 240 crc = crc32(0L, Z_NULL, 0); 241 242 if (ih.ih_type == IH_TYPE_SCRIPT) { 243 /* scripts have two extra words of size/pad */ 244 fsize = htobe32(sb.st_size); 245 crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize)); 246 if (write(ofd, &fsize, sizeof fsize) != sizeof fsize) 247 err(1, "%s", oname); 248 fsize = 0; 249 crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize)); 250 if (write(ofd, &fsize, sizeof fsize) != sizeof fsize) 251 err(1, "%s", oname); 252 } 253 254 if (is_elf(ifd, iname)) 255 crc = copy_elf(ifd, iname, ofd, oname, crc, &ih); 256 else 257 crc = copy_raw(ifd, iname, ofd, oname, crc, &ih); 258 ih.ih_dcrc = htobe32(crc); 259 260 if (ih.ih_type == IH_TYPE_SCRIPT) { 261 ih.ih_size += 8; /* two extra pad words */ 262 } 263 264 ih.ih_size = htobe32(ih.ih_size); 265 266 /* Calculate header CRC. */ 267 crc = crc32(0, (Bytef *)&ih, sizeof ih); 268 ih.ih_hcrc = htobe32(crc); 269 270 /* Write finalized header. */ 271 if (lseek(ofd, 0, SEEK_SET) != 0) 272 err(1, "%s", oname); 273 if (write(ofd, &ih, sizeof ih) != sizeof ih) 274 err(1, "%s", oname); 275 276 return(0); 277 } 278 279 int 280 is_elf(int ifd, const char *iname) 281 { 282 ssize_t nbytes; 283 Elf_Ehdr ehdr; 284 285 nbytes = read(ifd, &ehdr, sizeof ehdr); 286 if (nbytes == -1) 287 err(1, "%s", iname); 288 if (lseek(ifd, 0, SEEK_SET) != 0) 289 err(1, "%s", iname); 290 291 if (nbytes != sizeof ehdr || !IS_ELF(ehdr)) 292 return 0; 293 294 if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) 295 copy_elf = elf32_copy_elf; 296 else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) 297 copy_elf = elf64_copy_elf; 298 else 299 err(1, "%s: invalid elf, not 32 or 64 bit", iname); 300 return 1; 301 } 302 303 u_long 304 copy_data(int ifd, const char *iname, int ofd, const char *oname, u_long crc, 305 struct image_header *ih, Elf_Word size) 306 { 307 ssize_t nbytes, chunk; 308 char buf[BUFSIZ]; 309 310 while (size != 0) { 311 chunk = size > BUFSIZ ? BUFSIZ : size; 312 nbytes = read(ifd, buf, chunk); 313 if (nbytes != chunk) 314 err(1, "%s", iname); 315 if (write(ofd, buf, nbytes) != nbytes) 316 err(1, "%s", oname); 317 crc = crc32(crc, (Bytef *)buf, nbytes); 318 ih->ih_size += nbytes; 319 size -= nbytes; 320 } 321 322 return crc; 323 } 324 325 u_long 326 copy_mem(void *mem, int ofd, const char *oname, u_long crc, 327 struct image_header *ih, Elf_Word size) 328 { 329 ssize_t nbytes; 330 char *memp = (char *)mem; 331 332 while (size != 0) { 333 nbytes = size > BUFSIZ ? BUFSIZ : size; 334 if (write(ofd, memp, nbytes) != nbytes) 335 err(1, "%s", oname); 336 crc = crc32(crc, (Bytef *)memp, nbytes); 337 memp += nbytes; 338 ih->ih_size += nbytes; 339 size -= nbytes; 340 } 341 342 return crc; 343 } 344 345 u_long 346 fill_zeroes(int ofd, const char *oname, u_long crc, struct image_header *ih, 347 Elf_Word size) 348 { 349 ssize_t nbytes, chunk; 350 char buf[BUFSIZ]; 351 352 memset(buf, 0, BUFSIZ); 353 while (size != 0) { 354 chunk = size > BUFSIZ ? BUFSIZ : size; 355 nbytes = write(ofd, buf, chunk); 356 if (nbytes != chunk) 357 err(1, "%s", oname); 358 crc = crc32(crc, (Bytef *)buf, nbytes); 359 ih->ih_size += nbytes; 360 size -= nbytes; 361 } 362 363 return crc; 364 } 365 366 u_long 367 copy_raw(int ifd, const char *iname, int ofd, const char *oname, u_long crc, 368 struct image_header *ih) 369 { 370 ssize_t nbytes; 371 char buf[BUFSIZ]; 372 373 while ((nbytes = read(ifd, buf, sizeof buf)) != 0) { 374 if (nbytes == -1) 375 err(1, "%s", iname); 376 if (write(ofd, buf, nbytes) != nbytes) 377 err(1, "%s", oname); 378 crc = crc32(crc, (Bytef *)buf, nbytes); 379 ih->ih_size += nbytes; 380 } 381 382 return crc; 383 } 384 385 void 386 usage(void) 387 { 388 const struct arch_map *mapptr; 389 const struct os_map *osmapptr; 390 391 (void)fprintf(stderr, 392 "usage: %s [-a arch] [-e entry] [-l loadaddr] [-n name] [-o os] " 393 "[-t type] infile outfile\n", __progname); 394 (void)fprintf(stderr, 395 "arch is one of:"); 396 for (mapptr = archmap; mapptr->arch; mapptr++) 397 (void)fprintf(stderr, " %s", mapptr->arch); 398 (void)fprintf(stderr, "\n"); 399 (void)fprintf(stderr, 400 "os is one of:"); 401 for (osmapptr = osmap; osmapptr->arch; osmapptr++) 402 (void)fprintf(stderr, " %s", osmapptr->arch); 403 (void)fprintf(stderr, "\n"); 404 405 exit(1); 406 } 407