• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/xiaomifw.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
  4  */
  5 
  6 /*
  7  * Standard Xiaomi firmware image consists of:
  8  * 1. Xiaomi header
  9  * 2. Blobs
 10  * 3. RSA signature
 11  *
 12  * Each blob section consists of:
 13  * 1. Header
 14  * 2. Content
 15  *
 16  * Signature consists of:
 17  * 1. Header
 18  * 2. Content
 19  */
 20 
 21 #include <byteswap.h>
 22 #include <endian.h>
 23 #include <errno.h>
 24 #include <stdbool.h>
 25 #include <stddef.h>
 26 #include <stdint.h>
 27 #include <stdio.h>
 28 #include <stdlib.h>
 29 #include <string.h>
 30 #include <sys/stat.h>
 31 #include <unistd.h>
 32 
 33 #if !defined(__BYTE_ORDER)
 34 #error "Unknown byte order"
 35 #endif
 36 
 37 #if __BYTE_ORDER == __BIG_ENDIAN
 38 #define cpu_to_le32(x)  bswap_32(x)
 39 #define le32_to_cpu(x)  bswap_32(x)
 40 #define cpu_to_be32(x)  (x)
 41 #define be32_to_cpu(x)  (x)
 42 #define cpu_to_le16(x)  bswap_16(x)
 43 #define le16_to_cpu(x)  bswap_16(x)
 44 #define cpu_to_be16(x)  (x)
 45 #define be16_to_cpu(x)  (x)
 46 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 47 #define cpu_to_le32(x)  (x)
 48 #define le32_to_cpu(x)  (x)
 49 #define cpu_to_be32(x)  bswap_32(x)
 50 #define be32_to_cpu(x)  bswap_32(x)
 51 #define cpu_to_le16(x)  (x)
 52 #define le16_to_cpu(x)  (x)
 53 #define cpu_to_be16(x)  bswap_16(x)
 54 #define be16_to_cpu(x)  bswap_16(x)
 55 #else
 56 #error "Unsupported endianness"
 57 #endif
 58 
 59 #define DEVICE_ID_MIWIFI_R1CM           0x0003
 60 #define DEVICE_ID_MIWIFI_R2D            0x0004
 61 #define DEVICE_ID_MIWIFI_R1CL           0x0005
 62 #define DEVICE_ID_MIWIFI_R3             0x0007
 63 #define DEVICE_ID_MIWIFI_R3D            0x0008
 64 #define DEVICE_ID_MIWIFI_R3G            0x000d
 65 #define DEVICE_ID_MIWIFI_R4CM           0x0012
 66 #define DEVICE_ID_MIWIFI_R2100          0x0016
 67 #define DEVICE_ID_MIWIFI_RA70           0x0025
 68 
 69 #define BLOB_ALIGNMENT                  0x4
 70 
 71 #define BLOB_TYPE_UBOOT                 0x0001
 72 #define BLOB_TYPE_FW_UIMAGE             0x0004  /* Found in r1cl, r1cm */
 73 #define BLOB_TYPE_FW_OS2                0x0006
 74 #define BLOB_TYPE_FW_UIMAGE2            0x0007  /* Found in r4cm */
 75 
 76 /* Raw data */
 77 
 78 struct xiaomi_header {
 79         char magic[4];
 80         uint32_t signature_offset;
 81         uint32_t crc32;
 82         uint16_t unused;
 83         uint16_t device_id;
 84         uint32_t blob_offsets[8];
 85 };
 86 
 87 struct xiaomi_blob_header {
 88         uint32_t magic;
 89         uint32_t flash_offset;
 90         uint32_t size;
 91         uint16_t type;
 92         uint16_t unused;
 93         char name[32];
 94 };
 95 
 96 struct xiaomi_signature_header {
 97         uint32_t size;
 98         uint32_t padding[3];
 99         uint8_t content[0x100];
100 };
101 
102 /* Parsed info */
103 
104 struct xiaomifw_blob_info {
105         struct xiaomi_blob_header header;
106         size_t offset;
107         size_t size;
108 };
109 
110 struct xiaomifw_info {
111         struct xiaomi_header header;
112         size_t file_size;
113         struct xiaomifw_blob_info blobs[8];
114         size_t signature_offset;
115         uint32_t crc32;
116 };
117 
118 static inline size_t xiaomifw_min(size_t x, size_t y) {
119         return x < y ? x : y;
120 }
121 
122 struct device_map {
123         int device_id;
124         const char *device_name;
125 };
126 
127 static const struct device_map device_names[] = {
128         { DEVICE_ID_MIWIFI_R1CM, "r1cm" },
129         { DEVICE_ID_MIWIFI_R2D, "r2d" },
130         { DEVICE_ID_MIWIFI_R1CL, "r1cl" },
131         { DEVICE_ID_MIWIFI_R3, "r3" },
132         { DEVICE_ID_MIWIFI_R3D, "r3d" },
133         { DEVICE_ID_MIWIFI_R3G, "r3g" },
134         { DEVICE_ID_MIWIFI_R4CM, "r4cm" },
135         { DEVICE_ID_MIWIFI_R2100, "r2100" },
136         { DEVICE_ID_MIWIFI_RA70, "ra70" },
137 };
138 
139 const char *xiaomifw_device_name(int device_id) {
140         int i;
141 
142         for (i = 0; i < sizeof(device_names); i++) {
143                 if (device_names[i].device_id == device_id) {
144                         return device_names[i].device_name;
145                 }
146         }
147 
148         return "unknown";
149 }
150 
151 const int xiaomifw_device_id(const char *device_name) {
152         int i;
153 
154         for (i = 0; i < sizeof(device_names); i++) {
155                 if (!strcmp(device_names[i].device_name, device_name)) {
156                         return device_names[i].device_id;
157                 }
158         }
159 
160         return -ENOENT;
161 }
162 
163 /**************************************************
164  * CRC32
165  **************************************************/
166 
167 static const uint32_t crc32_tbl[] = {
168         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
169         0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
170         0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
171         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
172         0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
173         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
174         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
175         0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
176         0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
177         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
178         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
179         0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
180         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
181         0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
182         0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
183         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
184         0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
185         0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
186         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
187         0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
188         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
189         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
190         0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
191         0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
192         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
193         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
194         0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
195         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
196         0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
197         0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
198         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
199         0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
200         0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
201         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
202         0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
203         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
204         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
205         0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
206         0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
207         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
208         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
209         0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
210         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
211         0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
212         0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
213         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
214         0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
215         0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
216         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
217         0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
218         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
219         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
220         0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
221         0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
222         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
223         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
224         0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
225         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
226         0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
227         0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
228         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
229         0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
230         0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
231         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
232 };
233 
234 uint32_t xiaomifw_crc32(uint32_t crc, const void *buf, size_t len) {
235         const uint8_t *in = buf;
236 
237         while (len) {
238                 crc = crc32_tbl[(crc ^ *in) & 0xff] ^ (crc >> 8);
239                 in++;
240                 len--;
241         }
242 
243         return crc;
244 }
245 
246 /**************************************************
247  * Helpers
248  **************************************************/
249 
250 static FILE *xiaomifw_open(const char *pathname, const char *mode) {
251         struct stat st;
252 
253         if (pathname)
254                 return fopen(pathname, mode);
255 
256         if (isatty(fileno(stdin))) {
257                 fprintf(stderr, "Reading from TTY stdin is unsupported\n");
258                 return NULL;
259         }
260 
261         if (fstat(fileno(stdin), &st)) {
262                 fprintf(stderr, "Failed to fstat stdin: %d\n", -errno);
263                 return NULL;
264         }
265 
266         if (S_ISFIFO(st.st_mode)) {
267                 fprintf(stderr, "Reading from pipe stdin is unsupported\n");
268                 return NULL;
269         }
270 
271         return stdin;
272 }
273 
274 static void xiaomifw_close(FILE *fp) {
275         if (fp != stdin)
276                 fclose(fp);
277 }
278 
279 /**************************************************
280  * Existing firmware parser
281  **************************************************/
282 
283 static int xiaomifw_parse(FILE *fp, struct xiaomifw_info *info) {
284         struct xiaomi_header *header = &info->header;
285         struct stat st;
286         uint8_t buf[1024];
287         size_t length;
288         size_t bytes;
289         int i;
290         int err = 0;
291 
292         memset(info, 0, sizeof(*info));
293 
294         /* File size */
295 
296         if (fstat(fileno(fp), &st)) {
297                 err = -errno;
298                 fprintf(stderr, "Failed to fstat: %d\n", err);
299                 return err;
300         }
301         info->file_size = st.st_size;
302 
303         /* Header */
304 
305         if (fread(header, 1, sizeof(*header), fp) != sizeof(*header)) {
306                 fprintf(stderr, "Failed to read Xiaomi header\n");
307                 return -EIO;
308         }
309 
310         if (strncmp(header->magic, "HDR1", 4)) {
311                 fprintf(stderr, "Invalid Xiaomi header magic\n");
312                 return -EPROTO;
313         }
314         info->signature_offset = le32_to_cpu(header->signature_offset);
315 
316         /* CRC32 */
317 
318         fseek(fp, 12, SEEK_SET);
319 
320         info->crc32 = 0xffffffff;
321         length = info->file_size - 12;
322         while (length && (bytes = fread(buf, 1, xiaomifw_min(sizeof(buf), length), fp)) > 0) {
323                 info->crc32 = xiaomifw_crc32(info->crc32, buf, bytes);
324                 length -= bytes;
325         }
326         if (length) {
327                 fprintf(stderr, "Failed to read last %zd B of data\n", length);
328                 return -EIO;
329         }
330 
331         if (info->crc32 != le32_to_cpu(header->crc32)) {
332                 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info->crc32, le32_to_cpu(header->crc32));
333                 return -EPROTO;
334         }
335 
336         /* Blobs */
337 
338         for (i = 0; i < sizeof(info->blobs); i++) {
339                 size_t offset = le32_to_cpu(info->header.blob_offsets[i]);
340                 struct xiaomifw_blob_info *file_info = &info->blobs[i];
341 
342                 if (!offset) {
343                         break;
344                 }
345 
346                 fseek(fp, offset, SEEK_SET);
347 
348                 if (fread(&file_info->header, 1, sizeof(file_info->header), fp) != sizeof(file_info->header)) {
349                         fprintf(stderr, "Failed to read file Xiaomi header\n");
350                         return -EIO;
351                 }
352 
353                 file_info->offset = offset;
354                 file_info->size = le32_to_cpu(file_info->header.size);
355 
356                 offset += sizeof(file_info->header) + file_info->size;
357                 offset = (offset + 4) & ~(0x4 - 1);
358         }
359 
360         return 0;
361 }
362 
363 /**************************************************
364  * Info
365  **************************************************/
366 
367 static int xiaomifw_info(int argc, char **argv) {
368         struct xiaomifw_info info;
369         const char *pathname = NULL;
370         uint16_t device_id;
371         FILE *fp;
372         int i;
373         int c;
374         int err = 0;
375 
376         while ((c = getopt(argc, argv, "i:")) != -1) {
377                 switch (c) {
378                 case 'i':
379                         pathname = optarg;
380                         break;
381                 }
382         }
383 
384         fp = xiaomifw_open(pathname, "r");
385         if (!fp) {
386                 fprintf(stderr, "Failed to open Xiaomi firmware image\n");
387                 err = -EACCES;
388                 goto out;
389         }
390 
391         err = xiaomifw_parse(fp, &info);
392         if (err) {
393                 fprintf(stderr, "Failed to parse Xiaomi firmware image\n");
394                 goto err_close;
395         }
396 
397         device_id = le16_to_cpu(info.header.device_id);
398 
399         printf("Device ID: 0x%04x (%s)\n", device_id, xiaomifw_device_name(device_id));
400         printf("CRC32: 0x%08x\n", info.crc32);
401         printf("Signature offset: 0x%08zx\n", info.signature_offset);
402         for (i = 0; i < sizeof(info.blobs) && info.blobs[i].offset; i++) {
403                 struct xiaomifw_blob_info *file_info = &info.blobs[i];
404 
405                 printf("[Blob %d] offset:0x%08zx flash_offset:0x%08x size:0x%08zx type:0x%04x name:%s\n", i, file_info->offset, file_info->header.flash_offset, file_info->size, file_info->header.type, file_info->header.name);
406         }
407 
408 err_close:
409         xiaomifw_close(fp);
410 out:
411         return err;
412 }
413 
414 /**************************************************
415  * Create
416  **************************************************/
417 
418 static ssize_t xiaomifw_create_append_zeros(FILE *fp, size_t length) {
419         uint8_t *buf;
420 
421         buf = malloc(length);
422         if (!buf)
423                 return -ENOMEM;
424         memset(buf, 0, length);
425 
426         if (fwrite(buf, 1, length, fp) != length) {
427                 fprintf(stderr, "Failed to write %zu B of zeros\n", length);
428                 free(buf);
429                 return -EIO;
430         }
431 
432         free(buf);
433 
434         return length;
435 }
436 
437 static ssize_t xiaomifw_create_append_file(FILE *fp, char *blob) {
438         struct xiaomi_blob_header header = {
439                 .magic = le32_to_cpu(0x0000babe),
440                 .flash_offset = ~0,
441                 .type = ~0,
442         };
443         struct stat st;
444         char *in_path = NULL;
445         ssize_t length = 0;
446         char *type = NULL;
447         char *resptr;
448         char *tok;
449         char *p;
450         uint8_t buf[1024];
451         size_t bytes;
452         FILE *in;
453         int err;
454         int i = 0;
455 
456         /* sscanf and strtok can't handle optional fields (e.g. "::firmware.bin:/tmp/foo.bin") */
457         resptr = blob;
458         do {
459                 p = resptr;
460                 if ((tok = strchr(resptr, ':'))) {
461                         *tok = '\0';
462                         resptr = tok + 1;
463                 } else {
464                         resptr = NULL;
465                 }
466 
467                 switch (i++) {
468                 case 0:
469                         if (*p) {
470                                 header.flash_offset = cpu_to_le32(strtoul(p, NULL, 0));
471                         }
472                         break;
473                 case 1:
474                         type = p;
475                         break;
476                 case 2:
477                         strncpy(header.name, p, sizeof(header.name));
478                         break;
479                 case 3:
480                         in_path = p;
481                         break;
482                 }
483         } while (resptr);
484 
485         if (i < 4) {
486                 fprintf(stderr, "Failed to parse blob info\n");
487                 return -EPROTO;
488         }
489 
490         in = fopen(in_path, "r");
491         if (!in) {
492                 fprintf(stderr, "Failed to open %s\n", in_path);
493                 return -EACCES;
494         }
495 
496         if (fstat(fileno(in), &st)) {
497                 err = -errno;
498                 fprintf(stderr, "Failed to fstat: %d\n", err);
499                 return err;
500         }
501         header.size = cpu_to_le32(st.st_size);
502 
503         if (*type) {
504                 if (!strcmp(type, "uimage")) {
505                         header.type = cpu_to_le32(BLOB_TYPE_FW_UIMAGE);
506                 } else if (!strcmp(type, "uimage2")) {
507                         header.type = cpu_to_le32(BLOB_TYPE_FW_UIMAGE2);
508                 } else {
509                         fprintf(stderr, "Unsupported blob type: %s\n", type);
510                         return -ENOENT;
511                 }
512         }
513 
514         bytes = fwrite(&header, 1, sizeof(header), fp);
515         if (bytes != sizeof(header)) {
516                 fprintf(stderr, "Failed to write blob header\n");
517                 return -EIO;
518         }
519         length += bytes;
520 
521         while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
522                 if (fwrite(buf, 1, bytes, fp) != bytes) {
523                         fprintf(stderr, "Failed to write %zu B of blob\n", bytes);
524                         return -EIO;
525                 }
526                 length += bytes;
527         }
528 
529         fclose(in);
530 
531         if (length & (BLOB_ALIGNMENT - 1)) {
532                 size_t padding = BLOB_ALIGNMENT - (length % BLOB_ALIGNMENT);
533 
534                 bytes = xiaomifw_create_append_zeros(fp, padding);
535                 if (bytes != padding) {
536                         fprintf(stderr, "Failed to align blob\n");
537                         return -EIO;
538                 }
539                 length += bytes;
540         }
541 
542         return length;
543 }
544 
545 static ssize_t xiaomifw_create_write_signature(FILE *fp) {
546         struct xiaomi_signature_header header = {
547         };
548         size_t bytes;
549 
550         bytes = fwrite(&header, 1, sizeof(header), fp);
551         if (bytes != sizeof(header)) {
552                 fprintf(stderr, "Failed to write blob header\n");
553                 return -EIO;
554         }
555 
556         return bytes;
557 }
558 
559 static int xiaomifw_create(int argc, char **argv) {
560         struct xiaomi_header header = {
561                 .magic = { 'H', 'D', 'R', '1' },
562         };
563         uint32_t crc32 = 0xffffffff;
564         uint8_t buf[1024];
565         int blob_idx = 0;
566         ssize_t length;
567         ssize_t offset;
568         ssize_t bytes;
569         int device_id;
570         FILE *fp;
571         int c;
572         int err = 0;
573 
574         if (argc < 3) {
575                 fprintf(stderr, "No Xiaomi firmware image pathname passed\n");
576                 err = -EINVAL;
577                 goto out;
578         }
579 
580         optind = 3;
581         while ((c = getopt(argc, argv, "m:b:")) != -1) {
582                 switch (c) {
583                 case 'm':
584                         device_id = xiaomifw_device_id(optarg);
585                         if (device_id < 0) {
586                                 err = device_id;
587                                 fprintf(stderr, "Failed to find device %s\n", optarg);
588                                 goto out;
589                         }
590                         header.device_id = device_id;
591                         break;
592                 case 'b':
593                         break;
594                 }
595                 if (err)
596                         goto out;
597         }
598 
599         fp = fopen(argv[2], "w+");
600         if (!fp) {
601                 fprintf(stderr, "Failed to open %s\n", argv[2]);
602                 err = -EACCES;
603                 goto out;
604         }
605 
606         offset = sizeof(header);
607         fseek(fp, offset, SEEK_SET);
608 
609         optind = 3;
610         while ((c = getopt(argc, argv, "m:b:")) != -1) {
611                 switch (c) {
612                 case 'm':
613                         break;
614                 case 'b':
615                         if (blob_idx >= sizeof(header.blob_offsets)) {
616                                 err = -ENOENT;
617                                 fprintf(stderr, "Too many blobs specified\n");
618                                 goto err_close;
619                         }
620                         bytes = xiaomifw_create_append_file(fp, optarg);
621                         if (bytes < 0) {
622                                 err = bytes;
623                                 fprintf(stderr, "Failed to append blob: %d\n", err);
624                                 goto err_close;
625                         }
626                         header.blob_offsets[blob_idx++] = cpu_to_le32(offset);
627                         offset += bytes;
628                         break;
629                 }
630                 if (err)
631                         goto err_close;
632         }
633 
634         bytes = xiaomifw_create_write_signature(fp);
635         if (bytes < 0) {
636                 err = bytes;
637                 fprintf(stderr, "Failed to write signature: %d\n", err);
638                 goto err_close;
639         }
640         header.signature_offset = cpu_to_le32(offset);
641         offset += bytes;
642 
643         crc32 = xiaomifw_crc32(crc32, (uint8_t *)&header + 12, sizeof(header) - 12);
644         fseek(fp, sizeof(header), SEEK_SET);
645         length = offset - sizeof(header);
646         while (length && (bytes = fread(buf, 1, xiaomifw_min(sizeof(buf), length), fp)) > 0) {
647                 crc32 = xiaomifw_crc32(crc32, buf, bytes);
648                 length -= bytes;
649         }
650         if (length) {
651                 err = -EIO;
652                 fprintf(stderr, "Failed to calculate CRC32 over the last %zd B of data\n", length);
653                 goto err_close;
654         }
655 
656         header.crc32 = cpu_to_le32(crc32);
657 
658         rewind(fp);
659 
660         bytes = fwrite(&header, 1, sizeof(header), fp);
661         if (bytes != sizeof(header)) {
662                 fprintf(stderr, "Failed to write header\n");
663                 return -EIO;
664         }
665 
666 err_close:
667         fclose(fp);
668 out:
669         return err;
670 }
671 
672 /**************************************************
673  * Extract
674  **************************************************/
675 
676 static int xiaomifw_extract(int argc, char **argv) {
677         struct xiaomifw_info info;
678         const char *pathname = NULL;
679         const char *name = NULL;
680         uint8_t buf[1024];
681         size_t offset = 0;
682         size_t size = 0;
683         size_t bytes;
684         FILE *fp;
685         int i;
686         int c;
687         int err = 0;
688 
689         while ((c = getopt(argc, argv, "i:n:")) != -1) {
690                 switch (c) {
691                 case 'i':
692                         pathname = optarg;
693                         break;
694                 case 'n':
695                         name = optarg;
696                         break;
697                 }
698         }
699 
700         if (!name) {
701                 err = -EINVAL;
702                 fprintf(stderr, "No data to extract specified\n");
703                 goto err_out;
704         }
705 
706         fp = xiaomifw_open(pathname, "r");
707         if (!fp) {
708                 fprintf(stderr, "Failed to open Xiaomi firmware image\n");
709                 err = -EACCES;
710                 goto err_out;
711         }
712 
713         err = xiaomifw_parse(fp, &info);
714         if (err) {
715                 fprintf(stderr, "Failed to parse Xiaomi firmware image\n");
716                 goto err_close;
717         }
718 
719         for (i = 0; i < sizeof(info.blobs) && info.blobs[i].offset; i++) {
720                 struct xiaomifw_blob_info *file_info = &info.blobs[i];
721 
722                 if (!strcmp(file_info->header.name, name)) {
723                         offset = file_info->offset;
724                         size = file_info->size;
725                 }
726         }
727 
728         if (!offset || !size) {
729                 err = -EINVAL;
730                 fprintf(stderr, "Failed to find requested data in input image\n");
731                 goto err_close;
732         }
733 
734         fseek(fp, offset + sizeof(struct xiaomi_blob_header), SEEK_SET);
735         while (size && (bytes = fread(buf, 1, xiaomifw_min(sizeof(buf), size), fp)) > 0) {
736                 fwrite(buf, bytes, 1, stdout);
737                 size -= bytes;
738         }
739         if (size) {
740                 err = -EIO;
741                 fprintf(stderr, "Failed to read last %zd B of data\n", size);
742                 goto err_close;
743         }
744 
745 err_close:
746         xiaomifw_close(fp);
747 err_out:
748         return err;
749 }
750 
751 /**************************************************
752  * Start
753  **************************************************/
754 
755 static void usage() {
756         printf("Usage:\n");
757         printf("\n");
758         printf("Info about a Xiaomi firmware image:\n");
759         printf("\txiaomifw info <options>\n");
760         printf("\t-i <file>\t\t\t\t\tinput Xiaomi firmware image\n");
761         printf("\n");
762         printf("Creating a new Xiaomi firmware image:\n");
763         printf("\txiaomifw create <file> [options]\n");
764         printf("\t-m <model>\t\t\t\t\tmodel name (e.g. \"r4cm\")\n");
765         printf("\t-b <flash_offset>:<type>:<name>:<path>\t\tblob to include\n");
766         printf("\n");
767         printf("Extracting from a Xiaomi firmware image:\n");
768         printf("\txiaomifw extract <options>\n");
769         printf("\t-i <file>\t\t\t\t\tinput Xiaomi firmware image\n");
770         printf("\t-n <type>\t\t\t\t\tname of blob to extract (e.g. \"firmware.bin\")\n");
771         printf("\n");
772         printf("Examples:\n");
773         printf("\txiaomifw info -i miwifi_r4cm_firmware_c6fa8_3.0.23_INT.bin\n");
774         printf("\txiaomifw extract -i miwifi_r4cm_firmware_c6fa8_3.0.23_INT.bin -n firmware.bin\n");
775         printf("\txiaomifw create \\\n");
776         printf("\t\t-m r1cm \\\n");
777         printf("\t\t-b ::xiaoqiang_version:/tmp/xiaoqiang_version \\\n");
778         printf("\t\t-b 0x160000:uimage2:firmware.bin:/tmp/custom.bin\n");
779 }
780 
781 int main(int argc, char **argv) {
782         if (argc > 1) {
783                 optind++;
784                 if (!strcmp(argv[1], "info"))
785                         return xiaomifw_info(argc, argv);
786                 else if (!strcmp(argv[1], "create"))
787                         return xiaomifw_create(argc, argv);
788                 else if (!strcmp(argv[1], "extract"))
789                         return xiaomifw_extract(argc, argv);
790         }
791 
792         usage();
793         return 0;
794 }
795 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt