Submit #3041 ยป fw-remove-parent.patch
share/examples/kld/firmware/wrap-fw_module.sh | ||
---|---|---|
70 | 70 |
int error; |
71 | 71 |
switch (type) { |
72 | 72 |
case MOD_LOAD: |
73 |
fp = firmware_register("${MODNAME}", _binary_${FWSYM}_start , (size_t)(_binary_${FWSYM}_end - _binary_${FWSYM}_start), 0, NULL);
|
|
73 |
fp = firmware_register("${MODNAME}", _binary_${FWSYM}_start , (size_t)(_binary_${FWSYM}_end - _binary_${FWSYM}_start), 0); |
|
74 | 74 |
if (fp == NULL) |
75 | 75 |
goto fail_0; |
76 | 76 |
return (0); |
share/man/man9/firmware.9 | ||
---|---|---|
51 | 51 |
.Fa "const void *data" |
52 | 52 |
.Fa "size_t datasize" |
53 | 53 |
.Fa "unsigned int version" |
54 |
.Fa "const struct firmware *parent" |
|
55 | 54 |
.Fc |
56 | 55 |
.Ft int |
57 | 56 |
.Fn firmware_unregister "const char *imagename" |
... | ... | |
195 | 194 |
.Nm kern.module_path |
196 | 195 |
which on most systems defaults to |
197 | 196 |
.Nm /boot/kernel;/boot/modules . |
198 |
.Pp |
|
199 |
Note that in case a module contains multiple images, |
|
200 |
the caller should first request a |
|
201 |
.Fn firmware_get |
|
202 |
for the first image contained in the module, followed by requests |
|
203 |
for the other images. |
|
204 | 197 |
.Sh BUILDING FIRMWARE LOADABLE MODULES |
205 | 198 |
A firmware module is built by embedding the |
206 | 199 |
.Nm firmware image |
... | ... | |
219 | 212 |
.include <bsd.kmod.mk> |
220 | 213 | |
221 | 214 |
.Ed |
222 |
where KMOD is the basename of the module; FIRMWS is a list of
|
|
223 |
colon-separated tuples indicating the image_file's to be embedded |
|
224 |
in the module, the imagename and version of each firmware image.
|
|
215 |
where KMOD is the basename of the module; FIRMWS is a colon-separated
|
|
216 |
tuple indicating the image_file to be embedded in the module, the |
|
217 |
imagename and version of the firmware image.
|
|
225 | 218 |
.Pp |
226 | 219 |
If you need to embed firmware images into a system, you should write |
227 | 220 |
appropriate entries in the |
sys/dev/disk/ispfw/ispfw.c | ||
---|---|---|
143 | 143 |
break; \ |
144 | 144 |
if (firmware_register(#token, token##_risc_code, \ |
145 | 145 |
token##_risc_code[3] * sizeof(token##_risc_code[3]), \ |
146 |
ISPFW_VERSION, NULL) == NULL) { \
|
|
146 |
ISPFW_VERSION) == NULL) { \
|
|
147 | 147 |
kprintf("%s: unable to register firmware <%s>\n", \ |
148 | 148 |
MODULE_NAME, #token); \ |
149 | 149 |
break; \ |
sys/kern/subr_firmware.c | ||
---|---|---|
69 | 69 |
* |
70 | 70 |
* In order for the above to work, the 'file' field must remain |
71 | 71 |
* unchanged in firmware_unregister(). |
72 |
* |
|
73 |
* Images residing in the same module are linked to each other |
|
74 |
* through the 'parent' argument of firmware_register(). |
|
75 |
* One image (typically, one with the same name as the module to let |
|
76 |
* the autoloading mechanism work) is considered the parent image for |
|
77 |
* all other images in the same module. Children affect the refcount |
|
78 |
* on the parent image preventing improper unloading of the image itself. |
|
79 | 72 |
*/ |
80 | 73 | |
81 | 74 |
struct priv_fw { |
82 | 75 |
int refcnt; /* reference count */ |
83 | 76 | |
84 |
/* |
|
85 |
* parent entry, see above. Set on firmware_register(), |
|
86 |
* cleared on firmware_unregister(). |
|
87 |
*/ |
|
88 |
struct priv_fw *parent; |
|
89 | ||
90 | 77 |
int flags; /* record FIRMWARE_UNLOAD requests */ |
91 | 78 |
#define FW_UNLOAD 0x100 |
92 | 79 | |
... | ... | |
165 | 152 | |
166 | 153 |
/* |
167 | 154 |
* Register a firmware image with the specified name. The |
168 |
* image name must not already be registered. If this is a |
|
169 |
* subimage then parent refers to a previously registered |
|
170 |
* image that this should be associated with. |
|
155 |
* image name must not already be registered. |
|
171 | 156 |
*/ |
172 | 157 |
const struct firmware * |
173 | 158 |
firmware_register(const char *imagename, const void *data, size_t datasize, |
174 |
unsigned int version, const struct firmware *parent)
|
|
159 |
unsigned int version) |
|
175 | 160 |
{ |
176 | 161 |
struct priv_fw *match, *frp; |
177 | 162 | |
... | ... | |
197 | 182 |
frp->fw.data = data; |
198 | 183 |
frp->fw.datasize = datasize; |
199 | 184 |
frp->fw.version = version; |
200 |
if (parent != NULL) { |
|
201 |
frp->parent = PRIV_FW(parent); |
|
202 |
frp->parent->refcnt++; |
|
203 |
} |
|
185 | ||
204 | 186 |
lockmgr(&firmware_lock, LK_RELEASE); |
205 | 187 |
if (bootverbose) |
206 | 188 |
kprintf("firmware: '%s' version %u: %zu bytes loaded at %p\n", |
... | ... | |
225 | 207 |
/* |
226 | 208 |
* It is ok for the lookup to fail; this can happen |
227 | 209 |
* when a module is unloaded on last reference and the |
228 |
* module unload handler unregister's each of it's
|
|
229 |
* firmware images.
|
|
210 |
* module unload handler unregisters it's firmware
|
|
211 |
* image.
|
|
230 | 212 |
*/ |
231 | 213 |
err = 0; |
232 | 214 |
} else if (fp->refcnt != 0) { /* cannot unregister */ |
... | ... | |
234 | 216 |
} else { |
235 | 217 |
linker_file_t x = fp->file; /* save value */ |
236 | 218 | |
237 |
if (fp->parent != NULL) /* release parent reference */ |
|
238 |
fp->parent->refcnt--; |
|
239 | 219 |
/* |
240 | 220 |
* Clear the whole entry with bzero to make sure we |
241 | 221 |
* do not forget anything. Then restore 'file' which is |
... | ... | |
429 | 409 |
static void |
430 | 410 |
unloadentry(void *unused1, int unused2) |
431 | 411 |
{ |
432 |
int limit = FIRMWARE_MAX; |
|
433 |
int i; /* current cycle */ |
|
412 |
int i; |
|
434 | 413 | |
435 | 414 |
lockmgr(&firmware_lock, LK_EXCLUSIVE); |
436 |
/* |
|
437 |
* Scan the table. limit is set to make sure we make another |
|
438 |
* full sweep after matching an entry that requires unloading. |
|
439 |
*/ |
|
440 |
for (i = 0; i < limit; i++) { |
|
415 |
/* Scan the table. */ |
|
416 |
for (i = 0; i < FIRMWARE_MAX; i++) { |
|
441 | 417 |
struct priv_fw *fp; |
442 | 418 |
int err; |
443 | 419 | |
444 |
fp = &firmware_table[i % FIRMWARE_MAX];
|
|
420 |
fp = &firmware_table[i]; |
|
445 | 421 |
if (fp->fw.name == NULL || fp->file == NULL || |
446 | 422 |
fp->refcnt != 0 || (fp->flags & FW_UNLOAD) == 0) |
447 | 423 |
continue; |
448 | 424 | |
449 | 425 |
/* |
450 | 426 |
* Found an entry. Now: |
451 |
* 1. bump up limit to make sure we make another full round;
|
|
452 |
* 2. clear FW_UNLOAD so we don't try this entry again.
|
|
453 |
* 3. release the lock while trying to unload the module.
|
|
427 |
* 1. clear FW_UNLOAD so we don't try this entry again
|
|
428 |
* if unloading will be unsuccessful.
|
|
429 |
* 2. release the lock while trying to unload the module.
|
|
454 | 430 |
* 'file' remains set so that the entry cannot be reused |
455 | 431 |
* in the meantime (it also means that fp->file will |
456 | 432 |
* not change while we release the lock). |
457 | 433 |
*/ |
458 |
limit = i + FIRMWARE_MAX; /* make another full round */ |
|
459 | 434 |
fp->flags &= ~FW_UNLOAD; /* do not try again */ |
460 | 435 | |
461 | 436 |
lockmgr(&firmware_lock, LK_RELEASE); |
sys/sys/firmware.h | ||
---|---|---|
33 | 33 |
* The firmware abstraction provides an interface for loading firmware |
34 | 34 |
* images into the kernel and making them available to clients. |
35 | 35 |
* |
36 |
* Firmware images are usually embedded in kernel loadable modules that can
|
|
37 |
* be loaded on-demand or pre-loaded as desired. Modules may contain
|
|
38 |
* one or more firmware images that are stored as opaque data arrays
|
|
39 |
* and registered with a unique string name. Clients request
|
|
40 |
* firmware by name, and are returned a struct firmware * below on success.
|
|
41 |
* The kernel keeps track of references to firmware images to allow/prevent
|
|
42 |
* module/data unload. |
|
36 |
* Firmware images are usually embedded in kernel loadable modules |
|
37 |
* that can be loaded on-demand or pre-loaded as desired. Modules may
|
|
38 |
* contain one firmware image that is stored as opaque data array and
|
|
39 |
* registered with a unique string name. Clients request firmware by
|
|
40 |
* name, and are returned a struct firmware * below on success. The
|
|
41 |
* kernel keeps track of references to firmware images to
|
|
42 |
* allow/prevent module/data unload.
|
|
43 | 43 |
* |
44 |
* When multiple images are stored in one module, the first image is |
|
45 |
* treated as the master with the other images holding references |
|
46 |
* to it. This means that to unload the module each dependent/subimage |
|
47 |
* must first have its references removed. |
|
48 | 44 |
* In order for automatic loading to work, the master image must have |
49 | 45 |
* the same name as the module it is embedded into. |
50 | 46 |
*/ |
... | ... | |
56 | 52 |
}; |
57 | 53 | |
58 | 54 |
const struct firmware *firmware_register(const char *, |
59 |
const void *, size_t, unsigned int, const struct firmware *);
|
|
55 |
const void *, size_t, unsigned int); |
|
60 | 56 |
int firmware_unregister(const char *); |
61 | 57 |
const struct firmware *firmware_get(const char *); |
62 | 58 |
#define FIRMWARE_UNLOAD 0x0001 /* unload if unreferenced */ |
sys/tools/fw_stub.awk | ||
---|---|---|
33 | 33 | |
34 | 34 |
function usage () |
35 | 35 |
{ |
36 |
print "usage: fw_stub <firmware:name>* [-l name] [-m modname] [-c outfile]";
|
|
36 |
print "usage: fw_stub <firmware:name> [-l name] [-m modname] [-c outfile]"; |
|
37 | 37 |
exit 1; |
38 | 38 |
} |
39 | 39 | |
... | ... | |
98 | 98 |
} else |
99 | 99 |
usage(); |
100 | 100 |
} |
101 |
} else { |
|
101 |
} else if (num_files == 0) {
|
|
102 | 102 |
split(ARGV[i], curr, ":"); |
103 |
filenames[num_files] = curr[1];
|
|
103 |
filename = curr[1]; |
|
104 | 104 |
if (length(curr[2]) > 0) |
105 |
shortnames[num_files] = curr[2];
|
|
105 |
shortname = curr[2]; |
|
106 | 106 |
else |
107 |
shortnames[num_files] = curr[1];
|
|
107 |
shortname = curr[1]; |
|
108 | 108 |
if (length(curr[3]) > 0) |
109 |
versions[num_files] = int(curr[3]);
|
|
109 |
version = int(curr[3]); |
|
110 | 110 |
else |
111 |
versions[num_files] = 0;
|
|
111 |
version = 0; |
|
112 | 112 |
num_files++; |
113 |
} else { |
|
114 |
# The argument is a firmware image specification |
|
115 |
# but we already have one |
|
116 |
usage(); |
|
113 | 117 |
} |
114 | 118 |
} |
115 | 119 | |
... | ... | |
133 | 137 |
printc("static long " opt_l "_license_ack = 0;"); |
134 | 138 |
} |
135 | 139 | |
136 |
for (file_i = 0; file_i < num_files; file_i++) { |
|
137 |
symb = filenames[file_i]; |
|
138 |
# '-', '.' and '/' are converted to '_' by ld/objcopy |
|
139 |
gsub(/-|\.|\//, "_", symb); |
|
140 |
printc("extern char _binary_" symb "_start[], _binary_" symb "_end[];"); |
|
141 |
} |
|
140 |
symb = filename; |
|
141 |
# '-', '.' and '/' are converted to '_' by ld/objcopy |
|
142 |
gsub(/-|\.|\//, "_", symb); |
|
143 |
printc("extern char _binary_" symb "_start[], _binary_" symb "_end[];"); |
|
142 | 144 | |
143 | 145 |
printc("\nstatic int\n"\ |
144 | 146 |
modname "_fw_modevent(module_t mod, int type, void *unused)\ |
145 | 147 |
{\ |
146 | 148 |
const struct firmware *fp;"); |
147 | 149 | |
148 |
if (num_files > 1) |
|
149 |
printc("\tconst struct firmware *parent;"); |
|
150 | ||
151 | 150 |
printc("\tint error;\ |
152 | 151 |
switch (type) {\ |
153 | 152 |
case MOD_LOAD:\n"); |
... | ... | |
162 | 161 |
}\n"); |
163 | 162 |
} |
164 | 163 | |
165 |
for (file_i = 0; file_i < num_files; file_i++) { |
|
166 |
short = shortnames[file_i]; |
|
167 |
symb = filenames[file_i]; |
|
168 |
version = versions[file_i]; |
|
169 |
# '-', '.' and '/' are converted to '_' by ld/objcopy |
|
170 |
gsub(/-|\.|\//, "_", symb); |
|
164 |
short = shortname; |
|
165 |
symb = filename; |
|
166 |
version = version; |
|
167 |
# '-', '.' and '/' are converted to '_' by ld/objcopy |
|
168 |
gsub(/-|\.|\//, "_", symb); |
|
171 | 169 | |
172 |
reg = "\t\tfp = ";
|
|
173 |
reg = reg "firmware_register(\"" short "\", _binary_" symb "_start , ";
|
|
174 |
reg = reg "(size_t)(_binary_" symb "_end - _binary_" symb "_start), ";
|
|
175 |
reg = reg version ", ";
|
|
170 |
reg = "\t\tfp = "; |
|
171 |
reg = reg "firmware_register(\"" short "\", _binary_" symb "_start , "; |
|
172 |
reg = reg "(size_t)(_binary_" symb "_end - _binary_" symb "_start), "; |
|
173 |
reg = reg version ");";
|
|
176 | 174 | |
177 |
if (file_i == 0) |
|
178 |
reg = reg "NULL);"; |
|
179 |
else |
|
180 |
reg = reg "parent);"; |
|
175 |
printc(reg); |
|
181 | 176 | |
182 |
printc(reg); |
|
183 | ||
184 |
printc("\t\tif (fp == NULL)"); |
|
185 |
printc("\t\t\tgoto fail_" file_i ";"); |
|
186 |
if (file_i == 0 && num_files > 1) |
|
187 |
printc("\t\tparent = fp;"); |
|
188 |
} |
|
177 |
printc("\t\tif (fp == NULL)"); |
|
178 |
printc("\t\t\tgoto fail;"); |
|
189 | 179 | |
190 | 180 |
printc("\t\treturn (0);"); |
191 | 181 | |
192 |
for (file_i = num_files - 1; file_i > 0; file_i--) { |
|
193 |
printc("fail_" file_i ":") |
|
194 |
printc("\t\t(void)firmware_unregister(\"" shortnames[file_i - 1] "\");"); |
|
195 |
} |
|
196 | ||
197 |
printc("\tfail_0:"); |
|
182 |
printc("\tfail:"); |
|
198 | 183 |
printc("\t\treturn (ENXIO);"); |
199 | 184 | |
200 | 185 |
printc("\tcase MOD_UNLOAD:"); |
201 | 186 | |
202 |
for (file_i = 1; file_i < num_files; file_i++) { |
|
203 |
printc("\t\terror = firmware_unregister(\"" shortnames[file_i] "\");"); |
|
204 |
printc("\t\tif (error)"); |
|
205 |
printc("\t\t\treturn (error);"); |
|
206 |
} |
|
207 | ||
208 |
printc("\t\terror = firmware_unregister(\"" shortnames[0] "\");"); |
|
187 |
printc("\t\terror = firmware_unregister(\"" shortname "\");"); |
|
209 | 188 | |
210 | 189 |
printc("\t\treturn (error);\ |
211 | 190 |
}\ |