5fa323f2d55735634b2e5ab1a4412edb5ababd08
[openwrt/openwrt.git] / tools / firmware-utils / src / mksercommfw.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <byteswap.h>
8 #include <endian.h>
9 #include <getopt.h>
10
11 #if !defined(__BYTE_ORDER)
12 #error "Unknown byte order"
13 #endif
14
15 #if __BYTE_ORDER == __BIG_ENDIAN
16 #define cpu_to_be32(x) (x)
17 #elif __BYTE_ORDER == __LITTLE_ENDIAN
18 #define cpu_to_be32(x) bswap_32(x)
19 #else
20 #error "Unsupported endianness"
21 #endif
22
23 /* #define DEBUG 1 */
24
25 #ifdef DEBUG
26 #define DBG(...) {printf(__VA_ARGS__); }
27 #else
28 #define DBG(...) {}
29 #endif
30
31 #define ERR(...) {printf(__VA_ARGS__); }
32
33 /*
34 * Fw Header Layout for Netgear / Sercomm devices (bytes)
35 *
36 * Size : 512 bytes + zipped image size
37 *
38 * Locations:
39 * magic : 0-6 ASCII
40 * version: 7-11 fixed
41 * hwID : 11-44 ASCII
42 * hwVer : 45-54 ASCII
43 * swVer : 55-62 uint32_t in BE
44 * magic : 63-69 ASCII
45 * ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
46 */
47 static const char* magic = "sErCoMm"; /* 7 */
48 static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
49 static const int header_sz = 512;
50 static const int footer_sz = 71;
51
52 static int is_header = 1;
53
54 struct file_info {
55 char* file_name; /* name of the file */
56 char* file_data; /* data of the file in memory */
57 u_int32_t file_size; /* length of the file */
58 };
59
60 static u_int8_t getCheckSum(char* data, int len) {
61 u_int8_t new = 0;
62 int i;
63
64 if (!data) {
65 ERR("Invalid pointer provided!\n");
66 return 0;
67 }
68
69 for (i = 0; i < len; i++) {
70 new += data[i];
71 }
72
73 return new;
74 }
75
76 /*
77 * read file into buffer
78 * add space for header/footer
79 */
80 static int copyToOutputBuf(struct file_info* finfo) {
81 FILE* fp = NULL;
82
83 int file_sz = 0;
84 int extra_sz;
85 int hdr_pos;
86 int img_pos;
87
88 if (!finfo || !finfo->file_name) {
89 ERR("Invalid pointer provided!\n");
90 return -1;
91 }
92
93 DBG("Opening file: %s\n", finfo->file_name);
94
95 if (!(fp = fopen(finfo->file_name, "rb"))) {
96 ERR("Error opening file: %s\n", finfo->file_name);
97 return -1;
98 }
99
100 /* Get filesize */
101 rewind(fp);
102 fseek(fp, 0L, SEEK_END);
103 file_sz = ftell(fp);
104 rewind(fp);
105
106 if (file_sz < 1) {
107 ERR("Error getting filesize: %s\n", finfo->file_name);
108 fclose(fp);
109 return -1;
110 }
111
112 if (is_header) {
113 extra_sz = header_sz;
114 hdr_pos = 0;
115 img_pos = header_sz;
116 } else {
117 extra_sz = footer_sz;
118 hdr_pos = file_sz;
119 img_pos = 0;
120 }
121
122 DBG("Filesize: %i\n", file_sz);
123 finfo->file_size = file_sz + extra_sz;
124
125 if (!(finfo->file_data = malloc(finfo->file_size))) {
126 ERR("Out of memory!\n");
127 fclose(fp);
128 return -1;
129 }
130
131 /* init header/footer bytes */
132 memset(finfo->file_data + hdr_pos, 0, extra_sz);
133
134 /* read file and take care of leading header if exists */
135 if (fread(finfo->file_data + img_pos, 1, file_sz, fp) != file_sz) {
136 ERR("Error reading file %s\n", finfo->file_name);
137 fclose(fp);
138 return -1;
139 }
140
141 DBG("File: read successful\n");
142 fclose(fp);
143
144 return hdr_pos;
145 }
146
147 static int writeFile(struct file_info* finfo) {
148 FILE* fp;
149
150 if (!finfo || !finfo->file_name) {
151 ERR("Invalid pointer provided!\n");
152 return -1;
153 }
154
155 DBG("Opening file: %s\n", finfo->file_name);
156
157 if (!(fp = fopen(finfo->file_name, "w"))) {
158 ERR("Error opening file: %s\n", finfo->file_name);
159 return -1;
160 }
161
162 DBG("Writing file: %s\n", finfo->file_name);
163
164 if (fwrite(finfo->file_data, 1, finfo->file_size, fp) != finfo->file_size) {
165 ERR("Wanted to write, but something went wrong!\n");
166 fclose(fp);
167 return -1;
168 }
169
170 fclose(fp);
171 return 0;
172 }
173
174 static void usage(char* argv[]) {
175 printf("Usage: %s [OPTIONS...]\n"
176 "\n"
177 "Options:\n"
178 " -f add sercom footer (if absent, header)\n"
179 " -b <hwid> use hardware id specified with <hwid> (ASCII)\n"
180 " -r <hwrev> use hardware revision specified with <hwrev> (ASCII)\n"
181 " -v <version> set image version to <version> (decimal, hex or octal notation)\n"
182 " -i <file> input file\n"
183 , argv[0]);
184 }
185
186 int main(int argc, char* argv[]) {
187 struct file_info image = { 0 };
188
189 char* hwID = NULL;
190 char* hwVer = NULL;
191 u_int32_t swVer = 0;
192 u_int8_t chkSum;
193 int hdr_offset;
194
195 while ( 1 ) {
196 int c;
197
198 c = getopt(argc, argv, "b:i:r:v:f");
199 if (c == -1)
200 break;
201
202 switch (c) {
203 case 'b':
204 hwID = optarg;
205 break;
206 case 'f':
207 is_header = 0;
208 break;
209 case 'i':
210 image.file_name = optarg;
211 break;
212 case 'r':
213 hwVer = optarg;
214 break;
215 case 'v':
216 swVer = (u_int32_t) strtol(optarg, NULL, 0);
217 swVer = cpu_to_be32(swVer);
218 break;
219 default:
220 usage(argv);
221 return EXIT_FAILURE;
222 }
223 }
224
225 if (!hwID || !hwVer || !image.file_name) {
226 usage(argv);
227 return EXIT_FAILURE;
228 }
229
230 /*
231 * copy input to buffer, add extra space for header/footer and return
232 * header position
233 */
234 hdr_offset = copyToOutputBuf(&image);
235 if (hdr_offset < 0)
236 return EXIT_FAILURE;
237
238 DBG("Filling header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
239
240 strncpy(image.file_data + hdr_offset + 0, magic, 7);
241 memcpy(image.file_data + hdr_offset + 7, version, sizeof(version));
242 strncpy(image.file_data + hdr_offset + 11, hwID, 34);
243 strncpy(image.file_data + hdr_offset + 45, hwVer, 10);
244 memcpy(image.file_data + hdr_offset + 55, &swVer, sizeof(swVer));
245 strncpy(image.file_data + hdr_offset + 63, magic, 7);
246
247 /* calculate checksum and invert checksum */
248 if (is_header) {
249 chkSum = getCheckSum(image.file_data, image.file_size);
250 chkSum = (chkSum ^ 0xFF) + 1;
251 DBG("Checksum for Image: %hhX\n", chkSum);
252
253 /* write checksum to header */
254 image.file_data[511] = (char) chkSum;
255 }
256
257 /* overwrite input file */
258 if (writeFile(&image))
259 return EXIT_FAILURE;
260
261 return EXIT_SUCCESS;
262 }