ramips: Add a tool to create JCG factory images
[openwrt.git] / tools / firmware-utils / src / jcgimage.c
index c98b0b5..7755eab 100644 (file)
 /*
  * JCG Firmware image header
  */
-#define JH_MAGIC 0x59535a4a    /* "YSZJ" */
+#define JH_MAGIC 0x59535a4a        /* "YSZJ" */
 struct jcg_header {
-    uint32_t jh_magic;
-    uint8_t  jh_version[32];   /* Firmware version string. Fill with
-                                 zeros to avoid encryption */
-    uint32_t jh_type;          /* must be 1 */
-    uint8_t  jh_info[64];      /* Firmware info string. Fill with
-                                 zeros to avoid encryption */
-    uint32_t jh_time;          /* Image creation time in seconds since
-                               * the Epoch. Does not seem to be used
-                               * by the stock firmware. */
-    uint16_t jh_major;         /* Major fimware version */
-    uint16_t jh_minor;         /* Minor fimrmware version */
-    uint8_t  jh_unknown[392];  /* Apparently unused and all zeros */
-    uint32_t jh_dcrc;          /* CRC checksum of the payload */
-    uint32_t jh_hcrc;          /* CRC checksum of the header */
+       uint32_t jh_magic;
+       uint8_t  jh_version[32];   /* Firmware version string.
+                                     Fill with zeros to avoid encryption  */
+       uint32_t jh_type;          /* must be 1                            */
+       uint8_t  jh_info[64];      /* Firmware info string. Fill with
+                                     zeros to avoid encryption            */
+       uint32_t jh_time;          /* Image creation time in seconds since
+                                   * the Epoch. Does not seem to be used
+                                   * by the stock firmware.               */
+       uint16_t jh_major;         /* Major fimware version                */
+       uint16_t jh_minor;         /* Minor fimrmware version              */
+       uint8_t  jh_unknown[392];  /* Apparently unused and all zeros      */
+       uint32_t jh_dcrc;          /* CRC checksum of the payload          */
+       uint32_t jh_hcrc;          /* CRC checksum of the header           */
 };
 
 /*
@@ -122,19 +122,21 @@ struct jcg_header {
 #define IH_NMLEN    28            /* Image Name Length      */
 
 struct uimage_header {
-    uint32_t    ih_magic;         /* Image Header Magic Number */
-    uint32_t    ih_hcrc;          /* Image Header CRC Checksum */
-    uint32_t    ih_time;          /* Image Creation Timestamp  */
-    uint32_t    ih_size;          /* Image Data Size           */
-    uint32_t    ih_load;          /* Data     Load  Address    */
-    uint32_t    ih_ep;            /* Entry Point Address       */
-    uint32_t    ih_dcrc;          /* Image Data CRC Checksum   */
-    uint8_t     ih_os;            /* Operating System          */
-    uint8_t     ih_arch;          /* CPU architecture          */
-    uint8_t     ih_type;          /* Image Type                */
-    uint8_t     ih_comp;          /* Compression Type          */
-    uint8_t     ih_name[IH_NMLEN];/* Image Name                */
-    uint32_t    ih_fsoff;         /* Offset of the file system partition */
+       uint32_t    ih_magic;         /* Image Header Magic Number   */
+       uint32_t    ih_hcrc;          /* Image Header CRC Checksum   */
+       uint32_t    ih_time;          /* Image Creation Timestamp    */
+       uint32_t    ih_size;          /* Image Data Size             */
+       uint32_t    ih_load;          /* Data     Load  Address      */
+       uint32_t    ih_ep;            /* Entry Point Address         */
+       uint32_t    ih_dcrc;          /* Image Data CRC Checksum     */
+       uint8_t     ih_os;            /* Operating System            */
+       uint8_t     ih_arch;          /* CPU architecture            */
+       uint8_t     ih_type;          /* Image Type                  */
+       uint8_t     ih_comp;          /* Compression Type            */
+       uint8_t     ih_name[IH_NMLEN];/* Image Name                  */
+       uint32_t    ih_fsoff;         /* Offset of the file system
+                                        partition from the start of
+                                        the header                  */
 };
 
 /*
@@ -144,16 +146,16 @@ struct uimage_header {
 int
 opensize(char *name, size_t *size)
 {
-    struct stat s;
-    int fd = open(name, O_RDONLY);
-    if (fd < 0) {
-       err(1, "cannot open \"%s\"", name);
-    }
-    if (fstat(fd, &s) == -1) {
-       err(1, "cannot stat \"%s\"", name);
-    }
-    *size = s.st_size;
-    return fd;
+       struct stat s;
+       int fd = open(name, O_RDONLY);
+       if (fd < 0) {
+               err(1, "cannot open \"%s\"", name);
+       }
+       if (fstat(fd, &s) == -1) {
+               err(1, "cannot stat \"%s\"", name);
+       }
+       *size = s.st_size;
+       return fd;
 }
 
 /*
@@ -162,32 +164,32 @@ opensize(char *name, size_t *size)
 void
 mkjcgheader(struct jcg_header *h, size_t psize, char *version)
 {
-    uLong crc;
-    uint16_t major = 0, minor = 0;
-    void *payload = (void *)h + sizeof(*h);
+       uLong crc;
+       uint16_t major = 0, minor = 0;
+       void *payload = (void *)h + sizeof(*h);
 
-    if (version != NULL) {
-       if (sscanf(version, "%hu.%hu", &major, &minor) != 2) {
-           err(1, "cannot parse version \"%s\"", version);
+       if (version != NULL) {
+               if (sscanf(version, "%hu.%hu", &major, &minor) != 2) {
+                       err(1, "cannot parse version \"%s\"", version);
+               }
        }
-    }
 
-    memset(h, 0, sizeof(*h));
-    h->jh_magic = htonl(JH_MAGIC);
-    h->jh_type  = htonl(1);
-    h->jh_time  = htonl(time(NULL));
-    h->jh_major = htons(major);
-    h->jh_minor = htons(minor);
+       memset(h, 0, sizeof(*h));
+       h->jh_magic = htonl(JH_MAGIC);
+       h->jh_type  = htonl(1);
+       h->jh_time  = htonl(time(NULL));
+       h->jh_major = htons(major);
+       h->jh_minor = htons(minor);
 
-    /* CRC over JCG payload (uImage) */
-    crc = crc32(0L, Z_NULL, 0);
-    crc = crc32(crc, payload, psize);
-    h->jh_dcrc  = htonl(crc);
+       /* CRC over JCG payload (uImage) */
+       crc = crc32(0L, Z_NULL, 0);
+       crc = crc32(crc, payload, psize);
+       h->jh_dcrc  = htonl(crc);
 
