xref: /dpdk/lib/eal/unix/eal_firmware.c (revision 40edb9c0d36b781d711fabb91e250dca8fa6bd99)
1*40edb9c0SDavid Marchand /* SPDX-License-Identifier: BSD-3-Clause
2*40edb9c0SDavid Marchand  * Copyright(c) 2021 Red Hat, Inc.
3*40edb9c0SDavid Marchand  */
4*40edb9c0SDavid Marchand 
5*40edb9c0SDavid Marchand #ifdef RTE_HAS_LIBARCHIVE
6*40edb9c0SDavid Marchand #include <archive.h>
7*40edb9c0SDavid Marchand #endif
8*40edb9c0SDavid Marchand #include <fcntl.h>
9*40edb9c0SDavid Marchand #include <stdio.h>
10*40edb9c0SDavid Marchand #include <stdlib.h>
11*40edb9c0SDavid Marchand #include <unistd.h>
12*40edb9c0SDavid Marchand 
13*40edb9c0SDavid Marchand #include <rte_common.h>
14*40edb9c0SDavid Marchand #include <rte_log.h>
15*40edb9c0SDavid Marchand 
16*40edb9c0SDavid Marchand #include "eal_firmware.h"
17*40edb9c0SDavid Marchand 
18*40edb9c0SDavid Marchand #ifdef RTE_HAS_LIBARCHIVE
19*40edb9c0SDavid Marchand 
20*40edb9c0SDavid Marchand struct firmware_read_ctx {
21*40edb9c0SDavid Marchand 	struct archive *a;
22*40edb9c0SDavid Marchand };
23*40edb9c0SDavid Marchand 
24*40edb9c0SDavid Marchand static int
25*40edb9c0SDavid Marchand firmware_open(struct firmware_read_ctx *ctx, const char *name, size_t blocksize)
26*40edb9c0SDavid Marchand {
27*40edb9c0SDavid Marchand 	struct archive_entry *e;
28*40edb9c0SDavid Marchand 
29*40edb9c0SDavid Marchand 	ctx->a = archive_read_new();
30*40edb9c0SDavid Marchand 	if (ctx->a == NULL)
31*40edb9c0SDavid Marchand 		return -1;
32*40edb9c0SDavid Marchand 	if (archive_read_support_format_raw(ctx->a) != ARCHIVE_OK ||
33*40edb9c0SDavid Marchand 			archive_read_support_filter_xz(ctx->a) != ARCHIVE_OK ||
34*40edb9c0SDavid Marchand 			archive_read_open_filename(ctx->a, name, blocksize) != ARCHIVE_OK ||
35*40edb9c0SDavid Marchand 			archive_read_next_header(ctx->a, &e) != ARCHIVE_OK) {
36*40edb9c0SDavid Marchand 		archive_read_free(ctx->a);
37*40edb9c0SDavid Marchand 		ctx->a = NULL;
38*40edb9c0SDavid Marchand 		return -1;
39*40edb9c0SDavid Marchand 	}
40*40edb9c0SDavid Marchand 	return 0;
41*40edb9c0SDavid Marchand }
42*40edb9c0SDavid Marchand 
43*40edb9c0SDavid Marchand static ssize_t
44*40edb9c0SDavid Marchand firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)
45*40edb9c0SDavid Marchand {
46*40edb9c0SDavid Marchand 	return archive_read_data(ctx->a, buf, count);
47*40edb9c0SDavid Marchand }
48*40edb9c0SDavid Marchand 
49*40edb9c0SDavid Marchand static void
50*40edb9c0SDavid Marchand firmware_close(struct firmware_read_ctx *ctx)
51*40edb9c0SDavid Marchand {
52*40edb9c0SDavid Marchand 	archive_read_free(ctx->a);
53*40edb9c0SDavid Marchand 	ctx->a = NULL;
54*40edb9c0SDavid Marchand }
55*40edb9c0SDavid Marchand 
56*40edb9c0SDavid Marchand #else /* !RTE_HAS_LIBARCHIVE */
57*40edb9c0SDavid Marchand 
58*40edb9c0SDavid Marchand struct firmware_read_ctx {
59*40edb9c0SDavid Marchand 	int fd;
60*40edb9c0SDavid Marchand };
61*40edb9c0SDavid Marchand 
62*40edb9c0SDavid Marchand static int
63*40edb9c0SDavid Marchand firmware_open(struct firmware_read_ctx *ctx, const char *name,
64*40edb9c0SDavid Marchand 	__rte_unused size_t blocksize)
65*40edb9c0SDavid Marchand {
66*40edb9c0SDavid Marchand 	ctx->fd = open(name, O_RDONLY);
67*40edb9c0SDavid Marchand 	if (ctx->fd < 0)
68*40edb9c0SDavid Marchand 		return -1;
69*40edb9c0SDavid Marchand 	return 0;
70*40edb9c0SDavid Marchand }
71*40edb9c0SDavid Marchand 
72*40edb9c0SDavid Marchand static ssize_t
73*40edb9c0SDavid Marchand firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)
74*40edb9c0SDavid Marchand {
75*40edb9c0SDavid Marchand 	return read(ctx->fd, buf, count);
76*40edb9c0SDavid Marchand }
77*40edb9c0SDavid Marchand 
78*40edb9c0SDavid Marchand static void
79*40edb9c0SDavid Marchand firmware_close(struct firmware_read_ctx *ctx)
80*40edb9c0SDavid Marchand {
81*40edb9c0SDavid Marchand 	close(ctx->fd);
82*40edb9c0SDavid Marchand 	ctx->fd = -1;
83*40edb9c0SDavid Marchand }
84*40edb9c0SDavid Marchand 
85*40edb9c0SDavid Marchand #endif /* !RTE_HAS_LIBARCHIVE */
86*40edb9c0SDavid Marchand 
87*40edb9c0SDavid Marchand static int
88*40edb9c0SDavid Marchand firmware_read(const char *name, void **buf, size_t *bufsz)
89*40edb9c0SDavid Marchand {
90*40edb9c0SDavid Marchand 	const size_t blocksize = 4096;
91*40edb9c0SDavid Marchand 	struct firmware_read_ctx ctx;
92*40edb9c0SDavid Marchand 	int ret = -1;
93*40edb9c0SDavid Marchand 	int err;
94*40edb9c0SDavid Marchand 
95*40edb9c0SDavid Marchand 	*buf = NULL;
96*40edb9c0SDavid Marchand 	*bufsz = 0;
97*40edb9c0SDavid Marchand 
98*40edb9c0SDavid Marchand 	if (firmware_open(&ctx, name, blocksize) < 0)
99*40edb9c0SDavid Marchand 		return -1;
100*40edb9c0SDavid Marchand 
101*40edb9c0SDavid Marchand 	do {
102*40edb9c0SDavid Marchand 		void *tmp;
103*40edb9c0SDavid Marchand 
104*40edb9c0SDavid Marchand 		tmp = realloc(*buf, *bufsz + blocksize);
105*40edb9c0SDavid Marchand 		if (tmp == NULL) {
106*40edb9c0SDavid Marchand 			free(*buf);
107*40edb9c0SDavid Marchand 			*buf = NULL;
108*40edb9c0SDavid Marchand 			*bufsz = 0;
109*40edb9c0SDavid Marchand 			goto out;
110*40edb9c0SDavid Marchand 		}
111*40edb9c0SDavid Marchand 		*buf = tmp;
112*40edb9c0SDavid Marchand 
113*40edb9c0SDavid Marchand 		err = firmware_read_block(&ctx, RTE_PTR_ADD(*buf, *bufsz), blocksize);
114*40edb9c0SDavid Marchand 		if (err < 0) {
115*40edb9c0SDavid Marchand 			free(*buf);
116*40edb9c0SDavid Marchand 			*buf = NULL;
117*40edb9c0SDavid Marchand 			*bufsz = 0;
118*40edb9c0SDavid Marchand 			goto out;
119*40edb9c0SDavid Marchand 		}
120*40edb9c0SDavid Marchand 		*bufsz += err;
121*40edb9c0SDavid Marchand 
122*40edb9c0SDavid Marchand 	} while (err != 0);
123*40edb9c0SDavid Marchand 
124*40edb9c0SDavid Marchand 	ret = 0;
125*40edb9c0SDavid Marchand out:
126*40edb9c0SDavid Marchand 	firmware_close(&ctx);
127*40edb9c0SDavid Marchand 	return ret;
128*40edb9c0SDavid Marchand }
129*40edb9c0SDavid Marchand 
130*40edb9c0SDavid Marchand int
131*40edb9c0SDavid Marchand rte_firmware_read(const char *name, void **buf, size_t *bufsz)
132*40edb9c0SDavid Marchand {
133*40edb9c0SDavid Marchand 	char path[PATH_MAX];
134*40edb9c0SDavid Marchand 	int ret;
135*40edb9c0SDavid Marchand 
136*40edb9c0SDavid Marchand 	ret = firmware_read(name, buf, bufsz);
137*40edb9c0SDavid Marchand 	if (ret < 0) {
138*40edb9c0SDavid Marchand 		snprintf(path, sizeof(path), "%s.xz", name);
139*40edb9c0SDavid Marchand 		path[PATH_MAX - 1] = '\0';
140*40edb9c0SDavid Marchand #ifndef RTE_HAS_LIBARCHIVE
141*40edb9c0SDavid Marchand 		if (access(path, F_OK) == 0) {
142*40edb9c0SDavid Marchand 			RTE_LOG(WARNING, EAL, "libarchive not linked, %s cannot be decompressed\n",
143*40edb9c0SDavid Marchand 				path);
144*40edb9c0SDavid Marchand 		}
145*40edb9c0SDavid Marchand #else
146*40edb9c0SDavid Marchand 		ret = firmware_read(path, buf, bufsz);
147*40edb9c0SDavid Marchand #endif
148*40edb9c0SDavid Marchand 	}
149*40edb9c0SDavid Marchand 	return ret;
150*40edb9c0SDavid Marchand }
151