Subject: kern/32342: OpenBSD firmware loading framework
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <plunky@rya-online.net>
List: netbsd-bugs
Date: 12/19/2005 22:10:00
>Number: 32342
>Category: kern
>Synopsis: port of OpenBSD firmware loading framework
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Mon Dec 19 22:10:00 +0000 2005
>Originator: Iain Hibbert
>Release: NetBSD 3.99.14
>Organization:
>Environment:
System: NetBSD galant 3.99.14 NetBSD 3.99.14 (GALANT) #8: Mon Dec 19 21:34:33 GMT 2005 plunky@galant:/home/plunky/src/sys/arch/i386/compile/GALANT i386
Architecture: i386
Machine: i386
>Description:
I want to load driver firmware file from inside the kernel and there
is no way currently to do that. Christos Zoulas mentioned on tech-kern
that OpenBSD had a framwork to handle this so I took a look. This is
the result, please find below a shar archive containing two new files:
sys/dev/firmload.c
share/man/man9/load_firmware.9
which are exactly as in OpenBSD. Following this are patches for these
two files to make them work for NetBSD. Following that is a cvs diff
against the following files:
sys/conf/files
sys/sys/device.h
share/man/man9/Makefile
to integrate this patch with the -current version of NetBSD
>How-To-Repeat:
>Fix:
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# sys/dev/firmload.c
# share/man/man9/load_firmware.9
#
echo x - sys/dev/firmload.c
sed 's/^X//' >sys/dev/firmload.c << 'END-of-sys/dev/firmload.c'
X/* $OpenBSD: firmload.c,v 1.5 2005/08/01 08:15:02 deraadt Exp $ */
X
X/*
X * Copyright (c) 2004 Theo de Raadt <deraadt@openbsd.org>
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
X * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
X * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
X * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
X * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
X * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X */
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/syslimits.h>
X#include <sys/time.h>
X#include <sys/namei.h>
X#include <sys/vnode.h>
X#include <sys/mount.h>
X#include <sys/errno.h>
X#include <sys/malloc.h>
X#include <sys/proc.h>
X#include <sys/device.h>
X
Xint
Xloadfirmware(const char *name, u_char **bufp, size_t *buflen)
X{
X struct proc *p = curproc;
X struct nameidata nid;
X char *path, *ptr;
X struct iovec iov;
X struct uio uio;
X struct vattr va;
X int error;
X
X if (!rootvp || !vcount(rootvp))
X return (EIO);
X
X path = malloc(MAXPATHLEN, M_TEMP, M_NOWAIT);
X if (path == NULL)
X return (ENOMEM);
X
X snprintf(path, MAXPATHLEN, "/etc/firmware/%s", name);
X
X NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, path, p);
X error = namei(&nid);
X if (error)
X goto err;
X error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
X if (error)
X goto fail;
X if (va.va_size == 0) {
X error = EINVAL;
X goto fail;
X }
X if (va.va_size > FIRMWARE_MAX) {
X error = E2BIG;
X goto fail;
X }
X ptr = malloc(va.va_size, M_DEVBUF, M_NOWAIT);
X if (ptr == NULL) {
X error = ENOMEM;
X goto fail;
X }
X
X iov.iov_base = ptr;
X iov.iov_len = va.va_size;
X uio.uio_iov = &iov;
X uio.uio_iovcnt = 1;
X uio.uio_offset = 0;
X uio.uio_resid = va.va_size;
X uio.uio_segflg = UIO_SYSSPACE;
X uio.uio_rw = UIO_READ;
X uio.uio_procp = p;
X
X error = VOP_READ(nid.ni_vp, &uio, 0, NOCRED);
X
X if (error == 0) {
X *bufp = ptr;
X *buflen = va.va_size;
X } else
X free(ptr, M_DEVBUF);
X
Xfail:
X vput(nid.ni_vp);
Xerr:
X if (path)
X free(path, M_TEMP);
X return (error);
X}
END-of-sys/dev/firmload.c
echo x - share/man/man9/load_firmware.9
sed 's/^X//' >share/man/man9/load_firmware.9 << 'END-of-share/man/man9/load_firmware.9'
X.\" $OpenBSD: loadfirmware.9,v 1.2 2004/11/22 16:41:44 jmc Exp $
X.\"
X.\" Copyright (c) 2004 Theo de Raadt
X.\" All rights reserved.
X.\"
X.\" Permission to use, copy, modify, and distribute this software for any
X.\" purpose with or without fee is hereby granted, provided that the above
X.\" copyright notice and this permission notice appear in all copies.
X.\"
X.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
X.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
X.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
X.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
X.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
X.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
X.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X.\"
X.Dd November 21, 2004
X.Dt LOADFIRMWARE 9
X.Os
X.Sh NAME
X.Nm loadfirmware
X.Nd load a firmware file from the filesystem
X.Sh SYNOPSIS
X.Fd #include <sys/device.h>
X.Ft int
X.Fn loadfirmware "const char *filename" "u_char **buf" "size_t *buflen"
X.Sh DESCRIPTION
XThe
X.Fn loadfirmware
Xfunction loads a firmware from the file specified by
X.Ar filename
Xin the directory
X.Pa /etc/firmware .
XMemory for the firmware is allocated using
X.Xr malloc 9
Xwith type
X.Va M_DEVBUF
Xas need be, within a reasonable size limit.
X.Pp
XIf no longer needed, the firmware buffer
X.Va buf
Xcan be freed using
X.Xr free 9
Xwith type
X.Va M_DEVBUF .
X.Sh RETURN VALUES
XIf successful,
X.Ar buf
Xis set to point to the allocation and
X.Ar buflen
Xis set to the size of the firmware.
XThen
X.Fn loadfirmware
Xreturns 0.
XOtherwise, it returns an
X.Va errno
Xstyle error.
END-of-share/man/man9/load_firmware.9
exit
--- sys/dev/firmload.c 2005-08-01 09:15:02.000000000 +0100
+++ sys/dev/firmload.c 2005-12-19 21:46:02.000000000 +0000
@@ -1,3 +1,4 @@
+/* $NetBSD: firmload.c$ */
/* $OpenBSD: firmload.c,v 1.5 2005/08/01 08:15:02 deraadt Exp $ */
/*
@@ -29,11 +30,12 @@
#include <sys/device.h>
int
-loadfirmware(const char *name, u_char **bufp, size_t *buflen)
+load_firmware(const char *name, uint8_t **bufp, size_t *buflen)
{
- struct proc *p = curproc;
+ struct lwp *l = curlwp;
struct nameidata nid;
- char *path, *ptr;
+ char *path;
+ uint8_t *ptr;
struct iovec iov;
struct uio uio;
struct vattr va;
@@ -48,11 +50,11 @@
snprintf(path, MAXPATHLEN, "/etc/firmware/%s", name);
- NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, path, p);
+ NDINIT(&nid, LOOKUP, NOFOLLOW|LOCKLEAF, UIO_SYSSPACE, path, l);
error = namei(&nid);
if (error)
goto err;
- error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
+ error = VOP_GETATTR(nid.ni_vp, &va, l->l_proc->p_ucred, l);
if (error)
goto fail;
if (va.va_size == 0) {
@@ -77,7 +79,7 @@
uio.uio_resid = va.va_size;
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_rw = UIO_READ;
- uio.uio_procp = p;
+ uio.uio_lwp = l;
error = VOP_READ(nid.ni_vp, &uio, 0, NOCRED);
--- share/man/man9/load_firmware.9 2004-11-22 16:41:44.000000000 +0000
+++ share/man/man9/load_firmware.9 2005-12-19 21:56:48.000000000 +0000
@@ -1,3 +1,4 @@
+.\" $NetBSD: load_firmware.9$
.\" $OpenBSD: loadfirmware.9,v 1.2 2004/11/22 16:41:44 jmc Exp $
.\"
.\" Copyright (c) 2004 Theo de Raadt
@@ -16,18 +17,18 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd November 21, 2004
-.Dt LOADFIRMWARE 9
+.Dt LOAD_FIRMWARE 9
.Os
.Sh NAME
-.Nm loadfirmware
+.Nm load_firmware
.Nd load a firmware file from the filesystem
.Sh SYNOPSIS
.Fd #include <sys/device.h>
.Ft int
-.Fn loadfirmware "const char *filename" "u_char **buf" "size_t *buflen"
+.Fn load_firmware "const char *filename" "u_char **buf" "size_t *buflen"
.Sh DESCRIPTION
The
-.Fn loadfirmware
+.Fn load_firmware
function loads a firmware from the file specified by
.Ar filename
in the directory
@@ -36,9 +37,10 @@
.Xr malloc 9
with type
.Va M_DEVBUF
-as need be, within a reasonable size limit.
+as need be, within a reasonable size limit defined by
+.Va FIRMWARE_MAX .
.Pp
-If no longer needed, the firmware buffer
+When no longer needed, the firmware buffer
.Va buf
can be freed using
.Xr free 9
@@ -51,7 +53,7 @@
.Ar buflen
is set to the size of the firmware.
Then
-.Fn loadfirmware
+.Fn load_firmware
returns 0.
Otherwise, it returns an
.Va errno
Index: sys/conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.746
diff -u -r1.746 files
--- sys/conf/files 7 Dec 2005 00:42:03 -0000 1.746
+++ sys/conf/files 19 Dec 2005 21:54:52 -0000
@@ -234,6 +235,9 @@
define pckbport {[slot = -1]}
define pckbport_machdep_cnattach
+# filesystem firmware loading attribute
+define firmload
+
# audio device attributes
#
define mulaw
@@ -1169,6 +1170,7 @@
file dev/dkwedge/dkwedge_bsdlabel.c dkwedge_method_bsdlabel
file dev/dkwedge/dkwedge_gpt.c dkwedge_method_gpt
file dev/dkwedge/dkwedge_mbr.c dkwedge_method_mbr
+file dev/firmload.c firmload
file dev/fss.c fss needs-count
file dev/md.c md needs-count
file dev/midi.c midi | midibus needs-flag
Index: sys/sys/device.h
===================================================================
RCS file: /cvsroot/src/sys/sys/device.h,v
retrieving revision 1.81
diff -u -r1.81 device.h
--- sys/sys/device.h 11 Dec 2005 12:25:20 -0000 1.81
+++ sys/sys/device.h 19 Dec 2005 21:54:54 -0000
@@ -417,6 +417,9 @@
#define device_lookup(cfd, unit) \
(((unit) < (cfd)->cd_ndevs) ? (cfd)->cd_devs[(unit)] : NULL)
+int load_firmware(const char *, uint8_t **, size_t *);
+#define FIRMWARE_MAX (5*1024*1024)
+
#ifdef DDB
void event_print(int, void (*)(const char *, ...));
#endif
Index: share/man/man9/Makefile
===================================================================
RCS file: /cvsroot/src/share/man/man9/Makefile,v
retrieving revision 1.183
diff -u -r1.183 Makefile
--- share/man/man9/Makefile 24 Nov 2005 08:20:51 -0000 1.183
+++ share/man/man9/Makefile 19 Dec 2005 21:54:56 -0000
@@ -21,8 +21,8 @@
ieee80211_radiotap.9 \
in4_cksum.9 inittodr.9 intro.9 ioasic.9 ioctl.9 ipkdb.9 isa.9 \
isapnp.9 itimerfix.9 kcopy.9 kcont.9 \
- kfilter_register.9 knote.9 \
- kprintf.9 kthread.9 linedisc.9 lock.9 log.9 ltsleep.9 \
+ kfilter_register.9 knote.9 kprintf.9 kthread.9 linedisc.9 \
+ load_firmware.9 lock.9 log.9 ltsleep.9 \
malloc.9 mbuf.9 mca.9 memcmp.9 memcpy.9 memmove.9 memset.9 \
microtime.9 mstohz.9 m_tag.9 namecache.9 namei.9 need_resched.9 \
opencrypto.9 \
>Unformatted: