1 /* $NetBSD: mkubootimage.c,v 1.7 2011/06/08 05:54:38 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #if HAVE_NBTOOL_CONFIG_H 29 #include "nbtool_config.h" 30 #endif 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: mkubootimage.c,v 1.7 2011/06/08 05:54:38 matt Exp $"); 34 35 #include <sys/mman.h> 36 #include <sys/stat.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <limits.h> 41 #include <stdint.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <time.h> 46 #include <unistd.h> 47 48 #include "uboot.h" 49 50 #ifndef __arraycount 51 #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 52 #endif 53 54 extern uint32_t crc32(const void *, size_t); 55 56 static enum uboot_image_os image_os = IH_OS_NETBSD; 57 static enum uboot_image_arch image_arch = IH_ARCH_UNKNOWN; 58 static enum uboot_image_type image_type = IH_TYPE_UNKNOWN; 59 static enum uboot_image_comp image_comp = IH_COMP_NONE; 60 static uint32_t image_loadaddr = 0; 61 static uint32_t image_entrypoint = 0; 62 static char *image_name; 63 64 struct uboot_os { 65 enum uboot_image_os os; 66 const char *name; 67 } uboot_os[] = { 68 { IH_OS_OPENBSD, "openbsd" }, 69 { IH_OS_NETBSD, "netbsd" }, 70 { IH_OS_FREEBSD, "freebsd" }, 71 { IH_OS_LINUX, "linux" }, 72 }; 73 74 static enum uboot_image_os 75 get_os(const char *name) 76 { 77 unsigned int i; 78 79 for (i = 0; i < __arraycount(uboot_os); i++) { 80 if (strcmp(uboot_os[i].name, name) == 0) 81 return uboot_os[i].os; 82 } 83 84 return IH_OS_UNKNOWN; 85 } 86 87 static const char * 88 get_os_name(enum uboot_image_os os) 89 { 90 unsigned int i; 91 92 for (i = 0; i < __arraycount(uboot_os); i++) { 93 if (uboot_os[i].os == os) 94 return uboot_os[i].name; 95 } 96 97 return "Unknown"; 98 } 99 100 struct uboot_arch { 101 enum uboot_image_arch arch; 102 const char *name; 103 } uboot_arch[] = { 104 { IH_ARCH_ARM, "arm" }, 105 { IH_ARCH_MIPS, "mips" }, 106 { IH_ARCH_MIPS64, "mips64" }, 107 { IH_ARCH_PPC, "powerpc" }, 108 }; 109 110 static enum uboot_image_arch 111 get_arch(const char *name) 112 { 113 unsigned int i; 114 115 for (i = 0; i < __arraycount(uboot_arch); i++) { 116 if (strcmp(uboot_arch[i].name, name) == 0) 117 return uboot_arch[i].arch; 118 } 119 120 return IH_ARCH_UNKNOWN; 121 } 122 123 static const char * 124 get_arch_name(enum uboot_image_arch arch) 125 { 126 unsigned int i; 127 128 for (i = 0; i < __arraycount(uboot_arch); i++) { 129 if (uboot_arch[i].arch == arch) 130 return uboot_arch[i].name; 131 } 132 133 return "Unknown"; 134 } 135 136 struct uboot_type { 137 enum uboot_image_type type; 138 const char *name; 139 } uboot_type[] = { 140 { IH_TYPE_STANDALONE, "standalone" }, 141 { IH_TYPE_KERNEL, "kernel" }, 142 { IH_TYPE_RAMDISK, "ramdisk" }, 143 { IH_TYPE_FILESYSTEM, "fs" }, 144 }; 145 146 static enum uboot_image_type 147 get_type(const char *name) 148 { 149 unsigned int i; 150 151 for (i = 0; i < __arraycount(uboot_type); i++) { 152 if (strcmp(uboot_type[i].name, name) == 0) 153 return uboot_type[i].type; 154 } 155 156 return IH_TYPE_UNKNOWN; 157 } 158 159 static const char * 160 get_type_name(enum uboot_image_type type) 161 { 162 unsigned int i; 163 164 for (i = 0; i < __arraycount(uboot_type); i++) { 165 if (uboot_type[i].type == type) 166 return uboot_type[i].name; 167 } 168 169 return "Unknown"; 170 } 171 172 struct uboot_comp { 173 enum uboot_image_comp comp; 174 const char *name; 175 } uboot_comp[] = { 176 { IH_COMP_NONE, "none" }, 177 { IH_COMP_GZIP, "gz" }, 178 { IH_COMP_BZIP2, "bz2" }, 179 }; 180 181 static enum uboot_image_comp 182 get_comp(const char *name) 183 { 184 unsigned int i; 185 186 for (i = 0; i < __arraycount(uboot_comp); i++) { 187 if (strcmp(uboot_comp[i].name, name) == 0) 188 return uboot_comp[i].comp; 189 } 190 191 return IH_TYPE_UNKNOWN; 192 } 193 194 static const char * 195 get_comp_name(enum uboot_image_comp comp) 196 { 197 unsigned int i; 198 199 for (i = 0; i < __arraycount(uboot_comp); i++) { 200 if (uboot_comp[i].comp == comp) 201 return uboot_comp[i].name; 202 } 203 204 return "Unknown"; 205 } 206 207 static void 208 usage(void) 209 { 210 fprintf(stderr, "usage: mkubootimage -A <arm|mips|mips64|powerpc>"); 211 fprintf(stderr, " -C <none|gz|bz2>"); 212 fprintf(stderr, " -O <openbsd|netbsd|freebsd|linux>"); 213 fprintf(stderr, " -T <standalone|kernel|ramdisk|fs>"); 214 fprintf(stderr, " -a <addr> [-e <ep>] -n <name>"); 215 fprintf(stderr, " <srcfile> <dstfile>\n"); 216 217 exit(EXIT_FAILURE); 218 } 219 220 static void 221 dump_header(struct uboot_image_header *hdr) 222 { 223 time_t tm = ntohl(hdr->ih_time); 224 225 printf(" magic: 0x%08x\n", ntohl(hdr->ih_magic)); 226 printf(" time: %s", ctime(&tm)); 227 printf(" size: %u\n", ntohl(hdr->ih_size)); 228 printf(" load addr: 0x%08x\n", ntohl(hdr->ih_load)); 229 printf(" entry point: 0x%08x\n", ntohl(hdr->ih_ep)); 230 printf(" data crc: 0x%08x\n", ntohl(hdr->ih_dcrc)); 231 printf(" os: %d (%s)\n", hdr->ih_os, 232 get_os_name(hdr->ih_os)); 233 printf(" arch: %d (%s)\n", hdr->ih_arch, 234 get_arch_name(hdr->ih_arch)); 235 printf(" type: %d (%s)\n", hdr->ih_type, 236 get_type_name(hdr->ih_type)); 237 printf(" comp: %d (%s)\n", hdr->ih_comp, 238 get_comp_name(hdr->ih_comp)); 239 printf(" name: %s\n", hdr->ih_name); 240 printf(" header crc: 0x%08x\n", hdr->ih_hcrc); 241 } 242 243 static int 244 generate_header(struct uboot_image_header *hdr, int kernel_fd) 245 { 246 uint8_t *p; 247 struct stat st; 248 uint32_t crc; 249 int error; 250 251 error = fstat(kernel_fd, &st); 252 if (error == -1) { 253 perror("stat"); 254 return errno; 255 } 256 257 if (st.st_size + sizeof(*hdr) > UINT32_MAX) { 258 fprintf(stderr, "fatal: kernel too big\n"); 259 return EINVAL; 260 } 261 262 p = mmap(0, st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, kernel_fd, 0); 263 if (p == MAP_FAILED) { 264 perror("mmap kernel"); 265 return EINVAL; 266 } 267 crc = crc32(p, st.st_size); 268 munmap(p, st.st_size); 269 270 memset(hdr, 0, sizeof(*hdr)); 271 hdr->ih_magic = htonl(IH_MAGIC); 272 hdr->ih_time = htonl(st.st_mtime); 273 hdr->ih_size = htonl(st.st_size); 274 hdr->ih_load = htonl(image_loadaddr); 275 hdr->ih_ep = htonl(image_entrypoint); 276 hdr->ih_dcrc = htonl(crc); 277 hdr->ih_os = image_os; 278 hdr->ih_arch = image_arch; 279 hdr->ih_type = image_type; 280 hdr->ih_comp = image_comp; 281 strlcpy((char *)hdr->ih_name, image_name, sizeof(hdr->ih_name)); 282 crc = crc32((void *)hdr, sizeof(*hdr)); 283 hdr->ih_hcrc = htonl(crc); 284 285 dump_header(hdr); 286 287 return 0; 288 } 289 290 static int 291 write_image(struct uboot_image_header *hdr, int kernel_fd, int image_fd) 292 { 293 uint8_t buf[4096]; 294 ssize_t rlen, wlen; 295 296 wlen = write(image_fd, hdr, sizeof(*hdr)); 297 if (wlen != sizeof(*hdr)) { 298 perror("short write"); 299 return errno; 300 } 301 302 while ((rlen = read(kernel_fd, buf, sizeof(buf))) > 0) { 303 wlen = write(image_fd, buf, rlen); 304 if (wlen != rlen) { 305 perror("short write"); 306 return errno; 307 } 308 } 309 310 return 0; 311 } 312 313 int 314 main(int argc, char *argv[]) 315 { 316 struct uboot_image_header hdr; 317 const char *src, *dest; 318 char *ep; 319 int kernel_fd, image_fd; 320 int ch; 321 unsigned long num; 322 323 while ((ch = getopt(argc, argv, "A:C:O:T:a:e:hn:")) != -1) { 324 switch (ch) { 325 case 'A': /* arch */ 326 image_arch = get_arch(optarg); 327 break; 328 case 'C': /* comp */ 329 image_comp = get_comp(optarg); 330 break; 331 case 'O': /* os */ 332 image_os = get_os(optarg); 333 break; 334 case 'T': /* type */ 335 image_type = get_type(optarg); 336 break; 337 case 'a': /* addr */ 338 errno = 0; 339 num = strtoul(optarg, &ep, 0); 340 if (*ep != '\0' || (errno == ERANGE && 341 (num == ULONG_MAX || num == 0))) 342 errx(1, "illegal number -- %s", optarg); 343 image_loadaddr = (uint32_t)num; 344 break; 345 case 'e': /* ep */ 346 errno = 0; 347 num = strtoul(optarg, &ep, 0); 348 if (*ep != '\0' || (errno == ERANGE && 349 (num == ULONG_MAX || num == 0))) 350 errx(1, "illegal number -- %s", optarg); 351 image_entrypoint = (uint32_t)num; 352 break; 353 case 'n': /* name */ 354 image_name = strdup(optarg); 355 break; 356 case 'h': 357 default: 358 usage(); 359 /* NOTREACHED */ 360 } 361 } 362 argc -= optind; 363 argv += optind; 364 365 if (argc != 2) 366 usage(); 367 368 if (image_entrypoint == 0) 369 image_entrypoint = image_loadaddr; 370 371 if (image_arch == IH_ARCH_UNKNOWN || 372 image_type == IH_TYPE_UNKNOWN || 373 image_loadaddr == 0 || 374 image_name == NULL) 375 usage(); 376 377 src = argv[0]; 378 dest = argv[1]; 379 380 kernel_fd = open(src, O_RDONLY); 381 if (kernel_fd == -1) { 382 perror("open kernel"); 383 return EXIT_FAILURE; 384 } 385 image_fd = open(dest, O_WRONLY|O_CREAT, 0666); 386 if (image_fd == -1) { 387 perror("open image"); 388 return EXIT_FAILURE; 389 } 390 391 if (generate_header(&hdr, kernel_fd) != 0) 392 return EXIT_FAILURE; 393 394 if (write_image(&hdr, kernel_fd, image_fd) != 0) 395 return EXIT_FAILURE; 396 397 close(image_fd); 398 close(kernel_fd); 399 400 return EXIT_SUCCESS; 401 } 402