cb1913fdb1c35c3e3d50553d1f92806b6b2361d1
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
16 #if !defined(__BYTE_ORDER)
17 #error "Unknown byte order"
20 #if __BYTE_ORDER == __BIG_ENDIAN
21 #define cpu_to_le32(x) bswap_32(x)
22 #define le32_to_cpu(x) bswap_32(x)
23 #elif __BYTE_ORDER == __LITTLE_ENDIAN
24 #define cpu_to_le32(x) (x)
25 #define le32_to_cpu(x) (x)
27 #error "Unsupported endianness"
30 #define WFI_VERSION 0x00005732
31 #define WFI_VERSION_NAND_1MB_DATA 0x00005731
33 #define WFI_NOR_FLASH 1
34 #define WFI_NAND16_FLASH 2
35 #define WFI_NAND128_FLASH 3
36 #define WFI_NAND256_FLASH 4
37 #define WFI_NAND512_FLASH 5
38 #define WFI_NAND1024_FLASH 6
39 #define WFI_NAND2048_FLASH 7
41 #define WFI_FLAG_HAS_PMC 0x1
42 #define WFI_FLAG_SUPPORTS_BTRM 0x2
44 struct bcm4908img_tail
{
53 static size_t prefix_len
;
54 static size_t suffix_len
;
56 static inline size_t bcm4908img_min(size_t x
, size_t y
) {
60 /**************************************************
62 **************************************************/
64 static const uint32_t crc32_tbl
[] = {
65 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
66 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
67 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
68 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
69 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
70 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
71 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
72 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
73 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
74 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
75 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
76 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
77 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
78 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
79 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
80 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
81 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
82 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
83 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
84 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
85 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
86 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
87 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
88 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
89 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
90 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
91 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
92 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
93 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
94 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
95 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
96 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
97 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
98 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
99 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
100 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
101 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
102 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
103 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
104 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
105 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
106 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
107 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
108 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
109 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
110 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
111 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
112 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
113 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
114 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
115 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
116 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
117 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
118 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
119 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
120 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
121 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
122 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
123 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
124 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
125 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
126 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
127 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
128 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
131 uint32_t bcm4908img_crc32(uint32_t crc
, uint8_t *buf
, size_t len
) {
133 crc
= crc32_tbl
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
141 /**************************************************
143 **************************************************/
145 static void bcm4908img_check_parse_options(int argc
, char **argv
) {
148 while ((c
= getopt(argc
, argv
, "p:s:")) != -1) {
151 prefix_len
= atoi(optarg
);
154 suffix_len
= atoi(optarg
);
160 static int bcm4908img_check(int argc
, char **argv
) {
161 struct bcm4908img_tail tail
;
171 fprintf(stderr
, "No BCM4908 image pathname passed\n");
178 bcm4908img_check_parse_options(argc
, argv
);
180 if (stat(pathname
, &st
)) {
181 fprintf(stderr
, "Failed to stat %s\n", pathname
);
186 fp
= fopen(pathname
, "r");
188 fprintf(stderr
, "Failed to open %s\n", pathname
);
193 fseek(fp
, prefix_len
, SEEK_SET
);
196 length
= st
.st_size
- prefix_len
- sizeof(tail
) - suffix_len
;
197 while (length
&& (bytes
= fread(buf
, 1, bcm4908img_min(sizeof(buf
), length
), fp
)) > 0) {
198 crc32
= bcm4908img_crc32(crc32
, buf
, bytes
);
203 fprintf(stderr
, "Failed to read last %zd B of data from %s\n", length
, pathname
);
208 if (fread(&tail
, 1, sizeof(tail
), fp
) != sizeof(tail
)) {
209 fprintf(stderr
, "Failed to read BCM4908 image tail\n");
214 if (crc32
!= le32_to_cpu(tail
.crc32
)) {
215 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32
, le32_to_cpu(tail
.crc32
));
220 printf("Found a valid BCM4908 image (crc: 0x%08x)\n", crc32
);
228 /**************************************************
230 **************************************************/
232 static ssize_t
bcm4908img_create_append_file(FILE *trx
, const char *in_path
, uint32_t *crc32
) {
238 in
= fopen(in_path
, "r");
240 fprintf(stderr
, "Failed to open %s\n", in_path
);
244 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
245 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
246 fprintf(stderr
, "Failed to write %zu B to %s\n", bytes
, pathname
);
250 *crc32
= bcm4908img_crc32(*crc32
, buf
, bytes
);
259 static ssize_t
bcm4908img_create_append_zeros(FILE *trx
, size_t length
) {
262 buf
= malloc(length
);
265 memset(buf
, 0, length
);
267 if (fwrite(buf
, 1, length
, trx
) != length
) {
268 fprintf(stderr
, "Failed to write %zu B to %s\n", length
, pathname
);
278 static ssize_t
bcm4908img_create_align(FILE *trx
, size_t cur_offset
, size_t alignment
) {
279 if (cur_offset
& (alignment
- 1)) {
280 size_t length
= alignment
- (cur_offset
% alignment
);
281 return bcm4908img_create_append_zeros(trx
, length
);
287 static int bcm4908img_create(int argc
, char **argv
) {
288 struct bcm4908img_tail tail
= {
289 .version
= cpu_to_le32(WFI_VERSION
),
290 .chip_id
= cpu_to_le32(0x4908),
291 .flash_type
= cpu_to_le32(WFI_NAND128_FLASH
),
292 .flags
= cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM
),
294 uint32_t crc32
= 0xffffffff;
295 size_t cur_offset
= 0;
302 fprintf(stderr
, "No BCM4908 image pathname passed\n");
308 fp
= fopen(pathname
, "w+");
310 fprintf(stderr
, "Failed to open %s\n", pathname
);
316 while ((c
= getopt(argc
, argv
, "f:a:A:")) != -1) {
319 bytes
= bcm4908img_create_append_file(fp
, optarg
, &crc32
);
321 fprintf(stderr
, "Failed to append file %s\n", optarg
);
327 bytes
= bcm4908img_create_align(fp
, cur_offset
, strtol(optarg
, NULL
, 0));
329 fprintf(stderr
, "Failed to append zeros\n");
334 bytes
= strtol(optarg
, NULL
, 0) - cur_offset
;
336 fprintf(stderr
, "Current BCM4908 image length is 0x%zx, can't pad it with zeros to 0x%lx\n", cur_offset
, strtol(optarg
, NULL
, 0));
338 bytes
= bcm4908img_create_append_zeros(fp
, bytes
);
340 fprintf(stderr
, "Failed to append zeros\n");
350 tail
.crc32
= cpu_to_le32(crc32
);
352 bytes
= fwrite(&tail
, 1, sizeof(tail
), fp
);
353 if (bytes
!= sizeof(tail
)) {
354 fprintf(stderr
, "Failed to write BCM4908 image tail to %s\n", pathname
);
364 /**************************************************
366 **************************************************/
368 static void usage() {
371 printf("Checking a BCM4908 image:\n");
372 printf("\tbcm4908img check <file> [options]\tcheck if images is valid\n");
373 printf("\t-p prefix\t\t\tlength of custom header to skip (default: 0)\n");
374 printf("\t-s suffix\t\t\tlength of custom tail to skip (default: 0)\n");
376 printf("Creating a new BCM4908 image:\n");
377 printf("\tbcm4908img create <file> [options]\n");
378 printf("\t-f file\t\t\t\tadd data from specified file\n");
379 printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
380 printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
383 int main(int argc
, char **argv
) {
385 if (!strcmp(argv
[1], "check"))
386 return bcm4908img_check(argc
, argv
);
387 else if (!strcmp(argv
[1], "create"))
388 return bcm4908img_create(argc
, argv
);