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

Sources/firmware-utils/src/bcmclm.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Copyright (C) 2023 Rafał Miłecki <rafal@milecki.pl>
  4  */
  5 
  6 #include <byteswap.h>
  7 #include <endian.h>
  8 #include <errno.h>
  9 #include <stdbool.h>
 10 #include <stddef.h>
 11 #include <stdint.h>
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <string.h>
 15 #include <sys/stat.h>
 16 #include <unistd.h>
 17 
 18 #if !defined(__BYTE_ORDER)
 19 #error "Unknown byte order"
 20 #endif
 21 
 22 #if __BYTE_ORDER == __BIG_ENDIAN
 23 #define cpu_to_le32(x)  bswap_32(x)
 24 #define le32_to_cpu(x)  bswap_32(x)
 25 #define cpu_to_be32(x)  (x)
 26 #define be32_to_cpu(x)  (x)
 27 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 28 #define cpu_to_le32(x)  (x)
 29 #define le32_to_cpu(x)  (x)
 30 #define cpu_to_be32(x)  bswap_32(x)
 31 #define be32_to_cpu(x)  bswap_32(x)
 32 #else
 33 #error "Unsupported endianness"
 34 #endif
 35 
 36 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 37 
 38 #define BCMCLM_MAGIC            "CLM DATA"
 39 
 40 /* Raw data */
 41 
 42 struct bcmclm_header {
 43         char magic[8];
 44         uint32_t unk0;
 45         uint8_t unk1[2];
 46         char api[20];
 47         char compiler[10];
 48         uint32_t virtual_header_address;
 49         uint32_t lookup_table_address;
 50         char clm_import_ver[30];
 51         char manufacturer[22];
 52 };
 53 
 54 struct bcmclm_lookup_table {
 55         uint32_t offset0;
 56         uint32_t offset1;
 57         uint32_t offset2;
 58         uint32_t offset3;
 59         uint32_t offset4;
 60         uint32_t offset5;
 61         uint32_t offset6;
 62         uint32_t offset7;
 63         uint32_t offset8;
 64         uint32_t offset9;
 65         uint32_t offset10;
 66         uint32_t offset11;
 67         uint32_t offset12;
 68         uint32_t offset13;
 69         uint32_t offset14;
 70         uint32_t offset15;
 71         uint32_t offset16;
 72         uint32_t offset17;
 73         uint32_t offset18;
 74         uint32_t offset19;
 75         uint32_t offset20;
 76         uint32_t offset21;
 77         uint32_t offset22;
 78         uint32_t offset23;
 79         uint32_t offset_creation_date;
 80         uint32_t offset25;
 81         uint32_t offset26;
 82         uint32_t offset27;
 83         uint32_t offset28;
 84         uint32_t offset29;
 85         uint32_t offset30;
 86         uint32_t offset31;
 87         uint32_t offset32;
 88         uint32_t offset33;
 89         uint32_t offset34;
 90         uint32_t offset35;
 91         uint32_t offset36;
 92         uint32_t offset37;
 93         uint32_t offset38;
 94         uint32_t offset39;
 95         uint32_t offset40;
 96         uint32_t offset41;
 97         uint32_t offset42;
 98         uint32_t offset43;
 99         uint32_t offset44;
100         uint32_t offset45;
101         uint32_t offset46;
102         uint32_t offset47;
103 };
104 
105 /* Parsed info */
106 
107 struct bcmclm_info {
108         struct bcmclm_header header;
109         struct bcmclm_lookup_table lookup_table;
110         size_t file_size;
111         size_t clm_offset;
112         size_t offsets_fixup;
113 };
114 
115 static inline size_t bcmclm_min(size_t x, size_t y)
116 {
117         return x < y ? x : y;
118 }
119 
120 /**************************************************
121  * Helpers
122  **************************************************/
123 
124 static FILE *bcmclm_open(const char *pathname, const char *mode)
125 {
126         struct stat st;
127 
128         if (pathname)
129                 return fopen(pathname, mode);
130 
131         if (isatty(fileno(stdin))) {
132                 fprintf(stderr, "Reading from TTY stdin is unsupported\n");
133                 return NULL;
134         }
135 
136         if (fstat(fileno(stdin), &st)) {
137                 fprintf(stderr, "Failed to fstat stdin: %d\n", -errno);
138                 return NULL;
139         }
140 
141         if (S_ISFIFO(st.st_mode)) {
142                 fprintf(stderr, "Reading from pipe stdin is unsupported\n");
143                 return NULL;
144         }
145 
146         return stdin;
147 }
148 
149 static void bcmclm_close(FILE *fp)
150 {
151         if (fp != stdin)
152                 fclose(fp);
153 }
154 
155 /**************************************************
156  * Existing CLM parser
157  **************************************************/
158 
159 static int bcmclm_search(FILE *fp, struct bcmclm_info *info)
160 {
161         uint8_t buf[1024];
162         size_t offset = 0;
163         size_t bytes;
164         int i;
165 
166         while ((bytes = fread(buf, 1, sizeof(buf), fp)) == sizeof(buf)) {
167                 for (i = 0; i < bytes - 12; i += 4) {
168                         uint32_t unk = le32_to_cpu(*(uint32_t *)(&buf[i + 8]));
169 
170                         if (!memcmp(&buf[i], BCMCLM_MAGIC, 8) && !(unk & 0xff00ffff)) {
171                                 info->clm_offset = offset + i;
172 
173                                 printf("Found CLM at offset 0x%zx\n", info->clm_offset);
174                                 printf("\n");
175 
176                                 return 0;
177                         }
178                 }
179 
180                 offset += bytes;
181         }
182 
183         return -ENOENT;
184 }
185 
186 static int bcmclm_parse(FILE *fp, struct bcmclm_info *info)
187 {
188         struct bcmclm_header *header = &info->header;
189         struct bcmclm_lookup_table *lookup_table = &info->lookup_table;
190         struct stat st;
191         int err = 0;
192 
193         /* File size */
194 
195         if (fstat(fileno(fp), &st)) {
196                 err = -errno;
197                 fprintf(stderr, "Failed to fstat: %d\n", err);
198                 return err;
199         }
200         info->file_size = st.st_size;
201 
202         /* Header */
203 
204         fseek(fp, info->clm_offset, SEEK_SET);
205 
206         if (fread(header, 1, sizeof(*header), fp) != sizeof(*header)) {
207                 fprintf(stderr, "Failed to read CLM header\n");
208                 return -EIO;
209         }
210 
211         if (strncmp(header->magic, BCMCLM_MAGIC, 8)) {
212                 fprintf(stderr, "Invalid CLM header magic\n");
213                 return -EPROTO;
214         }
215 
216         info->offsets_fixup = info->clm_offset - le32_to_cpu(header->virtual_header_address);
217 
218         /* Lookup table */
219 
220         fseek(fp, le32_to_cpu(info->header.lookup_table_address) + info->offsets_fixup, SEEK_SET);
221 
222         if (fread(lookup_table, 1, sizeof(*lookup_table), fp) != sizeof(*lookup_table)) {
223                 fprintf(stderr, "Failed to read lookup table\n");
224                 return -EIO;
225         }
226 
227         return 0;
228 }
229 
230 /**************************************************
231  * Info
232  **************************************************/
233 
234 static void bcmclm_print_lookup_data(FILE *fp, struct bcmclm_info *info)
235 {
236         uint8_t buf[64];
237         size_t bytes;
238 
239         if (info->lookup_table.offset_creation_date) {
240                 printf("\n");
241 
242                 fseek(fp, le32_to_cpu(info->lookup_table.offset_creation_date) + info->offsets_fixup, SEEK_SET);
243 
244                 bytes = fread(buf, 1, sizeof(buf), fp);
245                 if (bytes) {
246                         printf("Creation date: %s\n", buf);
247                 }
248         }
249 }
250 
251 static int bcmclm_info(int argc, char **argv)
252 {
253         struct bcmclm_info info = {};
254         const char *pathname = NULL;
255         int search = 0;
256         FILE *fp;
257         int c;
258         int err = 0;
259 
260         while ((c = getopt(argc, argv, "i:s")) != -1) {
261                 switch (c) {
262                 case 'i':
263                         pathname = optarg;
264                         break;
265                 case 's':
266                         search = 1;
267                         break;
268                 }
269         }
270 
271         fp = bcmclm_open(pathname, "r");
272         if (!fp) {
273                 fprintf(stderr, "Failed to open CLM\n");
274                 err = -EACCES;
275                 goto out;
276         }
277 
278         if (search) {
279                 err = bcmclm_search(fp, &info);
280                 if (err) {
281                         fprintf(stderr, "Failed to find CLM in input file\n");
282                         goto err_close;
283                 }
284         }
285 
286         err = bcmclm_parse(fp, &info);
287         if (err) {
288                 fprintf(stderr, "Failed to parse CLM\n");
289                 goto err_close;
290         }
291 
292         printf("API: %s\n", info.header.api);
293         printf("Compiler: %s\n", info.header.compiler);
294         printf("clm_import_ver: %s\n", info.header.clm_import_ver);
295         printf("Manufacturer: %s\n", info.header.manufacturer);
296         printf("\n");
297         printf("Virtual header address: 0x%08x (real: 0x%zx)\n", le32_to_cpu(info.header.virtual_header_address), le32_to_cpu(info.header.virtual_header_address) + info.offsets_fixup);
298         printf("Virtual lookup table address: 0x%08x (real: 0x%zx)\n", le32_to_cpu(info.header.lookup_table_address), le32_to_cpu(info.header.lookup_table_address) + info.offsets_fixup);
299 
300         bcmclm_print_lookup_data(fp, &info);
301 
302 err_close:
303         bcmclm_close(fp);
304 out:
305         return err;
306 }
307 
308 /**************************************************
309  * Start
310  **************************************************/
311 
312 static void usage()
313 {
314         printf("Usage:\n");
315         printf("\n");
316         printf("Info about CLM:\n");
317         printf("\tbcmclm info <options>\n");
318         printf("\t-i <file>\t\t\t\t\tinput CLM\n");
319         printf("\t-s\t\t\t\t\tsearch for CLM data in bigger file\n");
320         printf("\n");
321         printf("Examples:\n");
322         printf("\tbcmclm info -i x.clm\n");
323         printf("\tbcmclm info -s -i brcmfmac4366c-pcie.bin\n");
324 }
325 
326 int main(int argc, char **argv)
327 {
328         if (argc > 1) {
329                 optind++;
330                 if (!strcmp(argv[1], "info"))
331                         return bcmclm_info(argc, argv);
332         }
333 
334         usage();
335 
336         return 0;
337 }
338 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt