52955edaf2e73c9c3342cc2d82a8bd80e4026a2d
1 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT
3 * Luxul's firmware container format
5 * Copyright 2020 Legrand AV Inc.
21 #if __BYTE_ORDER == __BIG_ENDIAN
22 #define cpu_to_le32(x) bswap_32(x)
23 #define cpu_to_le16(x) bswap_16(x)
24 #define le32_to_cpu(x) bswap_32(x)
25 #define le16_to_cpu(x) bswap_16(x)
26 #elif __BYTE_ORDER == __LITTLE_ENDIAN
27 #define cpu_to_le32(x) (x)
28 #define cpu_to_le16(x) (x)
29 #define le32_to_cpu(x) (x)
30 #define le16_to_cpu(x) (x)
35 __typeof__ (a) _a = (a); \
36 __typeof__ (b) _b = (b); \
42 __typeof__ (a) _a = (a); \
43 __typeof__ (b) _b = (b); \
47 #define MAX_SUPPORTED_VERSION 2
49 #define LXL_FLAGS_VENDOR_LUXUL 0x00000001
52 char magic
[4]; /* "LXL#" */
63 } __attribute__((packed
));
65 /**************************************************
67 **************************************************/
69 static uint32_t lxlfw_hdr_len(uint32_t version
)
73 return offsetof(struct lxl_hdr
, v0_end
);
75 return offsetof(struct lxl_hdr
, v1_end
);
77 return offsetof(struct lxl_hdr
, v2_end
);
79 fprintf(stderr
, "Unsupported version %d\n", version
);
85 * lxlfw_open - open Luxul firmware file and validate it
87 * @pathname: Luxul firmware file
88 * @hdr: struct to read to
90 static FILE *lxlfw_open(const char *pathname
, struct lxl_hdr
*hdr
)
92 size_t v0_len
= lxlfw_hdr_len(0);
98 lxl
= fopen(pathname
, "r");
100 fprintf(stderr
, "Could not open \"%s\" file\n", pathname
);
104 bytes
= fread(hdr
, 1, v0_len
, lxl
);
105 if (bytes
!= v0_len
) {
106 fprintf(stderr
, "Input file too small to use Luxul format\n");
110 if (memcmp(hdr
->magic
, "LXL#", 4)) {
111 fprintf(stderr
, "File <file> does not use Luxul's format\n");
115 version
= le32_to_cpu(hdr
->version
);
117 min_hdr_len
= lxlfw_hdr_len(min(version
, MAX_SUPPORTED_VERSION
));
119 bytes
= fread(((uint8_t *)hdr
) + v0_len
, 1, min_hdr_len
- v0_len
, lxl
);
120 if (bytes
!= min_hdr_len
- v0_len
) {
121 fprintf(stderr
, "Input file too small for header version %d\n", version
);
134 * lxlfw_copy_data - read data from one stream and write to another
136 * @from: input stream
138 * @size: amount of bytes to copy (0 to copy all data)
140 static ssize_t
lxlfw_copy_data(FILE *from
, FILE *to
, size_t size
)
142 int copy_all
= size
== 0;
146 while (copy_all
|| size
) {
147 size_t to_read
= copy_all
? sizeof(buf
) : min(size
, sizeof(buf
));
150 bytes
= fread(buf
, 1, to_read
, from
);
151 if (bytes
== 0 && copy_all
) {
153 } else if (bytes
<= 0) {
154 fprintf(stderr
, "Failed to read data\n");
158 if (fwrite(buf
, 1, bytes
, to
) != bytes
) {
159 fprintf(stderr
, "Failed to write data\n");
171 /**************************************************
173 **************************************************/
175 static int lxlfw_info(int argc
, char **argv
) {
184 fprintf(stderr
, "Missing <file> argument\n");
189 lxl
= lxlfw_open(argv
[2], &hdr
);
191 fprintf(stderr
, "Could not open \"%s\" Luxul firmware\n", argv
[2]);
196 version
= le32_to_cpu(hdr
.version
);
198 printf("Format version:\t%d\n", version
);
199 printf("Header length:\t%d\n", le32_to_cpu(hdr
.hdr_len
));
201 printf("Flags:\t\t");
202 flags
= le32_to_cpu(hdr
.flags
);
203 if (flags
& LXL_FLAGS_VENDOR_LUXUL
)
204 printf("VENDOR_LUXUL ");
206 memcpy(board
, hdr
.board
, sizeof(hdr
.board
));
208 printf("Board:\t\t%s\n", board
);
211 printf("Release:\t");
212 if (hdr
.release
[0] || hdr
.release
[1] || hdr
.release
[2] || hdr
.release
[3]) {
213 printf("%hu.%hu.%hu", hdr
.release
[0], hdr
.release
[1], hdr
.release
[2]);
215 printf(".%hu", hdr
.release
[3]);
226 /**************************************************
228 **************************************************/
230 static int lxlfw_create(int argc
, char **argv
) {
231 struct lxl_hdr hdr
= {
232 .magic
= { 'L', 'X', 'L', '#' },
234 char *in_path
= NULL
;
235 uint32_t version
= 0;
245 fprintf(stderr
, "Missing <file> argument\n");
251 while ((c
= getopt(argc
, argv
, "i:lb:r:")) != -1) {
257 hdr
.flags
|= cpu_to_le32(LXL_FLAGS_VENDOR_LUXUL
);
258 version
= max(version
, 1);
261 memcpy(hdr
.board
, optarg
, strlen(optarg
) > 16 ? 16 : strlen(optarg
));
262 version
= max(version
, 1);
265 if (sscanf(optarg
, "%hhu.%hhu.%hhu.%hhu", &hdr
.release
[0], &hdr
.release
[1], &hdr
.release
[2], &hdr
.release
[3]) < 1) {
266 fprintf(stderr
, "Failed to parse release number \"%s\"\n", optarg
);
270 version
= max(version
, 2);
275 hdr
.version
= cpu_to_le32(version
);
276 hdr_len
= lxlfw_hdr_len(version
);
281 hdr
.hdr_len
= cpu_to_le32(hdr_len
);
284 fprintf(stderr
, "Missing input file argument\n");
289 in
= fopen(in_path
, "r");
291 fprintf(stderr
, "Could not open input file %s\n", in_path
);
296 lxl
= fopen(argv
[2], "w+");
298 fprintf(stderr
, "Could not open \"%s\" file\n", argv
[2]);
303 bytes
= fwrite(&hdr
, 1, hdr_len
, lxl
);
304 if (bytes
!= hdr_len
) {
305 fprintf(stderr
, "Could not write Luxul's header\n");
310 bytes
= lxlfw_copy_data(in
, lxl
, 0);
312 fprintf(stderr
, "Could not copy %zu bytes from input file\n", bytes
);
325 /**************************************************
327 **************************************************/
329 static void usage() {
332 printf("Get info about Luxul firmware:\n");
333 printf("\tlxlfw info <file>\n");
335 printf("Create new Luxul firmware:\n");
336 printf("\tlxlfw create <file> [options]\n");
337 printf("\t-i file\t\t\t\tinput file for Luxul's firmware container\n");
338 printf("\t-l\t\t\t\tmark firmware as created by Luxul company (DON'T USE)\n");
339 printf("\t-b board\t\t\tboard (device) name\n");
340 printf("\t-r release\t\t\trelease number (e.g. 5.1.0, 7.1.0.2)\n");
343 int main(int argc
, char **argv
) {
345 if (!strcmp(argv
[1], "info"))
346 return lxlfw_info(argc
, argv
);
347 else if (!strcmp(argv
[1], "create"))
348 return lxlfw_create(argc
, argv
);