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