numam-dpdk/lib/eal/unix/eal_firmware.c
David Marchand 40edb9c0d3 eal: handle compressed firmware
Introduce an internal firmware loading helper to remove code duplication
in our drivers and handle xz compressed firmware by calling libarchive.

This helper tries to look for .xz suffixes so that drivers are not aware
the firmware has been compressed.

libarchive is set as an optional dependency: without libarchive, a
runtime warning is emitted so that users know there is a compressed
firmware.

Windows implementation is left as an empty stub.

Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Igor Russkikh <irusskikh@marvell.com>
Acked-by: Aaron Conole <aconole@redhat.com>
Tested-by: Haiyue Wang <haiyue.wang@intel.com>
2021-07-07 16:41:53 +02:00

151 lines
2.7 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2021 Red Hat, Inc.
*/
#ifdef RTE_HAS_LIBARCHIVE
#include <archive.h>
#endif
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <rte_common.h>
#include <rte_log.h>
#include "eal_firmware.h"
#ifdef RTE_HAS_LIBARCHIVE
struct firmware_read_ctx {
struct archive *a;
};
static int
firmware_open(struct firmware_read_ctx *ctx, const char *name, size_t blocksize)
{
struct archive_entry *e;
ctx->a = archive_read_new();
if (ctx->a == NULL)
return -1;
if (archive_read_support_format_raw(ctx->a) != ARCHIVE_OK ||
archive_read_support_filter_xz(ctx->a) != ARCHIVE_OK ||
archive_read_open_filename(ctx->a, name, blocksize) != ARCHIVE_OK ||
archive_read_next_header(ctx->a, &e) != ARCHIVE_OK) {
archive_read_free(ctx->a);
ctx->a = NULL;
return -1;
}
return 0;
}
static ssize_t
firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)
{
return archive_read_data(ctx->a, buf, count);
}
static void
firmware_close(struct firmware_read_ctx *ctx)
{
archive_read_free(ctx->a);
ctx->a = NULL;
}
#else /* !RTE_HAS_LIBARCHIVE */
struct firmware_read_ctx {
int fd;
};
static int
firmware_open(struct firmware_read_ctx *ctx, const char *name,
__rte_unused size_t blocksize)
{
ctx->fd = open(name, O_RDONLY);
if (ctx->fd < 0)
return -1;
return 0;
}
static ssize_t
firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)
{
return read(ctx->fd, buf, count);
}
static void
firmware_close(struct firmware_read_ctx *ctx)
{
close(ctx->fd);
ctx->fd = -1;
}
#endif /* !RTE_HAS_LIBARCHIVE */
static int
firmware_read(const char *name, void **buf, size_t *bufsz)
{
const size_t blocksize = 4096;
struct firmware_read_ctx ctx;
int ret = -1;
int err;
*buf = NULL;
*bufsz = 0;
if (firmware_open(&ctx, name, blocksize) < 0)
return -1;
do {
void *tmp;
tmp = realloc(*buf, *bufsz + blocksize);
if (tmp == NULL) {
free(*buf);
*buf = NULL;
*bufsz = 0;
goto out;
}
*buf = tmp;
err = firmware_read_block(&ctx, RTE_PTR_ADD(*buf, *bufsz), blocksize);
if (err < 0) {
free(*buf);
*buf = NULL;
*bufsz = 0;
goto out;
}
*bufsz += err;
} while (err != 0);
ret = 0;
out:
firmware_close(&ctx);
return ret;
}
int
rte_firmware_read(const char *name, void **buf, size_t *bufsz)
{
char path[PATH_MAX];
int ret;
ret = firmware_read(name, buf, bufsz);
if (ret < 0) {
snprintf(path, sizeof(path), "%s.xz", name);
path[PATH_MAX - 1] = '\0';
#ifndef RTE_HAS_LIBARCHIVE
if (access(path, F_OK) == 0) {
RTE_LOG(WARNING, EAL, "libarchive not linked, %s cannot be decompressed\n",
path);
}
#else
ret = firmware_read(path, buf, bufsz);
#endif
}
return ret;
}