tools: firmware-utils: mksercommfw build on Darwin
[openwrt/staging/rmilecki.git] / tools / firmware-utils / src / mksercommfw.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <byteswap.h>
7 #include <endian.h>
8
9 #if !defined(__BYTE_ORDER)
10 #error "Unknown byte order"
11 #endif
12
13 #if __BYTE_ORDER == __BIG_ENDIAN
14 #define cpu_to_be32(x) (x)
15 #define be32_to_cpu(x) (x)
16 #define cpu_to_be16(x) (x)
17 #define be16_to_cpu(x) (x)
18 #elif __BYTE_ORDER == __LITTLE_ENDIAN
19 #define cpu_to_be32(x) bswap_32(x)
20 #define be32_to_cpu(x) bswap_32(x)
21 #define cpu_to_be16(x) bswap_16(x)
22 #define be16_to_cpu(x) bswap_16(x)
23 #else
24 #error "Unsupported endianness"
25 #endif
26
27 /* #define DEBUG 1 */
28
29 #ifdef DEBUG
30 #define DBG(...) {printf(__VA_ARGS__); }
31 #else
32 #define DBG(...) {}
33 #endif
34
35 #define ERR(...) {printf(__VA_ARGS__); }
36 #define ALIGN(a,b) ((a) + ((b) - ((a) % (b))))
37 #define ROOTFS_ALIGN 128
38 #define HEADER_SIZE 71
39
40 /*
41 * Fw Header Layout for Netgear / Sercomm devices (bytes)
42 *
43 * Size : 512 bytes + zipped image size
44 *
45 * Locations:
46 * magic : 0-6 ASCII
47 * version: 7-11 fixed
48 * hwID : 11-44 ASCII
49 * hwVer : 45-54 ASCII
50 * swVer : 55-62 uint32_t in BE
51 * magic : 63-69 ASCII
52 * ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
53 */
54
55 static const char* magic = "sErCoMm"; /* 7 */
56
57 /* 7-11: version control/download control ? */
58 static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 };
59
60
61 /* 512 onwards -> ZIP containing rootfs with the same Header */
62
63 struct file_info {
64 char* file_name; /* name of the file */
65 char* file_data; /* data of the file in memory */
66 u_int32_t file_size; /* length of the file */
67 };
68
69 static u_int8_t getCheckSum(char* data, int len) {
70 u_int8_t new = 0;
71
72 if (!data) {
73 ERR("Invalid pointer provided!\n");
74 return 0;
75 }
76
77 for (int i = 0; i < len; i++) {
78 new += data[i];
79 }
80
81 return new;
82 }
83
84 static int bufferFile(struct file_info* finfo) {
85 int fs = 0;
86 FILE* fp = NULL;
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 fs = ftell(fp);
104 rewind(fp);
105
106 if (fs < 0) {
107 ERR("Error getting filesize: %s\n", finfo->file_name);
108 fclose(fp);
109 return -1;
110 }
111
112 DBG("Filesize: %i\n", fs);
113 finfo->file_size = fs;
114
115 if (!(finfo->file_data = malloc(fs))) {
116 ERR("Out of memory!\n");
117 fclose(fp);
118 return -1;
119 }
120
121 if (fread(finfo->file_data, 1, fs, fp) != fs) {
122 ERR("Error reading file %s\n", finfo->file_name);
123 fclose(fp);
124 return -1;
125 }
126
127 DBG("File: read successful\n");
128 fclose(fp);
129
130 return 0;
131 }
132
133 static int writeFile(struct file_info* finfo) {
134 FILE* fp;
135
136 if (!finfo || !finfo->file_name) {
137 ERR("Invalid pointer provided!\n");
138 return -1;
139 }
140
141 DBG("Opening file: %s\n", finfo->file_name);
142
143 if (!(fp = fopen(finfo->file_name, "w"))) {
144 ERR("Error opening file: %s\n", finfo->file_name);
145 return -1;
146 }
147
148 DBG("Writing file: %s\n", finfo->file_name);
149
150 if (fwrite(finfo->file_data, 1, finfo->file_size, fp) != finfo->file_size) {
151 ERR("Wanted to write, but something went wrong!\n");
152 fclose(fp);
153 return -1;
154 }
155
156 fclose(fp);
157 return 0;
158 }
159
160 static void fi_clean(struct file_info* finfo) {
161 if (!finfo)
162 return;
163
164 if (finfo->file_name) {
165 finfo->file_name = NULL;
166 }
167
168 if (finfo->file_data) {
169 free(finfo->file_data);
170 finfo->file_data = NULL;
171 }
172
173 finfo->file_size = 0;
174 }
175
176 static void usage(char* argv[]) {
177 printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
178 "All are positional arguments ... \n"
179 " sysupgradefile: File with the kernel uimage at 0\n"
180 " kernel_offset: Offset where the kernel is located (decimal, hex or octal notation)\n"
181 " HWID: Hardware ID, ASCII\n"
182 " HWVER: Hardware Version, ASCII\n"
183 " SWID: Software Version (decimal, hex or octal notation)\n"
184 " \n"
185 , argv[0]);
186 }
187
188 int main(int argc, char* argv[]) {
189 int ret = 1;
190 int rootfsname_sz;
191 int zipfsname_sz;
192 int zipcmd_sz;
193 u_int32_t kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
194 u_int32_t swVer = 0;
195 struct file_info sysupgrade = { 0 };
196 struct file_info header = { 0 };
197 struct file_info rootfs = { 0 };
198 struct file_info zippedfs = { 0 };
199 struct file_info image = { 0 };
200 char* hwID = NULL;
201 char* hwVer = NULL;
202 char* rootfsname = NULL;
203 char* zipfsname = NULL;
204 char* zipcmd = NULL;
205 u_int8_t chkSum;
206
207 if (argc == 2) {
208 struct file_info myfile = { argv[1], 0, 0 };
209
210 if (bufferFile(&myfile))
211 return 1;
212
213 chkSum = getCheckSum(myfile.file_data, myfile.file_size);
214 printf("Checksum for File: 0x%hhX\n", chkSum);
215
216 return 0;
217 }
218
219 if (argc != 6) {
220 usage(argv);
221 return 1;
222 }
223
224 printf("Building fw image for sercomm devices ..\n");
225
226 /* process args */
227 hwID = argv[3];
228 hwVer = argv[4];
229
230 sysupgrade.file_name = argv[1];
231 image.file_name = argv[1];
232 kernel_offset = (u_int32_t) strtol(argv[2], NULL, 0);
233 swVer = (u_int32_t) strtol(argv[5], NULL, 0);
234 swVer = cpu_to_be32(swVer);
235
236 /* Check if files actually exist */
237 if (access(sysupgrade.file_name, (F_OK | R_OK))) {
238 /* Error */
239 ERR("File not found: %s\n", sysupgrade.file_name);
240 goto cleanup;
241 }
242
243 /* Calculate amount of required memory (incl. 0-term) */
244 rootfsname_sz = strlen(sysupgrade.file_name) + 7 + 1;
245 zipfsname_sz = strlen(sysupgrade.file_name) + 7 + 4 + 1;
246
247 /* Allocate required memory */
248 if (!(rootfsname = (char*) malloc(rootfsname_sz)) || !(zipfsname =
249 (char*) malloc(zipfsname_sz))) {
250 /* Error */
251 ERR("Out of memory!\n");
252 goto cleanup;
253 }
254
255 /* Create filenames */
256 if (snprintf(rootfsname, rootfsname_sz, "%s.rootfs", sysupgrade.file_name)
257 >= rootfsname_sz
258 || snprintf(zipfsname, zipfsname_sz, "%s.rootfs.zip",
259 sysupgrade.file_name) >= zipfsname_sz) {
260 /* Error */
261 ERR("Buffer too small!\n");
262 goto cleanup;
263 }
264
265 /* Buffer all files */
266 if (bufferFile(&sysupgrade)) {
267 /* Error */
268 goto cleanup;
269 }
270
271 DBG("Building header: %s %s %2X %s\n", hwID, hwVer, swVer, magic);
272
273 /* Construct the firmware header/magic */
274 header.file_name = NULL;
275 header.file_size = HEADER_SIZE;
276
277 if (!(header.file_data = (char*) calloc(1, HEADER_SIZE))) {
278 /* Error */
279 ERR("Out of memory!\n");
280 goto cleanup;
281 }
282
283 strncpy(header.file_data + 0, magic, 7);
284 memcpy(header.file_data + 7, version, sizeof(version));
285 strncpy(header.file_data + 11, hwID, 34);
286 strncpy(header.file_data + 45, hwVer, 10);
287 memcpy(header.file_data + 55, &swVer, sizeof(swVer));
288 strncpy(header.file_data + 63, magic, 7);
289
290 DBG("Creating rootfs ..\n");
291
292 /* Construct a rootfs */
293 rootfs.file_name = rootfsname;
294 rootfs.file_size = ALIGN(
295 sysupgrade.file_size + kernel_offset + header.file_size,
296 ROOTFS_ALIGN);
297
298 if (!(rootfs.file_data = calloc(1, rootfs.file_size))) {
299 /* Error */
300 ERR("Out of memory!\n");
301 goto cleanup;
302 }
303
304 /* copy Owrt image to kernel location */
305 memcpy(rootfs.file_data + kernel_offset, sysupgrade.file_data,
306 sysupgrade.file_size);
307
308 /* Append header after the owrt image. The updater searches for it */
309 memcpy(rootfs.file_data + kernel_offset + sysupgrade.file_size,
310 header.file_data, header.file_size);
311
312 /* Write to file */
313 if (writeFile(&rootfs)) {
314 /* Error */
315 goto cleanup;
316 }
317
318 /* Construct a zip */
319 DBG("Preparing to zip ..\n");
320
321 /* now that we got the rootfs, repeat the whole thing again(sorta):
322 * 1. zip the rootfs */
323 zipcmd_sz = 3 + 1 + strlen(zipfsname) + 1 + strlen(rootfs.file_name) + 1;
324
325 if (!(zipcmd = malloc(zipcmd_sz))) {
326 /* Error */
327 ERR("Out of memory!\n");
328 goto cleanup;
329 }
330
331 if (snprintf(zipcmd, zipcmd_sz, "%s %s %s", "zip", zipfsname,
332 rootfs.file_name) >= zipcmd_sz) {
333 /* Error */
334 ERR("Buffer too small!\n");
335 goto cleanup;
336 }
337
338 if (system(zipcmd)) {
339 /* Error */
340 ERR("Error creating a zip file!\n");
341 goto cleanup;
342 }
343
344 /* and load zipped fs */
345 zippedfs.file_name = zipfsname;
346
347 if (bufferFile(&zippedfs)) {
348 /* Error */
349 goto cleanup;
350 }
351
352 DBG("Creating Image.\n");
353
354 /* 2. create new file 512 + rootfs size */
355 image.file_size = zippedfs.file_size + 512;
356 if (!(image.file_data = malloc(zippedfs.file_size + 512))) {
357 /* Error */
358 ERR("Out of memory!\n");
359 goto cleanup;
360 }
361
362 /* 3. add header to file */
363 memcpy(image.file_data, header.file_data, header.file_size);
364
365 /* 4. clear remaining space */
366 if (header.file_size < 512)
367 memset(image.file_data + header.file_size, 0, 512 - header.file_size);
368
369 /* 5. copy zipfile at loc 512 */
370 memcpy(image.file_data + 512, zippedfs.file_data, zippedfs.file_size);
371
372 /* 6. do a checksum run, and compute checksum */
373 chkSum = getCheckSum(image.file_data, image.file_size);
374
375 DBG("Checksum for Image: %hhX\n", chkSum);
376
377 /* 7. write the checksum inverted into byte 511 to bring it to 0 on verification */
378 chkSum = (chkSum ^ 0xFF) + 1;
379 image.file_data[511] = (char) chkSum;
380
381 chkSum = getCheckSum(image.file_data, image.file_size);
382 DBG("Checksum for after fix: %hhX\n", chkSum);
383
384 if (chkSum != 0) {
385 ERR("Invalid checksum!\n")
386 goto cleanup;
387 }
388
389 /* 8. pray that the updater will accept the file */
390 if (writeFile(&image)) {
391 /* Error */
392 goto cleanup;
393 }
394
395 /* All seems OK */
396 ret = 0;
397
398 cleanup:
399
400 if (rootfs.file_name && !access(rootfs.file_name, F_OK | W_OK))
401 remove(rootfs.file_name);
402
403 if (zippedfs.file_name && !access(zippedfs.file_name, F_OK | W_OK))
404 remove(zippedfs.file_name);
405
406 fi_clean(&sysupgrade);
407 fi_clean(&header);
408 fi_clean(&rootfs);
409 fi_clean(&zippedfs);
410 fi_clean(&image);
411
412 if (rootfsname)
413 free(rootfsname);
414
415 if (zipfsname)
416 free(zipfsname);
417
418 if (zipcmd)
419 free(zipcmd);
420
421 return ret;
422 }