1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2023 Rafał Miłecki <rafal@milecki.pl>
18 #if !defined(__BYTE_ORDER)
19 #error "Unknown byte order"
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)
33 #error "Unsupported endianness"
36 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
38 #define BCMCLM_MAGIC "CLM DATA"
42 struct bcmclm_header
{
48 uint32_t virtual_header_address
;
49 uint32_t lookup_table_address
;
50 char clm_import_ver
[30];
51 char manufacturer
[22];
54 struct bcmclm_lookup_table
{
79 uint32_t offset_creation_date
;
108 struct bcmclm_header header
;
109 struct bcmclm_lookup_table lookup_table
;
112 size_t offsets_fixup
;
115 static inline size_t bcmclm_min(size_t x
, size_t y
)
117 return x
< y
? x
: y
;
120 /**************************************************
122 **************************************************/
124 static FILE *bcmclm_open(const char *pathname
, const char *mode
)
129 return fopen(pathname
, mode
);
131 if (isatty(fileno(stdin
))) {
132 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
136 if (fstat(fileno(stdin
), &st
)) {
137 fprintf(stderr
, "Failed to fstat stdin: %d\n", -errno
);
141 if (S_ISFIFO(st
.st_mode
)) {
142 fprintf(stderr
, "Reading from pipe stdin is unsupported\n");
149 static void bcmclm_close(FILE *fp
)
155 /**************************************************
156 * Existing CLM parser
157 **************************************************/
159 static int bcmclm_search(FILE *fp
, struct bcmclm_info
*info
)
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]));
170 if (!memcmp(&buf
[i
], BCMCLM_MAGIC
, 8) && !(unk
& 0xff00ffff)) {
171 info
->clm_offset
= offset
+ i
;
173 printf("Found CLM at offset 0x%zx\n", info
->clm_offset
);
186 static int bcmclm_parse(FILE *fp
, struct bcmclm_info
*info
)
188 struct bcmclm_header
*header
= &info
->header
;
189 struct bcmclm_lookup_table
*lookup_table
= &info
->lookup_table
;
195 if (fstat(fileno(fp
), &st
)) {
197 fprintf(stderr
, "Failed to fstat: %d\n", err
);
200 info
->file_size
= st
.st_size
;
204 fseek(fp
, info
->clm_offset
, SEEK_SET
);
206 if (fread(header
, 1, sizeof(*header
), fp
) != sizeof(*header
)) {
207 fprintf(stderr
, "Failed to read CLM header\n");
211 if (strncmp(header
->magic
, BCMCLM_MAGIC
, 8)) {
212 fprintf(stderr
, "Invalid CLM header magic\n");
216 info
->offsets_fixup
= info
->clm_offset
- le32_to_cpu(header
->virtual_header_address
);
220 fseek(fp
, le32_to_cpu(info
->header
.lookup_table_address
) + info
->offsets_fixup
, SEEK_SET
);
222 if (fread(lookup_table
, 1, sizeof(*lookup_table
), fp
) != sizeof(*lookup_table
)) {
223 fprintf(stderr
, "Failed to read lookup table\n");
230 /**************************************************
232 **************************************************/
234 static void bcmclm_print_lookup_data(FILE *fp
, struct bcmclm_info
*info
)
239 if (info
->lookup_table
.offset_creation_date
) {
242 fseek(fp
, le32_to_cpu(info
->lookup_table
.offset_creation_date
) + info
->offsets_fixup
, SEEK_SET
);
244 bytes
= fread(buf
, 1, sizeof(buf
), fp
);
246 printf("Creation date: %s\n", buf
);
251 static int bcmclm_info(int argc
, char **argv
)
253 struct bcmclm_info info
= {};
254 const char *pathname
= NULL
;
260 while ((c
= getopt(argc
, argv
, "i:s")) != -1) {
271 fp
= bcmclm_open(pathname
, "r");
273 fprintf(stderr
, "Failed to open CLM\n");
279 err
= bcmclm_search(fp
, &info
);
281 fprintf(stderr
, "Failed to find CLM in input file\n");
286 err
= bcmclm_parse(fp
, &info
);
288 fprintf(stderr
, "Failed to parse CLM\n");
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
);
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
);
300 bcmclm_print_lookup_data(fp
, &info
);
308 /**************************************************
310 **************************************************/
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");
321 printf("Examples:\n");
322 printf("\tbcmclm info -i x.clm\n");
323 printf("\tbcmclm info -s -i brcmfmac4366c-pcie.bin\n");
326 int main(int argc
, char **argv
)
330 if (!strcmp(argv
[1], "info"))
331 return bcmclm_info(argc
, argv
);