firmware-utils: mktplinkfw: add option for endianness swap
[openwrt/openwrt.git] / tools / firmware-utils / src / zyxbcm.c
1 /*
2 * zyxbcm.c - based on Jonas Gorski's spw303v.c
3 *
4 * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <arpa/inet.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28
29 #define TAGVER_LEN 4 /* Length of Tag Version */
30 #define SIG1_LEN 20 /* Company Signature 1 Length */
31 #define SIG2_LEN 14 /* Company Signature 2 Lenght */
32 #define BOARDID_LEN 16 /* Length of BoardId */
33 #define ENDIANFLAG_LEN 2 /* Endian Flag Length */
34 #define CHIPID_LEN 6 /* Chip Id Length */
35 #define IMAGE_LEN 10 /* Length of Length Field */
36 #define ADDRESS_LEN 12 /* Length of Address field */
37 #define DUALFLAG_LEN 2 /* Dual Image flag Length */
38 #define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */
39 #define RSASIG_LEN 20 /* Length of RSA Signature in tag */
40 #define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */
41 #define ZYX_TAGINFO1_LEN 20 /* Length of vendor information field1 in tag */
42 #define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */
43 #define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */
44 #define CRC_LEN 4 /* Length of CRC in bytes */
45
46 #define IMAGETAG_CRC_START 0xFFFFFFFF
47
48 struct bcm_tag {
49 char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag
50 char sig_1[SIG1_LEN]; // 4-23: Company Line 1
51 char sig_2[SIG2_LEN]; // 24-37: Company Line 2
52 char chipid[CHIPID_LEN]; // 38-43: Chip this image is for
53 char boardid[BOARDID_LEN]; // 44-59: Board name
54 char big_endian[ENDIANFLAG_LEN]; // 60-61: Map endianness -- 1 BE 0 LE
55 char totalLength[IMAGE_LEN]; // 62-71: Total length of image
56 char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE
57 char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE
58 char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
59 char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs for flashing
60 char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel
61 char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel
62 char dualImage[DUALFLAG_LEN]; // 138-139: Unused at present
63 char inactiveFlag[INACTIVEFLAG_LEN]; // 140-141: Unused at present
64 char rsa_signature[RSASIG_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this)
65 char information1[TAGINFO1_LEN]; // 162-191: Compilation and related information (not generated/used by OpenWRT)
66 char flashLayoutVer[FLASHLAYOUTVER_LEN]; // 192-195: Version flash layout
67 char fskernelCRC[CRC_LEN]; // 196-199: kernel+rootfs CRC32
68 char information2[TAGINFO2_LEN]; // 200-215: Unused at present except Alice Gate where is is information
69 char imageCRC[CRC_LEN]; // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
70 char rootfsCRC[CRC_LEN]; // 220-223: CRC32 of rootfs partition
71 char kernelCRC[CRC_LEN]; // 224-227: CRC32 of kernel partition
72 char imageSequence[4]; // 228-231: Image sequence number
73 char rootLength[4]; // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
74 char headerCRC[CRC_LEN]; // 236-239: CRC32 of header excluding tagVersion
75 char reserved2[16]; // 240-255: Unused at present
76 };
77
78 struct zyxbcm_tag {
79 char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag
80 char sig_1[SIG1_LEN]; // 4-23: Company Line 1
81 char sig_2[SIG2_LEN]; // 24-37: Company Line 2
82 char chipid[CHIPID_LEN]; // 38-43: Chip this image is for
83 char boardid[BOARDID_LEN]; // 44-59: Board name
84 char big_endian[ENDIANFLAG_LEN]; // 60-61: Map endianness -- 1 BE 0 LE
85 char totalLength[IMAGE_LEN]; // 62-71: Total length of image
86 char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE
87 char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE
88 char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware)
89 char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs for flashing
90 char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel
91 char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel
92 char dualImage[DUALFLAG_LEN]; // 138-139: Unused at present
93 char inactiveFlag[INACTIVEFLAG_LEN]; // 140-141: Unused at present
94 char rsa_signature[RSASIG_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this)
95 char information1[ZYX_TAGINFO1_LEN]; // 162-181: Compilation and related information (not generated/used by OpenWRT)
96 char flashImageEnd[ADDRESS_LEN]; // 182-193: Address in memory of image end
97 char fskernelCRC[CRC_LEN]; // 194-197: kernel+rootfs CRC32
98 char reserved1[2]; // 198-199: Unused at present
99 char information2[TAGINFO2_LEN]; // 200-215: Unused at present except Alice Gate where is is information
100 char imageCRC[CRC_LEN]; // 216-219: CRC32 of image less imagetag (kernel for Alice Gate)
101 char rootfsCRC[CRC_LEN]; // 220-223: CRC32 of rootfs partition
102 char kernelCRC[CRC_LEN]; // 224-227: CRC32 of kernel partition
103 char imageSequence[4]; // 228-231: Image sequence number
104 char rootLength[4]; // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot
105 char headerCRC[CRC_LEN]; // 236-239: CRC32 of header excluding tagVersion
106 char reserved2[16]; // 240-255: Unused at present
107 };
108
109 static uint32_t crc32tab[256] = {
110 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
111 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
112 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
113 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
114 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
115 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
116 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
117 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
118 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
119 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
120 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
121 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
122 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
123 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
124 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
125 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
126 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
127 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
128 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
129 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
130 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
131 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
132 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
133 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
134 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
135 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
136 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
137 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
138 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
139 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
140 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
141 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
142 };
143
144 uint32_t crc32(uint32_t crc, uint8_t *data, size_t len)
145 {
146 while (len--)
147 crc = (crc >> 8) ^ crc32tab[(crc ^ *data++) & 0xFF];
148
149 return crc;
150 }
151
152 void fix_header(void *buf)
153 {
154 struct bcm_tag *bcmtag = buf;
155 struct zyxbcm_tag *zyxtag = buf;
156 uint8_t fskernel_crc[CRC_LEN];
157 uint32_t crc;
158 uint64_t flash_start, rootfs_len, kernel_len;
159
160 /* Backup values */
161 flash_start = strtoul(bcmtag->flashImageStart, NULL, 10);
162 rootfs_len = strtoul(bcmtag->flashRootLength, NULL, 10);
163 kernel_len = strtoul(bcmtag->kernelLength, NULL, 10);
164 memcpy(fskernel_crc, bcmtag->fskernelCRC, CRC_LEN);
165
166 /* Clear values */
167 zyxtag->information1[ZYX_TAGINFO1_LEN - 1] = 0;
168 memset(zyxtag->flashImageEnd, 0, ADDRESS_LEN);
169 memset(zyxtag->fskernelCRC, 0, CRC_LEN);
170 memset(zyxtag->reserved1, 0, 2);
171
172 /* Replace values */
173 sprintf(zyxtag->flashImageEnd, "%lu", flash_start + rootfs_len + kernel_len);
174 memcpy(zyxtag->fskernelCRC, fskernel_crc, CRC_LEN);
175
176 /* Update tag crc */
177 crc = htonl(crc32(IMAGETAG_CRC_START, buf, 236));
178 memcpy(zyxtag->headerCRC, &crc, 4);
179 }
180
181 void usage(void) __attribute__ (( __noreturn__ ));
182
183 void usage(void)
184 {
185 fprintf(stderr, "Usage: zyxbcm [-i <inputfile>] [-o <outputfile>]\n");
186 exit(EXIT_FAILURE);
187 }
188
189 int main(int argc, char **argv)
190 {
191 char buf[1024]; /* keep this at 1k or adjust garbage calc below */
192 FILE *in = stdin, *out = stdout;
193 char *ifn = NULL, *ofn = NULL;
194 size_t n;
195 int c, first_block = 1;
196
197 while ((c = getopt(argc, argv, "i:o:h")) != -1) {
198 switch (c) {
199 case 'i':
200 ifn = optarg;
201 break;
202 case 'o':
203 ofn = optarg;
204 break;
205 case 'h':
206 default:
207 usage();
208 }
209 }
210
211 if (optind != argc || optind == 1) {
212 fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
213 usage();
214 }
215
216 if (ifn && !(in = fopen(ifn, "r"))) {
217 fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
218 usage();
219 }
220
221 if (ofn && !(out = fopen(ofn, "w"))) {
222 fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
223 usage();
224 }
225
226 while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
227 if (n < sizeof(buf)) {
228 if (ferror(in)) {
229 FREAD_ERROR:
230 fprintf(stderr, "fread error\n");
231 return EXIT_FAILURE;
232 }
233 }
234
235 if (first_block && n >= 256) {
236 fix_header(buf);
237 first_block = 0;
238 }
239
240 if (!fwrite(buf, n, 1, out)) {
241 FWRITE_ERROR:
242 fprintf(stderr, "fwrite error\n");
243 return EXIT_FAILURE;
244 }
245 }
246
247 if (ferror(in)) {
248 goto FREAD_ERROR;
249 }
250
251 if (fflush(out)) {
252 goto FWRITE_ERROR;
253 }
254
255 fclose(in);
256 fclose(out);
257
258 return EXIT_SUCCESS;
259 }