firmware-utils: honor env SOURCE_DATE_EPOCH
[oweals/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 }