linux/lib/test_firmware.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * This module provides an interface to trigger and test firmware loading.
 *
 * It is designed to be used for basic evaluation of the firmware loading
 * subsystem (for example when validating firmware verification). It lacks
 * any extra dependencies, and will not normally be loaded by the system
 * unless explicitly requested by name.
 */

#define pr_fmt(fmt)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/completion.h>
#include <linux/firmware.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/kstrtox.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
#include <linux/efi_embedded_fw.h>

MODULE_IMPORT_NS();

#define TEST_FIRMWARE_NAME
#define TEST_FIRMWARE_NUM_REQS
#define TEST_FIRMWARE_BUF_SIZE
#define TEST_UPLOAD_MAX_SIZE
#define TEST_UPLOAD_BLK_SIZE

static DEFINE_MUTEX(test_fw_mutex);
static const struct firmware *test_firmware;
static LIST_HEAD(test_upload_list);

struct test_batched_req {};

/**
 * struct test_config - represents configuration for the test for different triggers
 *
 * @name: the name of the firmware file to look for
 * @into_buf: when the into_buf is used if this is true
 *	request_firmware_into_buf() will be used instead.
 * @buf_size: size of buf to allocate when into_buf is true
 * @file_offset: file offset to request when calling request_firmware_into_buf
 * @partial: partial read opt when calling request_firmware_into_buf
 * @sync_direct: when the sync trigger is used if this is true
 *	request_firmware_direct() will be used instead.
 * @send_uevent: whether or not to send a uevent for async requests
 * @num_requests: number of requests to try per test case. This is trigger
 *	specific.
 * @reqs: stores all requests information
 * @read_fw_idx: index of thread from which we want to read firmware results
 *	from through the read_fw trigger.
 * @upload_name: firmware name to be used with upload_read sysfs node
 * @test_result: a test may use this to collect the result from the call
 *	of the request_firmware*() calls used in their tests. In order of
 *	priority we always keep first any setup error. If no setup errors were
 *	found then we move on to the first error encountered while running the
 *	API. Note that for async calls this typically will be a successful
 *	result (0) unless of course you've used bogus parameters, or the system
 *	is out of memory.  In the async case the callback is expected to do a
 *	bit more homework to figure out what happened, unfortunately the only
 *	information passed today on error is the fact that no firmware was
 *	found so we can only assume -ENOENT on async calls if the firmware is
 *	NULL.
 *
 *	Errors you can expect:
 *
 *	API specific:
 *
 *	0:		success for sync, for async it means request was sent
 *	-EINVAL:	invalid parameters or request
 *	-ENOENT:	files not found
 *
 *	System environment:
 *
 *	-ENOMEM:	memory pressure on system
 *	-ENODEV:	out of number of devices to test
 *	-EINVAL:	an unexpected error has occurred
 * @req_firmware: if @sync_direct is true this is set to
 *	request_firmware_direct(), otherwise request_firmware()
 */
struct test_config {};

struct upload_inject_err {};

struct test_firmware_upload {};

static struct test_config *test_fw_config;

static struct test_firmware_upload *upload_lookup_name(const char *name)
{}

static ssize_t test_fw_misc_read(struct file *f, char __user *buf,
				 size_t size, loff_t *offset)
{}

static const struct file_operations test_fw_fops =;

static void __test_release_all_firmware(void)
{}

static void test_release_all_firmware(void)
{}


static void __test_firmware_config_free(void)
{}

/*
 * XXX: move to kstrncpy() once merged.
 *
 * Users should use kfree_const() when freeing these.
 */
static int __kstrncpy(char **dst, const char *name, size_t count, gfp_t gfp)
{}

static int __test_firmware_config_init(void)
{}

static ssize_t reset_store(struct device *dev,
			   struct device_attribute *attr,
			   const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(reset);

static ssize_t config_show(struct device *dev,
			   struct device_attribute *attr,
			   char *buf)
{}
static DEVICE_ATTR_RO(config);

static ssize_t config_name_store(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{}

/*
 * As per sysfs_kf_seq_show() the buf is max PAGE_SIZE.
 */
static ssize_t config_test_show_str(char *dst,
				    char *src)
{}

static inline int __test_dev_config_update_bool(const char *buf, size_t size,
				       bool *cfg)
{}

static int test_dev_config_update_bool(const char *buf, size_t size,
				       bool *cfg)
{}

static ssize_t test_dev_config_show_bool(char *buf, bool val)
{}

static int __test_dev_config_update_size_t(
					 const char *buf,
					 size_t size,
					 size_t *cfg)
{}

static ssize_t test_dev_config_show_size_t(char *buf, size_t val)
{}

static ssize_t test_dev_config_show_int(char *buf, int val)
{}

static int __test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
{}

static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
{}

static ssize_t test_dev_config_show_u8(char *buf, u8 val)
{}

static ssize_t config_name_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{}
static DEVICE_ATTR_RW(config_name);

static ssize_t config_upload_name_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

static ssize_t config_upload_name_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RW(config_upload_name);

static ssize_t config_num_requests_store(struct device *dev,
					 struct device_attribute *attr,
					 const char *buf, size_t count)
{}

static ssize_t config_num_requests_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{}
static DEVICE_ATTR_RW(config_num_requests);

static ssize_t config_into_buf_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)
{}

static ssize_t config_into_buf_show(struct device *dev,
				    struct device_attribute *attr,
				    char *buf)
{}
static DEVICE_ATTR_RW(config_into_buf);

static ssize_t config_buf_size_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)
{}

