]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_firmware.c
nmount: Ignore errors when copying out an error string
[FreeBSD/FreeBSD.git] / sys / kern / subr_firmware.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2005-2008, Sam Leffler <sam@errno.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/queue.h>
34 #include <sys/taskqueue.h>
35 #include <sys/systm.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/errno.h>
39 #include <sys/linker.h>
40 #include <sys/firmware.h>
41 #include <sys/priv.h>
42 #include <sys/proc.h>
43 #include <sys/module.h>
44 #include <sys/eventhandler.h>
45
46 #include <sys/filedesc.h>
47 #include <sys/vnode.h>
48
49 /*
50  * Loadable firmware support. See sys/sys/firmware.h and firmware(9)
51  * form more details on the subsystem.
52  *
53  * 'struct firmware' is the user-visible part of the firmware table.
54  * Additional internal information is stored in a 'struct priv_fw',
55  * which embeds the public firmware structure.
56  */
57
58 /*
59  * fw.name != NULL when an image is registered; file != NULL for
60  * autoloaded images whose handling has not been completed.
61  *
62  * The state of a slot evolves as follows:
63  *      firmware_register       -->  fw.name = image_name
64  *      (autoloaded image)      -->  file = module reference
65  *      firmware_unregister     -->  fw.name = NULL
66  *      (unloadentry complete)  -->  file = NULL
67  *
68  * In order for the above to work, the 'file' field must remain
69  * unchanged in firmware_unregister().
70  *
71  * Images residing in the same module are linked to each other
72  * through the 'parent' argument of firmware_register().
73  * One image (typically, one with the same name as the module to let
74  * the autoloading mechanism work) is considered the parent image for
75  * all other images in the same module. Children affect the refcount
76  * on the parent image preventing improper unloading of the image itself.
77  */
78
79 struct priv_fw {
80         int             refcnt;         /* reference count */
81         LIST_ENTRY(priv_fw) link;       /* table linkage */
82
83         /*
84          * parent entry, see above. Set on firmware_register(),
85          * cleared on firmware_unregister().
86          */
87         struct priv_fw  *parent;
88
89         int             flags;  /* record FIRMWARE_UNLOAD requests */
90 #define FW_UNLOAD       0x100
91
92         /*
93          * 'file' is private info managed by the autoload/unload code.
94          * Set at the end of firmware_get(), cleared only in the
95          * firmware_unload_task, so the latter can depend on its value even
96          * while the lock is not held.
97          */
98         linker_file_t   file;   /* module file, if autoloaded */
99
100         /*
101          * 'fw' is the externally visible image information.
102          * We do not make it the first field in priv_fw, to avoid the
103          * temptation of casting pointers to each other.
104          * Use PRIV_FW(fw) to get a pointer to the cointainer of fw.
105          * Beware, PRIV_FW does not work for a NULL pointer.
106          */
107         struct firmware fw;     /* externally visible information */
108 };
109
110 /*
111  * PRIV_FW returns the pointer to the container of struct firmware *x.
112  * Cast to intptr_t to override the 'const' attribute of x
113  */
114 #define PRIV_FW(x)      ((struct priv_fw *)             \
115         ((intptr_t)(x) - offsetof(struct priv_fw, fw)) )
116
117 /*
118  * Global firmware image registry.
119  */
120 static LIST_HEAD(, priv_fw) firmware_table;
121
122 /*
123  * Firmware module operations are handled in a separate task as they
124  * might sleep and they require directory context to do i/o.
125  */
126 static struct taskqueue *firmware_tq;
127 static struct task firmware_unload_task;
128
129 /*
130  * This mutex protects accesses to the firmware table.
131  */
132 static struct mtx firmware_mtx;
133 MTX_SYSINIT(firmware, &firmware_mtx, "firmware table", MTX_DEF);
134
135 static MALLOC_DEFINE(M_FIRMWARE, "firmware", "device firmware images");
136
137 /*
138  * Helper function to lookup a name.
139  * As a side effect, it sets the pointer to a free slot, if any.
140  * This way we can concentrate most of the registry scanning in
141  * this function, which makes it easier to replace the registry
142  * with some other data structure.
143  */
144 static struct priv_fw *
145 lookup(const char *name)
146 {
147         struct priv_fw *fp;
148
149         mtx_assert(&firmware_mtx, MA_OWNED);
150
151         LIST_FOREACH(fp, &firmware_table, link) {
152                 if (fp->fw.name != NULL && strcasecmp(name, fp->fw.name) == 0)
153                         break;
154         }
155         return (fp);
156 }
157
158 /*
159  * Register a firmware image with the specified name.  The
160  * image name must not already be registered.  If this is a
161  * subimage then parent refers to a previously registered
162  * image that this should be associated with.
163  */
164 const struct firmware *
165 firmware_register(const char *imagename, const void *data, size_t datasize,
166     unsigned int version, const struct firmware *parent)
167 {
168         struct priv_fw *frp;
169         char *name;
170
171         mtx_lock(&firmware_mtx);
172         frp = lookup(imagename);
173         if (frp != NULL) {
174                 mtx_unlock(&firmware_mtx);
175                 printf("%s: image %s already registered!\n",
176                     __func__, imagename);
177                 return (NULL);
178         }
179         mtx_unlock(&firmware_mtx);
180
181         frp = malloc(sizeof(*frp), M_FIRMWARE, M_WAITOK | M_ZERO);
182         name = strdup(imagename, M_FIRMWARE);
183
184         mtx_lock(&firmware_mtx);
185         if (lookup(imagename) != NULL) {
186                 /* We lost a race. */
187                 mtx_unlock(&firmware_mtx);
188                 free(name, M_FIRMWARE);
189                 free(frp, M_FIRMWARE);
190                 return (NULL);
191         }
192         frp->fw.name = name;
193         frp->fw.data = data;
194         frp->fw.datasize = datasize;
195         frp->fw.version = version;
196         if (parent != NULL)
197                 frp->parent = PRIV_FW(parent);
198         LIST_INSERT_HEAD(&firmware_table, frp, link);
199         mtx_unlock(&firmware_mtx);
200         if (bootverbose)
201                 printf("firmware: '%s' version %u: %zu bytes loaded at %p\n",
202                     imagename, version, datasize, data);
203         return (&frp->fw);
204 }
205
206 /*
207  * Unregister/remove a firmware image.  If there are outstanding
208  * references an error is returned and the image is not removed
209  * from the registry.
210  */
211 int
212 firmware_unregister(const char *imagename)
213 {
214         struct priv_fw *fp;
215         int err;
216
217         mtx_lock(&firmware_mtx);
218         fp = lookup(imagename);
219         if (fp == NULL) {
220                 /*
221                  * It is ok for the lookup to fail; this can happen
222                  * when a module is unloaded on last reference and the
223                  * module unload handler unregister's each of its
224                  * firmware images.
225                  */
226                 err = 0;
227         } else if (fp->refcnt != 0) {   /* cannot unregister */
228                 err = EBUSY;
229         } else {
230                 LIST_REMOVE(fp, link);
231                 free(__DECONST(char *, fp->fw.name), M_FIRMWARE);
232                 free(fp, M_FIRMWARE);
233                 err = 0;
234         }
235         mtx_unlock(&firmware_mtx);
236         return (err);
237 }
238
239 struct fw_loadimage {
240         const char      *imagename;
241         uint32_t        flags;
242 };
243
244 static void
245 loadimage(void *arg, int npending __unused)
246 {
247         struct fw_loadimage *fwli = arg;
248         struct priv_fw *fp;
249         linker_file_t result;
250         int error;
251
252         error = linker_reference_module(fwli->imagename, NULL, &result);
253         if (error != 0) {
254                 if (bootverbose || (fwli->flags & FIRMWARE_GET_NOWARN) == 0)
255                         printf("%s: could not load firmware image, error %d\n",
256                             fwli->imagename, error);
257                 mtx_lock(&firmware_mtx);
258                 goto done;
259         }
260
261         mtx_lock(&firmware_mtx);
262         fp = lookup(fwli->imagename);
263         if (fp == NULL || fp->file != NULL) {
264                 mtx_unlock(&firmware_mtx);
265                 if (fp == NULL)
266                         printf("%s: firmware image loaded, "
267                             "but did not register\n", fwli->imagename);
268                 (void) linker_release_module(fwli->imagename, NULL, NULL);
269                 mtx_lock(&firmware_mtx);
270                 goto done;
271         }
272         fp->file = result;      /* record the module identity */
273 done:
274         wakeup_one(arg);
275         mtx_unlock(&firmware_mtx);
276 }
277
278 /*
279  * Lookup and potentially load the specified firmware image.
280  * If the firmware is not found in the registry, try to load a kernel
281  * module named as the image name.
282  * If the firmware is located, a reference is returned. The caller must
283  * release this reference for the image to be eligible for removal/unload.
284  */
285 const struct firmware *
286 firmware_get_flags(const char *imagename, uint32_t flags)
287 {
288         struct task fwload_task;
289         struct thread *td;
290         struct priv_fw *fp;
291
292         mtx_lock(&firmware_mtx);
293         fp = lookup(imagename);
294         if (fp != NULL)
295                 goto found;
296         /*
297          * Image not present, try to load the module holding it.
298          */
299         td = curthread;
300         if (priv_check(td, PRIV_FIRMWARE_LOAD) != 0 ||
301             securelevel_gt(td->td_ucred, 0) != 0) {
302                 mtx_unlock(&firmware_mtx);
303                 printf("%s: insufficient privileges to "
304                     "load firmware image %s\n", __func__, imagename);
305                 return NULL;
306         }
307         /*
308          * Defer load to a thread with known context.  linker_reference_module
309          * may do filesystem i/o which requires root & current dirs, etc.
310          * Also we must not hold any mtx's over this call which is problematic.
311          */
312         if (!cold) {
313                 struct fw_loadimage fwli;
314
315                 fwli.imagename = imagename;
316                 fwli.flags = flags;
317                 TASK_INIT(&fwload_task, 0, loadimage, (void *)&fwli);
318                 taskqueue_enqueue(firmware_tq, &fwload_task);
319                 PHOLD(curproc);
320                 msleep((void *)&fwli, &firmware_mtx, 0, "fwload", 0);
321                 PRELE(curproc);
322         }
323         /*
324          * After attempting to load the module, see if the image is registered.
325          */
326         fp = lookup(imagename);
327         if (fp == NULL) {
328                 mtx_unlock(&firmware_mtx);
329                 return NULL;
330         }
331 found:                          /* common exit point on success */
332         if (fp->refcnt == 0 && fp->parent != NULL)
333                 fp->parent->refcnt++;
334         fp->refcnt++;
335         mtx_unlock(&firmware_mtx);
336         return &fp->fw;
337 }
338
339 const struct firmware *
340 firmware_get(const char *imagename)
341 {
342
343         return (firmware_get_flags(imagename, 0));
344 }
345
346 /*
347  * Release a reference to a firmware image returned by firmware_get.
348  * The caller may specify, with the FIRMWARE_UNLOAD flag, its desire
349  * to release the resource, but the flag is only advisory.
350  *
351  * If this is the last reference to the firmware image, and this is an
352  * autoloaded module, wake up the firmware_unload_task to figure out
353  * what to do with the associated module.
354  */
355 void
356 firmware_put(const struct firmware *p, int flags)
357 {
358         struct priv_fw *fp = PRIV_FW(p);
359
360         mtx_lock(&firmware_mtx);
361         fp->refcnt--;
362         if (fp->refcnt == 0) {
363                 if (fp->parent != NULL)
364                         fp->parent->refcnt--;
365                 if (flags & FIRMWARE_UNLOAD)
366                         fp->flags |= FW_UNLOAD;
367                 if (fp->file)
368                         taskqueue_enqueue(firmware_tq, &firmware_unload_task);
369         }
370         mtx_unlock(&firmware_mtx);
371 }
372
373 /*
374  * Setup directory state for the firmware_tq thread so we can do i/o.
375  */
376 static void
377 set_rootvnode(void *arg, int npending)
378 {
379
380         pwd_ensure_dirs();
381         free(arg, M_TEMP);
382 }
383
384 /*
385  * Event handler called on mounting of /; bounce a task
386  * into the task queue thread to setup it's directories.
387  */
388 static void
389 firmware_mountroot(void *arg)
390 {
391         struct task *setroot_task;
392
393         setroot_task = malloc(sizeof(struct task), M_TEMP, M_NOWAIT);
394         if (setroot_task != NULL) {
395                 TASK_INIT(setroot_task, 0, set_rootvnode, setroot_task);
396                 taskqueue_enqueue(firmware_tq, setroot_task);
397         } else
398                 printf("%s: no memory for task!\n", __func__);
399 }
400 EVENTHANDLER_DEFINE(mountroot, firmware_mountroot, NULL, 0);
401
402 /*
403  * The body of the task in charge of unloading autoloaded modules
404  * that are not needed anymore.
405  * Images can be cross-linked so we may need to make multiple passes,
406  * but the time we spend in the loop is bounded because we clear entries
407  * as we touch them.
408  */
409 static void
410 unloadentry(void *unused1, int unused2)
411 {
412         struct priv_fw *fp;
413
414         mtx_lock(&firmware_mtx);
415 restart:
416         LIST_FOREACH(fp, &firmware_table, link) {
417                 if (fp->file == NULL || fp->refcnt != 0 ||
418                     (fp->flags & FW_UNLOAD) == 0)
419                         continue;
420
421                 /*
422                  * Found an entry. Now:
423                  * 1. make sure we scan the table again
424                  * 2. clear FW_UNLOAD so we don't try this entry again.
425                  * 3. release the lock while trying to unload the module.
426                  */
427                 fp->flags &= ~FW_UNLOAD;        /* do not try again */
428
429                 /*
430                  * We rely on the module to call firmware_unregister()
431                  * on unload to actually free the entry.
432                  */
433                 mtx_unlock(&firmware_mtx);
434                 (void)linker_release_module(NULL, NULL, fp->file);
435                 mtx_lock(&firmware_mtx);
436
437                 /*
438                  * When we dropped the lock, another thread could have
439                  * removed an element, so we must restart the scan.
440                  */
441                 goto restart;
442         }
443         mtx_unlock(&firmware_mtx);
444 }
445
446 /*
447  * Module glue.
448  */
449 static int
450 firmware_modevent(module_t mod, int type, void *unused)
451 {
452         struct priv_fw *fp;
453         int err;
454
455         err = 0;
456         switch (type) {
457         case MOD_LOAD:
458                 TASK_INIT(&firmware_unload_task, 0, unloadentry, NULL);
459                 firmware_tq = taskqueue_create("taskqueue_firmware", M_WAITOK,
460                     taskqueue_thread_enqueue, &firmware_tq);
461                 /* NB: use our own loop routine that sets up context */
462                 (void) taskqueue_start_threads(&firmware_tq, 1, PWAIT,
463                     "firmware taskq");
464                 if (rootvnode != NULL) {
465                         /*
466                          * Root is already mounted so we won't get an event;
467                          * simulate one here.
468                          */
469                         firmware_mountroot(NULL);
470                 }
471                 break;
472
473         case MOD_UNLOAD:
474                 /* request all autoloaded modules to be released */
475                 mtx_lock(&firmware_mtx);
476                 LIST_FOREACH(fp, &firmware_table, link)
477                         fp->flags |= FW_UNLOAD;
478                 mtx_unlock(&firmware_mtx);
479                 taskqueue_enqueue(firmware_tq, &firmware_unload_task);
480                 taskqueue_drain(firmware_tq, &firmware_unload_task);
481
482                 LIST_FOREACH(fp, &firmware_table, link) {
483                         if (fp->fw.name != NULL) {
484                                 printf("%s: image %s still active, %d refs\n",
485                                     __func__, fp->fw.name, fp->refcnt);
486                                 err = EINVAL;
487                         }
488                 }
489                 if (err == 0)
490                         taskqueue_free(firmware_tq);
491                 break;
492
493         default:
494                 err = EOPNOTSUPP;
495                 break;
496         }
497         return (err);
498 }
499
500 static moduledata_t firmware_mod = {
501         "firmware",
502         firmware_modevent,
503         NULL
504 };
505 DECLARE_MODULE(firmware, firmware_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
506 MODULE_VERSION(firmware, 1);