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