static ssize_t config_buf_size_show(struct device *dev,
				    struct device_attribute *attr,
				    char *buf)
{}
static DEVICE_ATTR_RW(config_buf_size);

static ssize_t config_file_offset_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

static ssize_t config_file_offset_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RW(config_file_offset);

static ssize_t config_partial_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{}

static ssize_t config_partial_show(struct device *dev,
				   struct device_attribute *attr,
				   char *buf)
{}
static DEVICE_ATTR_RW(config_partial);

static ssize_t config_sync_direct_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

static ssize_t config_sync_direct_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RW(config_sync_direct);

static ssize_t config_send_uevent_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

static ssize_t config_send_uevent_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RW(config_send_uevent);

static ssize_t config_read_fw_idx_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

static ssize_t config_read_fw_idx_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RW(config_read_fw_idx);


static ssize_t trigger_request_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_request);

#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
extern struct list_head efi_embedded_fw_list;
extern bool efi_embedded_fw_checked;

static ssize_t trigger_request_platform_store(struct device *dev,
					      struct device_attribute *attr,
					      const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_request_platform);
#endif

static DECLARE_COMPLETION(async_fw_done);

static void trigger_async_request_cb(const struct firmware *fw, void *context)
{}

static ssize_t trigger_async_request_store(struct device *dev,
					   struct device_attribute *attr,
					   const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_async_request);

static ssize_t trigger_custom_fallback_store(struct device *dev,
					     struct device_attribute *attr,
					     const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_custom_fallback);

static int test_fw_run_batch_request(void *data)
{}

/*
 * We use a kthread as otherwise the kernel serializes all our sync requests
 * and we would not be able to mimic batched requests on a sync call. Batched
 * requests on a sync call can for instance happen on a device driver when
 * multiple cards are used and firmware loading happens outside of probe.
 */
static ssize_t trigger_batched_requests_store(struct device *dev,
					      struct device_attribute *attr,
					      const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_batched_requests);

/*
 * We wait for each callback to return with the lock held, no need to lock here
 */
static void trigger_batched_cb(const struct firmware *fw, void *context)
{}

static
ssize_t trigger_batched_requests_async_store(struct device *dev,
					     struct device_attribute *attr,
					     const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_batched_requests_async);

static void upload_release(struct test_firmware_upload *tst)
{}

static void upload_release_all(void)
{}

/*
 * This table is replicated from .../firmware_loader/sysfs_upload.c
 * and needs to be kept in sync.
 */
static const char * const fw_upload_err_str[] =;

static void upload_err_inject_error(struct test_firmware_upload *tst,
				    const u8 *p, const char *prog)
{}

static void upload_err_inject_prog(struct test_firmware_upload *tst,
				   const u8 *p)
{}

#define FIVE_MINUTES_MS
static enum fw_upload_err
fw_upload_wait_on_cancel(struct test_firmware_upload *tst)
{}

static enum fw_upload_err test_fw_upload_prepare(struct fw_upload *fwl,
						 const u8 *data, u32 size)
{}

static enum fw_upload_err test_fw_upload_write(struct fw_upload *fwl,
					       const u8 *data, u32 offset,
					       u32 size, u32 *written)
{}

static enum fw_upload_err test_fw_upload_complete(struct fw_upload *fwl)
{}

static void test_fw_upload_cancel(struct fw_upload *fwl)
{}

static void test_fw_cleanup(struct fw_upload *fwl)
{}

static const struct fw_upload_ops upload_test_ops =;

static ssize_t upload_register_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(upload_register);

static ssize_t upload_unregister_store(struct device *dev,
				       struct device_attribute *attr,
				       const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(upload_unregister);

static ssize_t test_result_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{}
static DEVICE_ATTR_RO(test_result);

static ssize_t release_all_firmware_store(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(release_all_firmware);

static ssize_t read_firmware_show(struct device *dev,
				  struct device_attribute *attr,
				  char *buf)
{}
static DEVICE_ATTR_RO(read_firmware);

static ssize_t upload_read_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{}
static DEVICE_ATTR_RO(upload_read);

#define TEST_FW_DEV_ATTR(name)

static struct attribute *test_dev_attrs[] =;

ATTRIBUTE_GROUPS();

static struct miscdevice test_fw_misc_device =;

static int __init test_firmware_init(void)
{}

module_init();

static void __exit test_firmware_exit(void)
{}

module_exit(test_firmware_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();