-    /* CRC over JCG header */
-    crc = crc32(0L, Z_NULL, 0);
-    crc = crc32(crc, (void *)h, sizeof(*h));
-    h->jh_hcrc  = htonl(crc);
+       /* CRC over JCG header */
+       crc = crc32(0L, Z_NULL, 0);
+       crc = crc32(crc, (void *)h, sizeof(*h));
+       h->jh_hcrc  = htonl(crc);
 }
 
 /*
@@ -196,34 +198,34 @@ mkjcgheader(struct jcg_header *h, size_t psize, char *version)
 void
 mkuheader(struct uimage_header *h, size_t ksize, size_t fsize)
 {
-    uLong crc;
-    void *payload = (void *)h + sizeof(*h);
+       uLong crc;
+       void *payload = (void *)h + sizeof(*h);
 
-    // printf("mkuheader: %p, %zd, %zd\n", h, ksize, fsize);
-    memset(h, 0, sizeof(*h));
-    h->ih_magic = htonl(IH_MAGIC);
-    h->ih_time  = htonl(time(NULL));
-    h->ih_size  = htonl(ksize + fsize);
-    h->ih_load  = htonl(0x80000000);
-    h->ih_ep    = htonl(0x80292000);
-    h->ih_os    = 0x05;
-    h->ih_arch  = 0x05;
-    h->ih_type  = 0x02;
-    h->ih_comp  = 0x03;
-    h->ih_fsoff = htonl(sizeof(*h) + ksize);
-    strcpy((char *)h->ih_name, "Linux Kernel Image");
+       // printf("mkuheader: %p, %zd, %zd\n", h, ksize, fsize);
+       memset(h, 0, sizeof(*h));
+       h->ih_magic = htonl(IH_MAGIC);
+       h->ih_time  = htonl(time(NULL));
+       h->ih_size  = htonl(ksize + fsize);
+       h->ih_load  = htonl(0x80000000);
+       h->ih_ep    = htonl(0x80292000);
+       h->ih_os    = 0x05;
+       h->ih_arch  = 0x05;
+       h->ih_type  = 0x02;
+       h->ih_comp  = 0x03;
+       h->ih_fsoff = htonl(sizeof(*h) + ksize);
+       strcpy((char *)h->ih_name, "Linux Kernel Image");
 
-    /* CRC over uImage payload (kernel and file system) */
-    crc = crc32(0L, Z_NULL, 0);
-    crc = crc32(crc, payload, ntohl(h->ih_size));
-    h->ih_dcrc  = htonl(crc);
-    printf("CRC1: %08lx\n", crc);
+       /* CRC over uImage payload (kernel and file system) */
+       crc = crc32(0L, Z_NULL, 0);
+       crc = crc32(crc, payload, ntohl(h->ih_size));
+       h->ih_dcrc  = htonl(crc);
+       printf("CRC1: %08lx\n", crc);
 
