Project

General

Profile

Submit #3041 ยป fw-remove-parent.patch

Anonymous, 05/25/2017 05:23 AM

View differences:

share/examples/kld/firmware/wrap-fw_module.sh
int error;
switch (type) {
case MOD_LOAD:
fp = firmware_register("${MODNAME}", _binary_${FWSYM}_start , (size_t)(_binary_${FWSYM}_end - _binary_${FWSYM}_start), 0, NULL);
fp = firmware_register("${MODNAME}", _binary_${FWSYM}_start , (size_t)(_binary_${FWSYM}_end - _binary_${FWSYM}_start), 0);
if (fp == NULL)
goto fail_0;
return (0);
share/man/man9/firmware.9
.Fa "const void *data"
.Fa "size_t datasize"
.Fa "unsigned int version"
.Fa "const struct firmware *parent"
.Fc
.Ft int
.Fn firmware_unregister "const char *imagename"
......
.Nm kern.module_path
which on most systems defaults to
.Nm /boot/kernel;/boot/modules .
.Pp
Note that in case a module contains multiple images,
the caller should first request a
.Fn firmware_get
for the first image contained in the module, followed by requests
for the other images.
.Sh BUILDING FIRMWARE LOADABLE MODULES
A firmware module is built by embedding the
.Nm firmware image
......
.include <bsd.kmod.mk>
.Ed
where KMOD is the basename of the module; FIRMWS is a list of
colon-separated tuples indicating the image_file's to be embedded
in the module, the imagename and version of each firmware image.
where KMOD is the basename of the module; FIRMWS is a colon-separated
tuple indicating the image_file to be embedded in the module, the
imagename and version of the firmware image.
.Pp
If you need to embed firmware images into a system, you should write
appropriate entries in the
sys/dev/disk/ispfw/ispfw.c
break; \
if (firmware_register(#token, token##_risc_code, \
token##_risc_code[3] * sizeof(token##_risc_code[3]), \
ISPFW_VERSION, NULL) == NULL) { \
ISPFW_VERSION) == NULL) { \
kprintf("%s: unable to register firmware <%s>\n", \
MODULE_NAME, #token); \
break; \
sys/kern/subr_firmware.c
*
* In order for the above to work, the 'file' field must remain
* unchanged in firmware_unregister().
*
* Images residing in the same module are linked to each other
* through the 'parent' argument of firmware_register().
* One image (typically, one with the same name as the module to let
* the autoloading mechanism work) is considered the parent image for
* all other images in the same module. Children affect the refcount
* on the parent image preventing improper unloading of the image itself.
*/
struct priv_fw {
int refcnt; /* reference count */
/*
* parent entry, see above. Set on firmware_register(),
* cleared on firmware_unregister().
*/
struct priv_fw *parent;
int flags; /* record FIRMWARE_UNLOAD requests */
#define FW_UNLOAD 0x100
......
/*
* Register a firmware image with the specified name. The
* image name must not already be registered. If this is a
* subimage then parent refers to a previously registered
* image that this should be associated with.
* image name must not already be registered.
*/
const struct firmware *
firmware_register(const char *imagename, const void *data, size_t datasize,
unsigned int version, const struct firmware *parent)
unsigned int version)
{
struct priv_fw *match, *frp;
......
frp->fw.data = data;
frp->fw.datasize = datasize;
frp->fw.version = version;
if (parent != NULL) {
frp->parent = PRIV_FW(parent);
frp->parent->refcnt++;
}
lockmgr(&firmware_lock, LK_RELEASE);
if (bootverbose)
kprintf("firmware: '%s' version %u: %zu bytes loaded at %p\n",
......
/*
* It is ok for the lookup to fail; this can happen
* when a module is unloaded on last reference and the
* module unload handler unregister's each of it's
* firmware images.
* module unload handler unregisters it's firmware
* image.
*/
err = 0;
} else if (fp->refcnt != 0) { /* cannot unregister */
......
} else {
linker_file_t x = fp->file; /* save value */
if (fp->parent != NULL) /* release parent reference */
fp->parent->refcnt--;
/*
* Clear the whole entry with bzero to make sure we
* do not forget anything. Then restore 'file' which is
......
static void
unloadentry(void *unused1, int unused2)
{
int limit = FIRMWARE_MAX;
int i; /* current cycle */
int i;
lockmgr(&firmware_lock, LK_EXCLUSIVE);
/*
* Scan the table. limit is set to make sure we make another
* full sweep after matching an entry that requires unloading.
*/
for (i = 0; i < limit; i++) {
/* Scan the table. */
for (i = 0; i < FIRMWARE_MAX; i++) {
struct priv_fw *fp;
int err;
fp = &firmware_table[i % FIRMWARE_MAX];
fp = &firmware_table[i];
if (fp->fw.name == NULL || fp->file == NULL ||
fp->refcnt != 0 || (fp->flags & FW_UNLOAD) == 0)
continue;
/*
* Found an entry. Now:
* 1. bump up limit to make sure we make another full round;
* 2. clear FW_UNLOAD so we don't try this entry again.
* 3. release the lock while trying to unload the module.
* 1. clear FW_UNLOAD so we don't try this entry again
* if unloading will be unsuccessful.
* 2. release the lock while trying to unload the module.
* 'file' remains set so that the entry cannot be reused
* in the meantime (it also means that fp->file will
* not change while we release the lock).
*/
limit = i + FIRMWARE_MAX; /* make another full round */
fp->flags &= ~FW_UNLOAD; /* do not try again */
lockmgr(&firmware_lock, LK_RELEASE);
sys/sys/firmware.h
* The firmware abstraction provides an interface for loading firmware
* images into the kernel and making them available to clients.
*
* Firmware images are usually embedded in kernel loadable modules that can
* be loaded on-demand or pre-loaded as desired. Modules may contain
* one or more firmware images that are stored as opaque data arrays
* and registered with a unique string name. Clients request
* firmware by name, and are returned a struct firmware * below on success.
* The kernel keeps track of references to firmware images to allow/prevent
* module/data unload.
* Firmware images are usually embedded in kernel loadable modules
* that can be loaded on-demand or pre-loaded as desired. Modules may
* contain one firmware image that is stored as opaque data array and
* registered with a unique string name. Clients request firmware by
* name, and are returned a struct firmware * below on success. The
* kernel keeps track of references to firmware images to
* allow/prevent module/data unload.
*
* When multiple images are stored in one module, the first image is
* treated as the master with the other images holding references
* to it. This means that to unload the module each dependent/subimage
* must first have its references removed.
* In order for automatic loading to work, the master image must have
* the same name as the module it is embedded into.
*/
......
};
const struct firmware *firmware_register(const char *,
const void *, size_t, unsigned int, const struct firmware *);
const void *, size_t, unsigned int);
int firmware_unregister(const char *);
const struct firmware *firmware_get(const char *);
#define FIRMWARE_UNLOAD 0x0001 /* unload if unreferenced */
sys/tools/fw_stub.awk
function usage ()
{
print "usage: fw_stub <firmware:name>* [-l name] [-m modname] [-c outfile]";
print "usage: fw_stub <firmware:name> [-l name] [-m modname] [-c outfile]";
exit 1;
}
......
} else
usage();
}
} else {
} else if (num_files == 0) {
split(ARGV[i], curr, ":");
filenames[num_files] = curr[1];
filename = curr[1];
if (length(curr[2]) > 0)
shortnames[num_files] = curr[2];
shortname = curr[2];
else
shortnames[num_files] = curr[1];
shortname = curr[1];
if (length(curr[3]) > 0)
versions[num_files] = int(curr[3]);
version = int(curr[3]);
else
versions[num_files] = 0;
version = 0;
num_files++;
} else {
# The argument is a firmware image specification
# but we already have one
usage();
}
}
......
printc("static long " opt_l "_license_ack = 0;");
}
for (file_i = 0; file_i < num_files; file_i++) {
symb = filenames[file_i];
# '-', '.' and '/' are converted to '_' by ld/objcopy
gsub(/-|\.|\//, "_", symb);
printc("extern char _binary_" symb "_start[], _binary_" symb "_end[];");
}
symb = filename;
# '-', '.' and '/' are converted to '_' by ld/objcopy
gsub(/-|\.|\//, "_", symb);
printc("extern char _binary_" symb "_start[], _binary_" symb "_end[];");
printc("\nstatic int\n"\
modname "_fw_modevent(module_t mod, int type, void *unused)\
{\
const struct firmware *fp;");
if (num_files > 1)
printc("\tconst struct firmware *parent;");
printc("\tint error;\
switch (type) {\
case MOD_LOAD:\n");
......
}\n");
}
for (file_i = 0; file_i < num_files; file_i++) {
short = shortnames[file_i];
symb = filenames[file_i];
version = versions[file_i];
# '-', '.' and '/' are converted to '_' by ld/objcopy
gsub(/-|\.|\//, "_", symb);
short = shortname;
symb = filename;
version = version;
# '-', '.' and '/' are converted to '_' by ld/objcopy
gsub(/-|\.|\//, "_", symb);
reg = "\t\tfp = ";
reg = reg "firmware_register(\"" short "\", _binary_" symb "_start , ";
reg = reg "(size_t)(_binary_" symb "_end - _binary_" symb "_start), ";
reg = reg version ", ";
reg = "\t\tfp = ";
reg = reg "firmware_register(\"" short "\", _binary_" symb "_start , ";
reg = reg "(size_t)(_binary_" symb "_end - _binary_" symb "_start), ";
reg = reg version ");";
if (file_i == 0)
reg = reg "NULL);";
else
reg = reg "parent);";
printc(reg);
printc(reg);
printc("\t\tif (fp == NULL)");
printc("\t\t\tgoto fail_" file_i ";");
if (file_i == 0 && num_files > 1)
printc("\t\tparent = fp;");
}
printc("\t\tif (fp == NULL)");
printc("\t\t\tgoto fail;");
printc("\t\treturn (0);");
for (file_i = num_files - 1; file_i > 0; file_i--) {
printc("fail_" file_i ":")
printc("\t\t(void)firmware_unregister(\"" shortnames[file_i - 1] "\");");
}
printc("\tfail_0:");
printc("\tfail:");
printc("\t\treturn (ENXIO);");
printc("\tcase MOD_UNLOAD:");
for (file_i = 1; file_i < num_files; file_i++) {
printc("\t\terror = firmware_unregister(\"" shortnames[file_i] "\");");
printc("\t\tif (error)");
printc("\t\t\treturn (error);");
}
printc("\t\terror = firmware_unregister(\"" shortnames[0] "\");");
printc("\t\terror = firmware_unregister(\"" shortname "\");");
printc("\t\treturn (error);\
}\
    (1-1/1)