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#" */
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
);
133 /**************************************************
135 **************************************************/
137 static int lxlfw_info(int argc
, char **argv
) {
146 fprintf(stderr
, "Missing <file> argument\n");
151 lxl
= lxlfw_open(argv
[2], &hdr
);
153 fprintf(stderr
, "Could not open \"%s\" Luxul firmware\n", argv
[2]);
158 version
= le32_to_cpu(hdr
.version
);
160 printf("Format version:\t%d\n", version
);
161 printf("Header length:\t%d\n", le32_to_cpu(hdr
.hdr_len
));
163 printf("Flags:\t\t");
164 flags
= le32_to_cpu(hdr
.flags
);
165 if (flags
& LXL_FLAGS_VENDOR_LUXUL
)
166 printf("VENDOR_LUXUL ");
168 memcpy(board
, hdr
.board
, sizeof(hdr
.board
));
170 printf("Board:\t\t%s\n", board
);
173 printf("Release:\t");
174 if (hdr
.release
[0] || hdr
.release
[1] || hdr
.release
[2] || hdr
.release
[3]) {
175 printf("%hu.%hu.%hu", hdr
.release
[0], hdr
.release
[1], hdr
.release
[2]);
177 printf(".%hu", hdr
.release
[3]);
188 /**************************************************
190 **************************************************/
192 static int lxlfw_create(int argc
, char **argv
) {
193 struct lxl_hdr hdr
= {
194 .magic
= { 'L', 'X', 'L', '#' },
196 char *in_path
= NULL
;
197 uint32_t version
= 0;
207 fprintf(stderr
, "Missing <file> argument\n");
213 while ((c
= getopt(argc
, argv
, "i:lb:r:")) != -1) {
219 hdr
.flags
|= cpu_to_le32(LXL_FLAGS_VENDOR_LUXUL
);
220 version
= max(version
, 1);
223 memcpy(hdr
.board
, optarg
, strlen(optarg
) > 16 ? 16 : strlen(optarg
));
224 version
= max(version
, 1);
227 if (sscanf(optarg
, "%hhu.%hhu.%hhu.%hhu", &hdr
.release
[0], &hdr
.release
[1], &hdr
.release
[2], &hdr
.release
[3]) < 1) {
228 fprintf(stderr
, "Failed to parse release number \"%s\"\n", optarg
);
232 version
= max(version
, 2);
237 hdr
.version
= cpu_to_le32(version
);
238 hdr_len
= lxlfw_hdr_len(version
);
243 hdr
.hdr_len
= cpu_to_le32(hdr_len
);
246 fprintf(stderr
, "Missing input file argument\n");
251 in
= fopen(in_path
, "r");
253 fprintf(stderr
, "Could not open input file %s\n", in_path
);
258 lxl
= fopen(argv
[2], "w+");
260 fprintf(stderr
, "Could not open \"%s\" file\n", argv
[2]);
265 bytes
= fwrite(&hdr
, 1, hdr_len
, lxl
);
266 if (bytes
!= hdr_len
) {
267 fprintf(stderr
, "Could not write Luxul's header\n");
272 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
273 if (fwrite(buf
, 1, bytes
, lxl
) != bytes
) {
274 fprintf(stderr
, "Could not copy %zu bytes from input file\n", bytes
);
288 /**************************************************
290 **************************************************/
292 static void usage() {
295 printf("Get info about Luxul firmware:\n");
296 printf("\tlxlfw info <file>\n");
298 printf("Create new Luxul firmware:\n");
299 printf("\tlxlfw create <file> [options]\n");
300 printf("\t-i file\t\t\t\tinput file for Luxul's firmware container\n");
301 printf("\t-l\t\t\t\tmark firmware as created by Luxul company (DON'T USE)\n");
302 printf("\t-b board\t\t\tboard (device) name\n");
303 printf("\t-r release\t\t\trelease number (e.g. 5.1.0, 7.1.0.2)\n");
306 int main(int argc
, char **argv
) {
308 if (!strcmp(argv
[1], "info"))
309 return lxlfw_info(argc
, argv
);
310 else if (!strcmp(argv
[1], "create"))
311 return lxlfw_create(argc
, argv
);