-    /* CRC over uImage header */
-    crc = crc32(0L, Z_NULL, 0);
-    crc = crc32(crc, (void *)h, sizeof(*h));
-    h->ih_hcrc  = htonl(crc);
-    printf("CRC2: %08lx\n", crc);
+       /* CRC over uImage header */
+       crc = crc32(0L, Z_NULL, 0);
+       crc = crc32(crc, (void *)h, sizeof(*h));
+       h->ih_hcrc  = htonl(crc);
+       printf("CRC2: %08lx\n", crc);
 }
 
 /*
@@ -237,42 +239,43 @@ mkuheader(struct uimage_header *h, size_t ksize, size_t fsize)
 void
 craftcrc(uint32_t dcrc, uint8_t *buf, size_t len)
 {
-    int i;
-    uint32_t a;
-    uint32_t patch = 0;
-    uint32_t crc = crc32(0L, Z_NULL, 0);
+       int i;
+       uint32_t a;
+       uint32_t patch = 0;
+       uint32_t crc = crc32(0L, Z_NULL, 0);
 
-    a = ~dcrc;
-    for (i = 0; i < 32; i++) {
-       if (patch & 1) {
-           patch = (patch >> 1) ^ 0xedb88320L;
-       } else {
-           patch >>= 1;
+       a = ~dcrc;
+       for (i = 0; i < 32; i++) {
+               if (patch & 1) {
+                       patch = (patch >> 1) ^ 0xedb88320L;
+               } else {
+                       patch >>= 1;
+               }
+               if (a & 1) {
+                       patch ^= 0x5b358fd3L;
+               }
+               a >>= 1;
        }
-       if (a & 1) {
-           patch ^= 0x5b358fd3L;
+       patch ^= ~crc32(crc, buf, len - 4);
+       for (i = 0; i < 4; i++) {
+               buf[len - 4 + i] = patch & 0xff;
+               patch >>= 8;
+       }
+       /* Verify that we actually get the desired result */
+       crc = crc32(0L, Z_NULL, 0);
+       crc = crc32(crc, buf, len);
+       if (crc != dcrc) {
+               errx(1, "CRC patching is broken: wanted %08x, but got %08x.",
+                    dcrc, crc);
        }
-       a >>= 1;
-    }
-    patch ^= ~crc32(crc, buf, len - 4);
-    for (i = 0; i < 4; i++) {
-       buf[len - 4 + i] = patch & 0xff;
-       patch >>= 8;
-    }
-    /* Verify that we actually get the desired result */
-    crc = crc32(0L, Z_NULL, 0);
-    crc = crc32(crc, buf, len);
-    if (crc != dcrc) {
-       errx(1, "CRC patching is broken: wanted %08x, but got %08x.", dcrc, crc);
-    }
 }
 
 void
 usage() {
-    fprintf(stderr, "Usage:\n"
-           "   jcgimage -o outputfile -u uImage [-v version]\n"
-           "   jcgimage -o outputfile -k kernel -f rootfs [-v version]\n");
-    exit(1);
+       fprintf(stderr, "Usage:\n"
+               "jcgimage -o outfile -u uImage [-v version]\n"
+               "jcgimage -o outfile -k kernel -f rootfs [-v version]\n");
+       exit(1);
 }
 
 #define MODE_UNKNOWN 0
