tools: otrx: allow own magic
[project/firmware-utils.git] / src / mkdapimg2.c
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License,
4 * version 2 as published by the Free Software Foundation.
5 *
6 * (C) Nicolò Veronese <nicveronese@gmail.com>
7 */
8
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <libgen.h>
14 #include <stdarg.h>
15 #include <getopt.h>
16 #include <string.h>
17 #include <errno.h>
18
19 #include <netinet/in.h> // htonl
20
21 // Usage: mkdapimg2 -s signature [-v version] [-r region]
22 // [-k uImage block size] -i <input> -o <output>
23 //
24 // NOTE: The kernel block size is used to know the offset of the rootfs
25 // in the image file.
26 //
27 // The system writes in the uImage partition until the end of uImage
28 // is reached, after that, the system jumps to the offset specified with the -k
29 // parameter and begin writing at the beginning of the rootfs MTD partition.
30 //
31 // If the -k parameter is the size of the original uImage partition, the system
32 // continue writing in the rootfs partition starting from the last block
33 // that has been wrote. (This is useful if the new kernel size is
34 // different from the original one)
35 //
36 // Example:
37 // ------------------------------------------
38 // Creating 7 MTD partitions on "ath-nor0":
39 // 0x000000000000-0x000000010000 : "u-boot"
40 // 0x000000010000-0x000000020000 : "ART"
41 // 0x000000020000-0x000000030000 : "MP"
42 // 0x000000030000-0x000000040000 : "config"
43 // 0x000000040000-0x000000120000 : "uImage"
44 // 0x000000120000-0x000000800000 : "rootfs"
45 // 0x000000040000-0x000000800000 : "firmware"
46 // ------------------------------------------
47 //
48 // 0x000000120000-0x000000040000 = 0xE0000 -> 917504
49 //
50 // e.g.: mkdapimg2 -s HONEYBEE-FIRMWARE-DAP-1330 -v 1.00.21 -r Default
51 // -k 917504 -i sysupgrade.bin -o factory.bin
52 //
53 //
54 // The img_hdr_struct was taken from the D-Link SDK:
55 // DAP-1330_OSS-firmware_1.00b21/DAP-1330_OSS-firmware_1.00b21/uboot/uboot.patch
56
57 #define MAX_SIGN_LEN 32
58 #define MAX_FW_VER_LEN 16
59 #define MAX_REG_LEN 8
60
61 struct img_hdr_struct {
62 uint32_t hdr_len;
63 uint32_t checksum;
64 uint32_t total_size;
65 uint32_t kernel_size;
66 char signature[MAX_SIGN_LEN];
67 char fw_ver[MAX_FW_VER_LEN];
68 char fw_reg[MAX_REG_LEN];
69 } imghdr ;
70
71 char *progname;
72
73 void
74 perrexit(int code, char *msg)
75 {
76 fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno));
77 exit(code);
78 }
79
80 void
81 usage()
82 {
83 fprintf(stderr, "usage: %s -s signature [-v version] [-r region] [-k uImage part size] -i <input> -o <output>\n", progname);
84 exit(1);
85 }
86
87 int
88 main(int ac, char *av[])
89 {
90 char signature[MAX_SIGN_LEN];
91 char version[MAX_FW_VER_LEN];
92 char region[MAX_REG_LEN];
93 int kernel = 0;
94
95 FILE *ifile, *ofile;
96 int c;
97
98 uint32_t cksum;
99 uint32_t bcnt;
100
101 progname = basename(av[0]);
102
103 memset(signature, 0, sizeof(signature));
104 memset(version, 0, sizeof(version));
105 memset(region, 0, sizeof(region));
106
107 while ( 1 ) {
108 char *ptr;
109 int c;
110
111 c = getopt(ac, av, "s:v:r:k:i:o:");
112 if (c == -1)
113 break;
114
115 switch (c) {
116 case 's':
117 if (strlen(optarg) > MAX_SIGN_LEN + 1) {
118 fprintf(stderr, "%s: signature exceeds %d chars\n",
119 progname, MAX_SIGN_LEN);
120 exit(1);
121 }
122 strcpy(signature, optarg);
123 break;
124 case 'v':
125 if (strlen(optarg) > MAX_FW_VER_LEN + 1) {
126 fprintf(stderr, "%s: version exceeds %d chars\n",
127 progname, MAX_FW_VER_LEN);
128 exit(1);
129 }
130 strcpy(version, optarg);
131 break;
132 case 'r':
133 if (strlen(optarg) > MAX_REG_LEN + 1) {
134 fprintf(stderr, "%s: region exceeds %d chars\n",
135 progname, MAX_REG_LEN);
136 exit(1);
137 }
138 strcpy(region, optarg);
139 break;
140 case 'k':
141 kernel = strtoul(optarg, &ptr, 0);
142 if(ptr[0] == 'k'){
143 kernel *= 1000;
144 }
145 break;
146 case 'i':
147 if ((ifile = fopen(optarg, "r")) == NULL)
148 perrexit(1, optarg);
149 break;
150 case 'o':
151 if ((ofile = fopen(optarg, "w")) == NULL)
152 perrexit(1, optarg);
153 break;
154 default:
155 usage();
156 }
157 }
158
159 if (signature[0] == 0 || ifile == NULL || ofile == NULL) {
160 usage();
161 exit(1);
162 }
163
164 for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
165 cksum += c & 0xff;
166
167 if (fseek(ifile, 0, SEEK_SET) < 0)
168 perrexit(2, "fseek on input");
169
170 // Fill in the header
171 memset(&imghdr, 0, sizeof(imghdr));
172 imghdr.hdr_len = sizeof(imghdr);
173 imghdr.checksum = htonl(cksum);
174 imghdr.total_size = htonl(bcnt);
175 imghdr.kernel_size = htonl(kernel);
176
177 strncpy(imghdr.signature, signature, MAX_SIGN_LEN);
178 strncpy(imghdr.fw_ver, version, MAX_FW_VER_LEN);
179 strncpy(imghdr.fw_reg, region, MAX_REG_LEN);
180
181 if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0)
182 perrexit(2, "fwrite header on output");
183
184 while ((c = fgetc(ifile)) != EOF) {
185 if (fputc(c, ofile) == EOF)
186 perrexit(2, "fputc on output");
187 }
188
189 if (ferror(ifile))
190 perrexit(2, "fgetc on input");
191
192 fclose(ofile);
193 fclose(ifile);
194
195 fprintf(stderr, "imgHdr.hdr_len = %lu\n", sizeof(imghdr));
196 fprintf(stderr, "imgHdr.checksum = 0x%08x\n", cksum);
197 fprintf(stderr, "imgHdr.total_size = 0x%08x\n", bcnt);
198 fprintf(stderr, "imgHdr.kernel_size = 0x%08x\n", kernel);
199 fprintf(stderr, "imgHdr.header = %s\n", signature);
200 fprintf(stderr, "imgHdr.fw_ver = %s\n", version);
201 fprintf(stderr, "imgHdr.fw_reg = %s\n", region);
202
203 return 0;
204 }