1 1.34 gutterid /* $NetBSD: mkubootimage.c,v 1.34 2024/10/29 02:54:38 gutteridge Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2010 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. The name of the author may not be used to endorse or promote products 13 1.1 jmcneill * derived from this software without specific prior written permission. 14 1.1 jmcneill * 15 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 jmcneill * SUCH DAMAGE. 26 1.1 jmcneill */ 27 1.1 jmcneill 28 1.2 dogcow #if HAVE_NBTOOL_CONFIG_H 29 1.2 dogcow #include "nbtool_config.h" 30 1.2 dogcow #endif 31 1.2 dogcow 32 1.1 jmcneill #include <sys/cdefs.h> 33 1.34 gutterid __RCSID("$NetBSD: mkubootimage.c,v 1.34 2024/10/29 02:54:38 gutteridge Exp $"); 34 1.1 jmcneill 35 1.1 jmcneill #include <sys/mman.h> 36 1.1 jmcneill #include <sys/stat.h> 37 1.9 matt #include <sys/endian.h> 38 1.23 jmcneill #include <sys/param.h> 39 1.17 jmcneill #include <sys/uio.h> 40 1.1 jmcneill #include <err.h> 41 1.1 jmcneill #include <errno.h> 42 1.1 jmcneill #include <fcntl.h> 43 1.23 jmcneill #include <inttypes.h> 44 1.1 jmcneill #include <limits.h> 45 1.1 jmcneill #include <stdint.h> 46 1.1 jmcneill #include <stdio.h> 47 1.1 jmcneill #include <stdlib.h> 48 1.1 jmcneill #include <string.h> 49 1.1 jmcneill #include <time.h> 50 1.1 jmcneill #include <unistd.h> 51 1.1 jmcneill 52 1.1 jmcneill #include "uboot.h" 53 1.23 jmcneill #include "arm64.h" 54 1.31 christos #include "crc32.h" 55 1.1 jmcneill 56 1.1 jmcneill #ifndef __arraycount 57 1.1 jmcneill #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 58 1.1 jmcneill #endif 59 1.1 jmcneill 60 1.23 jmcneill enum image_format { 61 1.23 jmcneill FMT_UNKNOWN, 62 1.23 jmcneill FMT_UIMG, /* Legacy U-Boot image */ 63 1.23 jmcneill FMT_ARM64, /* Linux ARM64 image (booti) */ 64 1.23 jmcneill }; 65 1.23 jmcneill 66 1.6 phx static enum uboot_image_os image_os = IH_OS_NETBSD; 67 1.1 jmcneill static enum uboot_image_arch image_arch = IH_ARCH_UNKNOWN; 68 1.1 jmcneill static enum uboot_image_type image_type = IH_TYPE_UNKNOWN; 69 1.1 jmcneill static enum uboot_image_comp image_comp = IH_COMP_NONE; 70 1.1 jmcneill static uint32_t image_loadaddr = 0; 71 1.1 jmcneill static uint32_t image_entrypoint = 0; 72 1.1 jmcneill static char *image_name; 73 1.8 riz static uint32_t image_magic = IH_MAGIC; 74 1.23 jmcneill static enum image_format image_format = FMT_UIMG; 75 1.25 jmcneill static int update_image = 0; 76 1.23 jmcneill 77 1.23 jmcneill static const struct uboot_image_format { 78 1.23 jmcneill enum image_format format; 79 1.23 jmcneill const char *name; 80 1.23 jmcneill } uboot_image_format[] = { 81 1.23 jmcneill { FMT_UIMG, "uimg" }, 82 1.23 jmcneill { FMT_ARM64, "arm64" }, 83 1.23 jmcneill }; 84 1.23 jmcneill 85 1.23 jmcneill static enum image_format 86 1.23 jmcneill get_image_format(const char *name) 87 1.23 jmcneill { 88 1.23 jmcneill unsigned int i; 89 1.23 jmcneill 90 1.23 jmcneill for (i = 0; i < __arraycount(uboot_image_format); i++) { 91 1.23 jmcneill if (strcmp(uboot_image_format[i].name, name) == 0) 92 1.23 jmcneill return uboot_image_format[i].format; 93 1.23 jmcneill } 94 1.23 jmcneill 95 1.23 jmcneill return FMT_UNKNOWN; 96 1.23 jmcneill } 97 1.23 jmcneill 98 1.23 jmcneill static const char * 99 1.23 jmcneill get_image_format_name(enum image_format format) 100 1.23 jmcneill { 101 1.23 jmcneill unsigned int i; 102 1.23 jmcneill 103 1.23 jmcneill for (i = 0; i < __arraycount(uboot_image_format); i++) { 104 1.23 jmcneill if (uboot_image_format[i].format == format) 105 1.23 jmcneill return uboot_image_format[i].name; 106 1.23 jmcneill } 107 1.23 jmcneill 108 1.23 jmcneill return "Unknown"; 109 1.23 jmcneill } 110 1.1 jmcneill 111 1.14 joerg static const struct uboot_os { 112 1.6 phx enum uboot_image_os os; 113 1.6 phx const char *name; 114 1.6 phx } uboot_os[] = { 115 1.6 phx { IH_OS_OPENBSD, "openbsd" }, 116 1.6 phx { IH_OS_NETBSD, "netbsd" }, 117 1.6 phx { IH_OS_FREEBSD, "freebsd" }, 118 1.6 phx { IH_OS_LINUX, "linux" }, 119 1.6 phx }; 120 1.6 phx 121 1.6 phx static enum uboot_image_os 122 1.6 phx get_os(const char *name) 123 1.6 phx { 124 1.6 phx unsigned int i; 125 1.6 phx 126 1.6 phx for (i = 0; i < __arraycount(uboot_os); i++) { 127 1.6 phx if (strcmp(uboot_os[i].name, name) == 0) 128 1.6 phx return uboot_os[i].os; 129 1.6 phx } 130 1.6 phx 131 1.6 phx return IH_OS_UNKNOWN; 132 1.6 phx } 133 1.6 phx 134 1.7 matt static const char * 135 1.7 matt get_os_name(enum uboot_image_os os) 136 1.7 matt { 137 1.7 matt unsigned int i; 138 1.7 matt 139 1.7 matt for (i = 0; i < __arraycount(uboot_os); i++) { 140 1.7 matt if (uboot_os[i].os == os) 141 1.7 matt return uboot_os[i].name; 142 1.7 matt } 143 1.7 matt 144 1.7 matt return "Unknown"; 145 1.7 matt } 146 1.7 matt 147 1.13 joerg static const struct uboot_arch { 148 1.1 jmcneill enum uboot_image_arch arch; 149 1.1 jmcneill const char *name; 150 1.1 jmcneill } uboot_arch[] = { 151 1.1 jmcneill { IH_ARCH_ARM, "arm" }, 152 1.21 jmcneill { IH_ARCH_ARM64, "arm64" }, 153 1.18 msaitoh { IH_ARCH_I386, "i386" }, 154 1.5 matt { IH_ARCH_MIPS, "mips" }, 155 1.5 matt { IH_ARCH_MIPS64, "mips64" }, 156 1.1 jmcneill { IH_ARCH_PPC, "powerpc" }, 157 1.18 msaitoh { IH_ARCH_OPENRISC, "or1k" }, 158 1.32 gutterid { IH_ARCH_RISCV, "riscv" }, 159 1.21 jmcneill { IH_ARCH_SH, "sh" }, 160 1.1 jmcneill }; 161 1.1 jmcneill 162 1.1 jmcneill static enum uboot_image_arch 163 1.1 jmcneill get_arch(const char *name) 164 1.1 jmcneill { 165 1.1 jmcneill unsigned int i; 166 1.1 jmcneill 167 1.1 jmcneill for (i = 0; i < __arraycount(uboot_arch); i++) { 168 1.1 jmcneill if (strcmp(uboot_arch[i].name, name) == 0) 169 1.1 jmcneill return uboot_arch[i].arch; 170 1.1 jmcneill } 171 1.1 jmcneill 172 1.1 jmcneill return IH_ARCH_UNKNOWN; 173 1.1 jmcneill } 174 1.1 jmcneill 175 1.7 matt static const char * 176 1.7 matt get_arch_name(enum uboot_image_arch arch) 177 1.7 matt { 178 1.7 matt unsigned int i; 179 1.7 matt 180 1.7 matt for (i = 0; i < __arraycount(uboot_arch); i++) { 181 1.7 matt if (uboot_arch[i].arch == arch) 182 1.7 matt return uboot_arch[i].name; 183 1.7 matt } 184 1.7 matt 185 1.7 matt return "Unknown"; 186 1.7 matt } 187 1.7 matt 188 1.14 joerg static const struct uboot_type { 189 1.1 jmcneill enum uboot_image_type type; 190 1.1 jmcneill const char *name; 191 1.1 jmcneill } uboot_type[] = { 192 1.20 jmcneill { IH_TYPE_STANDALONE, "standalone" }, 193 1.20 jmcneill { IH_TYPE_KERNEL, "kernel" }, 194 1.20 jmcneill { IH_TYPE_KERNEL_NOLOAD, "kernel_noload" }, 195 1.20 jmcneill { IH_TYPE_RAMDISK, "ramdisk" }, 196 1.20 jmcneill { IH_TYPE_FILESYSTEM, "fs" }, 197 1.20 jmcneill { IH_TYPE_SCRIPT, "script" }, 198 1.1 jmcneill }; 199 1.1 jmcneill 200 1.1 jmcneill static enum uboot_image_type 201 1.1 jmcneill get_type(const char *name) 202 1.1 jmcneill { 203 1.1 jmcneill unsigned int i; 204 1.1 jmcneill 205 1.1 jmcneill for (i = 0; i < __arraycount(uboot_type); i++) { 206 1.1 jmcneill if (strcmp(uboot_type[i].name, name) == 0) 207 1.1 jmcneill return uboot_type[i].type; 208 1.1 jmcneill } 209 1.1 jmcneill 210 1.1 jmcneill return IH_TYPE_UNKNOWN; 211 1.1 jmcneill } 212 1.1 jmcneill 213 1.7 matt static const char * 214 1.7 matt get_type_name(enum uboot_image_type type) 215 1.7 matt { 216 1.7 matt unsigned int i; 217 1.7 matt 218 1.7 matt for (i = 0; i < __arraycount(uboot_type); i++) { 219 1.7 matt if (uboot_type[i].type == type) 220 1.7 matt return uboot_type[i].name; 221 1.7 matt } 222 1.7 matt 223 1.7 matt return "Unknown"; 224 1.7 matt } 225 1.7 matt 226 1.14 joerg static const struct uboot_comp { 227 1.1 jmcneill enum uboot_image_comp comp; 228 1.1 jmcneill const char *name; 229 1.1 jmcneill } uboot_comp[] = { 230 1.1 jmcneill { IH_COMP_NONE, "none" }, 231 1.1 jmcneill { IH_COMP_GZIP, "gz" }, 232 1.1 jmcneill { IH_COMP_BZIP2, "bz2" }, 233 1.10 matt { IH_COMP_LZMA, "lzma" }, 234 1.10 matt { IH_COMP_LZO, "lzo" }, 235 1.1 jmcneill }; 236 1.1 jmcneill 237 1.1 jmcneill static enum uboot_image_comp 238 1.1 jmcneill get_comp(const char *name) 239 1.1 jmcneill { 240 1.1 jmcneill unsigned int i; 241 1.1 jmcneill 242 1.1 jmcneill for (i = 0; i < __arraycount(uboot_comp); i++) { 243 1.1 jmcneill if (strcmp(uboot_comp[i].name, name) == 0) 244 1.1 jmcneill return uboot_comp[i].comp; 245 1.1 jmcneill } 246 1.1 jmcneill 247 1.24 jmcneill return IH_COMP_NONE; 248 1.1 jmcneill } 249 1.1 jmcneill 250 1.7 matt static const char * 251 1.7 matt get_comp_name(enum uboot_image_comp comp) 252 1.7 matt { 253 1.7 matt unsigned int i; 254 1.7 matt 255 1.7 matt for (i = 0; i < __arraycount(uboot_comp); i++) { 256 1.7 matt if (uboot_comp[i].comp == comp) 257 1.7 matt return uboot_comp[i].name; 258 1.7 matt } 259 1.7 matt 260 1.7 matt return "Unknown"; 261 1.7 matt } 262 1.7 matt 263 1.13 joerg __dead static void 264 1.1 jmcneill usage(void) 265 1.1 jmcneill { 266 1.31 christos fprintf(stderr, 267 1.33 gutterid "Usage: %s [-hu] -A <arm|arm64|i386|mips|mips64|or1k|powerpc|riscv|sh>\n" 268 1.33 gutterid "\t-a address [-C <bz2|gz|lzma|lzo|none>] [-E address] [-e address] \n" 269 1.33 gutterid "\t[-f <arm64|uimg>] [-m magic] -n image [-O <freebsd|linux|netbsd|openbsd>]\n" 270 1.33 gutterid "\t-T <fs|kernel|kernel_noload|ramdisk|script|standalone> [-t timestamp]\n" 271 1.31 christos "\tsource destination\n", getprogname()); 272 1.1 jmcneill 273 1.1 jmcneill exit(EXIT_FAILURE); 274 1.1 jmcneill } 275 1.1 jmcneill 276 1.1 jmcneill static void 277 1.23 jmcneill dump_header_uimg(struct uboot_image_header *hdr) 278 1.1 jmcneill { 279 1.34 gutterid time_t tm = be32toh(hdr->ih_time); 280 1.1 jmcneill 281 1.34 gutterid printf(" magic: 0x%08x\n", be32toh(hdr->ih_magic)); 282 1.1 jmcneill printf(" time: %s", ctime(&tm)); 283 1.34 gutterid printf(" size: %u\n", be32toh(hdr->ih_size)); 284 1.34 gutterid printf(" load addr: 0x%08x\n", be32toh(hdr->ih_load)); 285 1.34 gutterid printf(" entry point: 0x%08x\n", be32toh(hdr->ih_ep)); 286 1.34 gutterid printf(" data crc: 0x%08x\n", be32toh(hdr->ih_dcrc)); 287 1.7 matt printf(" os: %d (%s)\n", hdr->ih_os, 288 1.7 matt get_os_name(hdr->ih_os)); 289 1.7 matt printf(" arch: %d (%s)\n", hdr->ih_arch, 290 1.7 matt get_arch_name(hdr->ih_arch)); 291 1.7 matt printf(" type: %d (%s)\n", hdr->ih_type, 292 1.7 matt get_type_name(hdr->ih_type)); 293 1.7 matt printf(" comp: %d (%s)\n", hdr->ih_comp, 294 1.7 matt get_comp_name(hdr->ih_comp)); 295 1.1 jmcneill printf(" name: %s\n", hdr->ih_name); 296 1.1 jmcneill printf(" header crc: 0x%08x\n", hdr->ih_hcrc); 297 1.1 jmcneill } 298 1.1 jmcneill 299 1.1 jmcneill static int 300 1.31 christos generate_header_uimg(struct uboot_image_header *hdr, time_t repro_time, 301 1.31 christos int kernel_fd) 302 1.1 jmcneill { 303 1.1 jmcneill uint8_t *p; 304 1.1 jmcneill struct stat st; 305 1.17 jmcneill uint32_t crc, dsize, size_buf[2]; 306 1.1 jmcneill int error; 307 1.1 jmcneill 308 1.1 jmcneill error = fstat(kernel_fd, &st); 309 1.1 jmcneill if (error == -1) { 310 1.1 jmcneill perror("stat"); 311 1.1 jmcneill return errno; 312 1.1 jmcneill } 313 1.1 jmcneill 314 1.1 jmcneill if (st.st_size + sizeof(*hdr) > UINT32_MAX) { 315 1.1 jmcneill fprintf(stderr, "fatal: kernel too big\n"); 316 1.1 jmcneill return EINVAL; 317 1.1 jmcneill } 318 1.1 jmcneill 319 1.1 jmcneill p = mmap(0, st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, kernel_fd, 0); 320 1.1 jmcneill if (p == MAP_FAILED) { 321 1.1 jmcneill perror("mmap kernel"); 322 1.1 jmcneill return EINVAL; 323 1.1 jmcneill } 324 1.17 jmcneill if (image_type == IH_TYPE_SCRIPT) { 325 1.17 jmcneill struct iovec iov[3]; 326 1.31 christos dsize = (uint32_t)(st.st_size + (sizeof(uint32_t) * 2)); 327 1.34 gutterid size_buf[0] = htobe32(st.st_size); 328 1.34 gutterid size_buf[1] = htobe32(0); 329 1.17 jmcneill iov[0].iov_base = &size_buf[0]; 330 1.17 jmcneill iov[0].iov_len = sizeof(size_buf[0]); 331 1.17 jmcneill iov[1].iov_base = &size_buf[1]; 332 1.17 jmcneill iov[1].iov_len = sizeof(size_buf[1]); 333 1.17 jmcneill iov[2].iov_base = p; 334 1.17 jmcneill iov[2].iov_len = st.st_size; 335 1.17 jmcneill crc = crc32v(iov, 3); 336 1.17 jmcneill } else { 337 1.31 christos dsize = update_image ? (uint32_t)(st.st_size - sizeof(*hdr)) : 338 1.31 christos (uint32_t)st.st_size; 339 1.17 jmcneill crc = crc32(p, st.st_size); 340 1.17 jmcneill } 341 1.1 jmcneill munmap(p, st.st_size); 342 1.1 jmcneill 343 1.1 jmcneill memset(hdr, 0, sizeof(*hdr)); 344 1.34 gutterid hdr->ih_magic = htobe32(image_magic); 345 1.34 gutterid hdr->ih_time = htobe32(repro_time ? repro_time : st.st_mtime); 346 1.34 gutterid hdr->ih_size = htobe32(dsize); 347 1.34 gutterid hdr->ih_load = htobe32(image_loadaddr); 348 1.34 gutterid hdr->ih_ep = htobe32(image_entrypoint); 349 1.34 gutterid hdr->ih_dcrc = htobe32(crc); 350 1.6 phx hdr->ih_os = image_os; 351 1.1 jmcneill hdr->ih_arch = image_arch; 352 1.1 jmcneill hdr->ih_type = image_type; 353 1.1 jmcneill hdr->ih_comp = image_comp; 354 1.7 matt strlcpy((char *)hdr->ih_name, image_name, sizeof(hdr->ih_name)); 355 1.1 jmcneill crc = crc32((void *)hdr, sizeof(*hdr)); 356 1.34 gutterid hdr->ih_hcrc = htobe32(crc); 357 1.1 jmcneill 358 1.23 jmcneill dump_header_uimg(hdr); 359 1.1 jmcneill 360 1.1 jmcneill return 0; 361 1.1 jmcneill } 362 1.1 jmcneill 363 1.23 jmcneill static void 364 1.23 jmcneill dump_header_arm64(struct arm64_image_header *hdr) 365 1.23 jmcneill { 366 1.23 jmcneill printf(" magic: 0x%" PRIx32 "\n", le32toh(hdr->magic)); 367 1.23 jmcneill printf(" text offset: 0x%" PRIx64 "\n", le64toh(hdr->text_offset)); 368 1.23 jmcneill printf(" image size: %" PRIu64 "\n", le64toh(hdr->image_size)); 369 1.23 jmcneill printf(" flags: 0x%" PRIx64 "\n", le64toh(hdr->flags)); 370 1.23 jmcneill } 371 1.23 jmcneill 372 1.1 jmcneill static int 373 1.23 jmcneill generate_header_arm64(struct arm64_image_header *hdr, int kernel_fd) 374 1.23 jmcneill { 375 1.23 jmcneill struct stat st; 376 1.23 jmcneill uint32_t flags; 377 1.23 jmcneill int error; 378 1.23 jmcneill 379 1.23 jmcneill error = fstat(kernel_fd, &st); 380 1.23 jmcneill if (error == -1) { 381 1.23 jmcneill perror("stat"); 382 1.23 jmcneill return errno; 383 1.23 jmcneill } 384 1.23 jmcneill 385 1.23 jmcneill flags = 0; 386 1.24 jmcneill flags |= ARM64_FLAGS_PAGE_SIZE_4K; 387 1.23 jmcneill #if 0 388 1.24 jmcneill flags |= ARM64_FLAGS_PHYS_PLACEMENT_ANY; 389 1.23 jmcneill #endif 390 1.23 jmcneill 391 1.28 skrll const uint64_t dsize = update_image ? 392 1.30 ryo (uint64_t)st.st_size : (uint64_t)st.st_size + sizeof(*hdr); 393 1.28 skrll 394 1.23 jmcneill memset(hdr, 0, sizeof(*hdr)); 395 1.23 jmcneill hdr->code0 = htole32(ARM64_CODE0); 396 1.23 jmcneill hdr->text_offset = htole64(image_entrypoint); 397 1.28 skrll hdr->image_size = htole64(dsize); 398 1.23 jmcneill hdr->flags = htole32(flags); 399 1.23 jmcneill hdr->magic = htole32(ARM64_MAGIC); 400 1.23 jmcneill 401 1.23 jmcneill dump_header_arm64(hdr); 402 1.23 jmcneill 403 1.23 jmcneill return 0; 404 1.23 jmcneill } 405 1.23 jmcneill 406 1.23 jmcneill static int 407 1.23 jmcneill write_image(void *hdr, size_t hdrlen, int kernel_fd, int image_fd) 408 1.1 jmcneill { 409 1.1 jmcneill uint8_t buf[4096]; 410 1.1 jmcneill ssize_t rlen, wlen; 411 1.17 jmcneill struct stat st; 412 1.17 jmcneill uint32_t size_buf[2]; 413 1.17 jmcneill int error; 414 1.17 jmcneill 415 1.17 jmcneill error = fstat(kernel_fd, &st); 416 1.17 jmcneill if (error == -1) { 417 1.17 jmcneill perror("stat"); 418 1.17 jmcneill return errno; 419 1.17 jmcneill } 420 1.1 jmcneill 421 1.23 jmcneill wlen = write(image_fd, hdr, hdrlen); 422 1.23 jmcneill if (wlen != (ssize_t)hdrlen) { 423 1.1 jmcneill perror("short write"); 424 1.1 jmcneill return errno; 425 1.1 jmcneill } 426 1.1 jmcneill 427 1.17 jmcneill if (image_type == IH_TYPE_SCRIPT) { 428 1.34 gutterid size_buf[0] = htobe32(st.st_size); 429 1.34 gutterid size_buf[1] = htobe32(0); 430 1.17 jmcneill wlen = write(image_fd, &size_buf, sizeof(size_buf)); 431 1.17 jmcneill if (wlen != sizeof(size_buf)) { 432 1.17 jmcneill perror("short write"); 433 1.17 jmcneill return errno; 434 1.17 jmcneill } 435 1.17 jmcneill } 436 1.17 jmcneill 437 1.25 jmcneill if (update_image) { 438 1.26 jmcneill if (lseek(kernel_fd, hdrlen, SEEK_SET) != (off_t)hdrlen) { 439 1.25 jmcneill perror("seek failed"); 440 1.25 jmcneill return errno; 441 1.25 jmcneill } 442 1.25 jmcneill } 443 1.25 jmcneill 444 1.1 jmcneill while ((rlen = read(kernel_fd, buf, sizeof(buf))) > 0) { 445 1.1 jmcneill wlen = write(image_fd, buf, rlen); 446 1.1 jmcneill if (wlen != rlen) { 447 1.1 jmcneill perror("short write"); 448 1.1 jmcneill return errno; 449 1.1 jmcneill } 450 1.1 jmcneill } 451 1.1 jmcneill 452 1.1 jmcneill return 0; 453 1.1 jmcneill } 454 1.1 jmcneill 455 1.1 jmcneill int 456 1.1 jmcneill main(int argc, char *argv[]) 457 1.1 jmcneill { 458 1.23 jmcneill struct uboot_image_header hdr_uimg; 459 1.23 jmcneill struct arm64_image_header hdr_arm64; 460 1.1 jmcneill const char *src, *dest; 461 1.1 jmcneill char *ep; 462 1.1 jmcneill int kernel_fd, image_fd; 463 1.1 jmcneill int ch; 464 1.15 matt unsigned long long num; 465 1.31 christos time_t repro_time = 0; 466 1.1 jmcneill 467 1.31 christos while ((ch = getopt(argc, argv, "A:C:E:O:T:a:e:f:hm:n:t:u")) != -1) { 468 1.1 jmcneill switch (ch) { 469 1.1 jmcneill case 'A': /* arch */ 470 1.1 jmcneill image_arch = get_arch(optarg); 471 1.1 jmcneill break; 472 1.1 jmcneill case 'C': /* comp */ 473 1.1 jmcneill image_comp = get_comp(optarg); 474 1.1 jmcneill break; 475 1.6 phx case 'O': /* os */ 476 1.6 phx image_os = get_os(optarg); 477 1.6 phx break; 478 1.1 jmcneill case 'T': /* type */ 479 1.1 jmcneill image_type = get_type(optarg); 480 1.1 jmcneill break; 481 1.1 jmcneill case 'a': /* addr */ 482 1.1 jmcneill errno = 0; 483 1.15 matt num = strtoull(optarg, &ep, 0); 484 1.1 jmcneill if (*ep != '\0' || (errno == ERANGE && 485 1.15 matt (num == ULLONG_MAX || num == 0)) || 486 1.16 matt ((signed long long)num != (int32_t)num && 487 1.16 matt num != (uint32_t)num)) 488 1.1 jmcneill errx(1, "illegal number -- %s", optarg); 489 1.1 jmcneill image_loadaddr = (uint32_t)num; 490 1.1 jmcneill break; 491 1.9 matt case 'E': /* ep (byte swapped) */ 492 1.1 jmcneill case 'e': /* ep */ 493 1.1 jmcneill errno = 0; 494 1.15 matt num = strtoull(optarg, &ep, 0); 495 1.1 jmcneill if (*ep != '\0' || (errno == ERANGE && 496 1.15 matt (num == ULLONG_MAX || num == 0)) || 497 1.16 matt ((signed long long)num != (int32_t)num && 498 1.16 matt num != (uint32_t)num)) 499 1.1 jmcneill errx(1, "illegal number -- %s", optarg); 500 1.1 jmcneill image_entrypoint = (uint32_t)num; 501 1.9 matt if (ch == 'E') 502 1.9 matt image_entrypoint = bswap32(image_entrypoint); 503 1.1 jmcneill break; 504 1.23 jmcneill case 'f': /* image format */ 505 1.23 jmcneill image_format = get_image_format(optarg); 506 1.23 jmcneill break; 507 1.8 riz case 'm': /* magic */ 508 1.8 riz errno = 0; 509 1.8 riz num = strtoul(optarg, &ep, 0); 510 1.8 riz if (*ep != '\0' || (errno == ERANGE && 511 1.8 riz (num == ULONG_MAX || num == 0))) 512 1.8 riz errx(1, "illegal number -- %s", optarg); 513 1.8 riz image_magic = (uint32_t)num; 514 1.22 jmcneill break; 515 1.1 jmcneill case 'n': /* name */ 516 1.1 jmcneill image_name = strdup(optarg); 517 1.1 jmcneill break; 518 1.31 christos case 't': /* FS timestamp */ 519 1.31 christos repro_time = atoll(optarg); 520 1.31 christos break; 521 1.25 jmcneill case 'u': /* update image */ 522 1.25 jmcneill update_image = 1; 523 1.25 jmcneill break; 524 1.1 jmcneill case 'h': 525 1.1 jmcneill default: 526 1.1 jmcneill usage(); 527 1.1 jmcneill /* NOTREACHED */ 528 1.1 jmcneill } 529 1.1 jmcneill } 530 1.1 jmcneill argc -= optind; 531 1.1 jmcneill argv += optind; 532 1.1 jmcneill 533 1.1 jmcneill if (argc != 2) 534 1.1 jmcneill usage(); 535 1.1 jmcneill 536 1.4 kiyohara if (image_entrypoint == 0) 537 1.4 kiyohara image_entrypoint = image_loadaddr; 538 1.4 kiyohara 539 1.23 jmcneill switch (image_format) { 540 1.23 jmcneill case FMT_UIMG: 541 1.23 jmcneill if (image_arch == IH_ARCH_UNKNOWN || 542 1.23 jmcneill image_type == IH_TYPE_UNKNOWN || 543 1.23 jmcneill image_name == NULL) 544 1.23 jmcneill usage(); 545 1.23 jmcneill /* NOTREACHED */ 546 1.1 jmcneill 547 1.23 jmcneill switch (image_type) { 548 1.23 jmcneill case IH_TYPE_SCRIPT: 549 1.23 jmcneill case IH_TYPE_RAMDISK: 550 1.23 jmcneill case IH_TYPE_KERNEL_NOLOAD: 551 1.23 jmcneill break; 552 1.23 jmcneill default: 553 1.23 jmcneill if (image_loadaddr == 0) 554 1.23 jmcneill usage(); 555 1.23 jmcneill /* NOTREACHED */ 556 1.23 jmcneill break; 557 1.23 jmcneill } 558 1.20 jmcneill break; 559 1.23 jmcneill 560 1.23 jmcneill case FMT_ARM64: 561 1.23 jmcneill if (image_arch != IH_ARCH_UNKNOWN && 562 1.23 jmcneill image_arch != IH_ARCH_ARM64) 563 1.20 jmcneill usage(); 564 1.20 jmcneill /* NOTREACHED */ 565 1.23 jmcneill 566 1.20 jmcneill break; 567 1.23 jmcneill 568 1.23 jmcneill default: 569 1.23 jmcneill usage(); 570 1.23 jmcneill /* NOTREACHED */ 571 1.20 jmcneill } 572 1.20 jmcneill 573 1.1 jmcneill src = argv[0]; 574 1.1 jmcneill dest = argv[1]; 575 1.1 jmcneill 576 1.1 jmcneill kernel_fd = open(src, O_RDONLY); 577 1.1 jmcneill if (kernel_fd == -1) { 578 1.1 jmcneill perror("open kernel"); 579 1.1 jmcneill return EXIT_FAILURE; 580 1.1 jmcneill } 581 1.11 matt image_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0666); 582 1.1 jmcneill if (image_fd == -1) { 583 1.1 jmcneill perror("open image"); 584 1.1 jmcneill return EXIT_FAILURE; 585 1.1 jmcneill } 586 1.1 jmcneill 587 1.23 jmcneill printf(" image type: %s\n", get_image_format_name(image_format)); 588 1.23 jmcneill 589 1.23 jmcneill switch (image_format) { 590 1.23 jmcneill case FMT_UIMG: 591 1.31 christos if (generate_header_uimg(&hdr_uimg, repro_time, kernel_fd) != 0) 592 1.23 jmcneill return EXIT_FAILURE; 593 1.23 jmcneill 594 1.23 jmcneill if (write_image(&hdr_uimg, sizeof(hdr_uimg), 595 1.23 jmcneill kernel_fd, image_fd) != 0) 596 1.23 jmcneill return EXIT_FAILURE; 597 1.23 jmcneill 598 1.23 jmcneill break; 599 1.23 jmcneill case FMT_ARM64: 600 1.23 jmcneill if (generate_header_arm64(&hdr_arm64, kernel_fd) != 0) 601 1.23 jmcneill return EXIT_FAILURE; 602 1.23 jmcneill 603 1.23 jmcneill if (write_image(&hdr_arm64, sizeof(hdr_arm64), 604 1.23 jmcneill kernel_fd, image_fd) != 0) 605 1.23 jmcneill return EXIT_FAILURE; 606 1.1 jmcneill 607 1.23 jmcneill break; 608 1.23 jmcneill default: 609 1.23 jmcneill break; 610 1.23 jmcneill } 611 1.1 jmcneill 612 1.1 jmcneill close(image_fd); 613 1.1 jmcneill close(kernel_fd); 614 1.1 jmcneill 615 1.1 jmcneill return EXIT_SUCCESS; 616 1.1 jmcneill } 617