@@ -285,108 +288,116 @@ usage() {
 int
 main(int argc, char **argv)
 {
-    struct jcg_header *jh;
-    struct uimage_header *uh;
-    int c;
-    char *imagefile = NULL;
-    char *file1 = NULL;
-    char *file2 = NULL;
-    char *version = NULL;
-    int mode = MODE_UNKNOWN;
-    int fdo, fd1, fd2;
-    size_t size1, size2, sizeu, sizeo, off1, off2;
-    void *map;
+       struct jcg_header *jh;
+       struct uimage_header *uh;
+       int c;
+       char *imagefile = NULL;
+       char *file1 = NULL;
+       char *file2 = NULL;
+       char *version = NULL;
+       int mode = MODE_UNKNOWN;
+       int fdo, fd1, fd2;
+       size_t size1, size2, sizeu, sizeo, off1, off2;
+       void *map;
 
-    /* Make sure the headers have the right size */
-    assert(sizeof(struct jcg_header) == 512);
-    assert(sizeof(struct uimage_header) == 64);
+       /* Make sure the headers have the right size */
+       assert(sizeof(struct jcg_header) == 512);
+       assert(sizeof(struct uimage_header) == 64);
 
-    while ((c = getopt(argc, argv, "o:k:f:u:v:h")) != -1) {
-       switch (c) {
-       case 'o':
-           imagefile = optarg;
-           break;
-       case 'k':
-           if (mode == MODE_UIMAGE)
-               errx(1,"-k cannot be combined with -u");
-           mode = MODE_KR;
-           file1 = optarg;
-           break;
-       case 'f':
-           if (mode == MODE_UIMAGE)
-               errx(1,"-f cannot be combined with -u");
-           mode = MODE_KR;
-           file2 = optarg;
-           break;
-       case 'u':
-           if (mode == MODE_KR)
-               errx(1,"-u cannot be combined with -k and -r");
-           mode = MODE_UIMAGE;
-           file1 = optarg;
-           break;
-       case 'v':
-           version = optarg;
-           break;
-       case 'h':
-       default:
-           usage();
+       while ((c = getopt(argc, argv, "o:k:f:u:v:h")) != -1) {
+               switch (c) {
+               case 'o':
+                       imagefile = optarg;
+                       break;
+               case 'k':
+                       if (mode == MODE_UIMAGE) {
+                               errx(1,"-k cannot be combined with -u");
+                       }
+                       mode = MODE_KR;
+                       file1 = optarg;
+                       break;
+               case 'f':
+                       if (mode == MODE_UIMAGE) {
+                               errx(1,"-f cannot be combined with -u");
+                       }
+                       mode = MODE_KR;
+                       file2 = optarg;
+                       break;
+               case 'u':
+                       if (mode == MODE_KR) {
+                               errx(1,"-u cannot be combined with -k and -r");
+                       }
+                       mode = MODE_UIMAGE;
+                       file1 = optarg;
+                       break;
+               case 'v':
+                       version = optarg;
+                       break;
+               case 'h':
+               default:
+                       usage();
+               }
+       }
+       if (optind != argc) {
+               errx(1, "illegal arg \"%s\"", argv[optind]);
+       }
+       if (imagefile == NULL) {
+               errx(1, "no output file specified");
+       }
+       if (mode == MODE_UNKNOWN) {
+               errx(1, "specify either -u or -k and -r");
+       }
+       if (mode == MODE_KR) {
+               if (file1 == NULL || file2 == NULL) {
+                       errx(1,"need -k and -r");
+               }
+               fd2 = opensize(file2, &size2);
+       }
+       fd1 = opensize(file1, &size1);
+       if (mode == MODE_UIMAGE) {
+               off1 = sizeof(*jh);
+               sizeu = size1 + 4;
+               sizeo = sizeof(*jh) + sizeu;
+       } else {
+               off1 = sizeof(*jh) + sizeof(*uh);
+               off2 = sizeof(*jh) + sizeof(*uh) + size1;
+               sizeu = sizeof(*uh) + size1 + size2;
+               sizeo = sizeof(*jh) + sizeu;
        }
-    }
-    if (optind != argc) {
-       errx(1, "illegal arg \"%s\"", argv[optind]);
-    }
-    if (imagefile == NULL) {
-       errx(1, "no output file specified");
-    }
-    if (mode == MODE_UNKNOWN)
-       errx(1, "specify either -u or -k and -r");
-    if (mode == MODE_KR) {
-       if (file1 == NULL || file2 == NULL)
-           errx(1,"need -k and -r");
-       fd2 = opensize(file2, &size2);
-    }
-    fd1 = opensize(file1, &size1);
-    if (mode == MODE_UIMAGE) {
-       off1 = sizeof(*jh);
-       sizeu = size1 + 4;
-       sizeo = sizeof(*jh) + sizeu;
-    } else {
-       off1 = sizeof(*jh) + sizeof(*uh);
-       off2 = sizeof(*jh) + sizeof(*uh) + size1;
-       sizeu = sizeof(*uh) + size1 + size2;
-       sizeo = sizeof(*jh) + sizeu;
-    }
 
-    if (sizeo > MAXSIZE)
-       errx(1,"payload too large: %zd > %zd\n", sizeo, MAXSIZE);
+       if (sizeo > MAXSIZE) {
+               errx(1,"payload too large: %zd > %zd\n", sizeo, MAXSIZE);
+       }
 
-    fdo = open(imagefile, O_RDWR | O_CREAT | O_TRUNC, 00644);
-    if (fdo < 0)
-       err(1, "cannot open \"%s\"", imagefile);
+       fdo = open(imagefile, O_RDWR | O_CREAT | O_TRUNC, 00644);
+       if (fdo < 0) {
+               err(1, "cannot open \"%s\"", imagefile);
+       }
 
-    if (ftruncate(fdo, sizeo) == -1) {
-       err(1, "cannot grow \"%s\" to %zd bytes", imagefile, sizeo);
-    }
-    map = mmap(NULL, sizeo, PROT_READ|PROT_WRITE, MAP_SHARED, fdo, 0);
-    uh = map + sizeof(*jh);
-    if (map == MAP_FAILED) {
-       err(1, "cannot mmap \"%s\"", imagefile);
-    }
+       if (ftruncate(fdo, sizeo) == -1) {
+               err(1, "cannot grow \"%s\" to %zd bytes", imagefile, sizeo);
+       }
+       map = mmap(NULL, sizeo, PROT_READ|PROT_WRITE, MAP_SHARED, fdo, 0);
+       uh = map + sizeof(*jh);
+       if (map == MAP_FAILED) {
+               err(1, "cannot mmap \"%s\"", imagefile);
+       }
 
-    if (read(fd1, map + off1, size1) != size1)
-       err(1, "cannot copy %s", file1);
+       if (read(fd1, map + off1, size1) != size1) {
+               err(1, "cannot copy %s", file1);
+       }
 
-    if (mode == MODE_KR) {
-       if (read(fd2, map+off2, size2) != size2)
-           err(1, "cannot copy %s", file2);
-       mkuheader(uh, size1, size2);
-    } else if (mode == MODE_UIMAGE) {
-       craftcrc(ntohl(uh->ih_dcrc), (void*)uh + sizeof(*uh),
-                sizeu - sizeof(*uh));
-    }
-    mkjcgheader(map, sizeu, version);
-    munmap(map, sizeo);
-    close(fdo);
-    return 0;
+       if (mode == MODE_KR) {
+               if (read(fd2, map+off2, size2) != size2) {
+                       err(1, "cannot copy %s", file2);
+               }
+               mkuheader(uh, size1, size2);
+       } else if (mode == MODE_UIMAGE) {
+               craftcrc(ntohl(uh->ih_dcrc), (void*)uh + sizeof(*uh),
+                        sizeu - sizeof(*uh));
+       }
+       mkjcgheader(map, sizeu, version);
+       munmap(map, sizeo);
+       close(fdo);
+       return 0;
 }
-