1#!/bin/sh
2
3set -e
4
5if [ "$#" -eq 0 ] || [ "$#" -gt 2 ]; then
6  echo "Usage: $(basename $0) fw.bin [module_prefix]"
7  exit 1
8fi
9
10if [ ! -f $1 ]; then
11   echo "File $1 does not exist"
12   exit 1
13fi
14
15if [ "$#" -eq 2 ]; then
16MOD_PREFIX=$2
17fi
18
19MODULEDIR=${MODULEDIR:-/boot/modules.local}
20WORKDIR=$(mktemp -d)
21CURDIR=$PWD
22
23FWFILE=$(basename "$1")
24# strip .bin and .fw extensions
25MODNAME=$(basename $(basename "$1" .bin) .fw)
26
27# if module_prefix is provided, append to module name
28if [ "$#" -eq 2 ]; then
29MODNAME=${MOD_PREFIX}${MODNAME}
30fi
31
32# copy firmware file to workdir
33cp -v "$1" "$WORKDIR"/"$FWFILE"
34
35# prefer to use /sys build but provide workaround too
36if [ -f /sys/tools/fw_stub.awk ];
37then
38echo "KMOD=	${MODNAME}" > 			"$WORKDIR"/Makefile
39echo "FIRMWS=	${FWFILE}:${MODNAME}" >>	"$WORKDIR"/Makefile
40echo ".include <bsd.kmod.mk>" >>		"$WORKDIR"/Makefile
41
42(cd $WORKDIR && make)
43
44else
45# workaround case to build a local fw module version w/o kernel sources (should have no impact)
46set -x
47
48# ld/objcopy substitutes ' ', '-', '.' and '/' to '_'
49FWSYM=$(echo ${FWFILE} |sed 's/ /_/g' | sed 's/-/_/g' |sed 's/\./_/g' |sed 's/\/_//g')
50echo FWSYM=${FWSYM}
51
52cd $WORKDIR
53ld -b binary --no-warn-mismatch -r -d -o "${FWFILE}.fwo"  "${FWFILE}"
54
55cat << EOF >> ${MODNAME}.c
56#include <sys/param.h>
57#include <sys/errno.h>
58#include <sys/kernel.h>
59#include <sys/module.h>
60#include <sys/linker.h>
61#include <sys/firmware.h>
62//#include <sys/systm.h>
63
64extern char _binary_${FWSYM}_start[], _binary_${FWSYM}_end[];
65
66static int
67${MODNAME}_fw_modevent(module_t mod, int type, void *unused)
68{
69  const struct firmware *fp;
70  int error;
71  switch (type) {
72  case MOD_LOAD:
73    fp = firmware_register("${MODNAME}", _binary_${FWSYM}_start , (size_t)(_binary_${FWSYM}_end - _binary_${FWSYM}_start), 0, NULL);
74    if (fp == NULL)
75      goto fail_0;
76    return (0);
77fail_0:
78    return (ENXIO);
79  case MOD_UNLOAD:
80    error = firmware_unregister("${MODNAME}");
81    return (error);
82  }
83  return (EINVAL);
84}
85
86static moduledata_t ${MODNAME}_fw_mod = {
87  "${MODNAME}_fw",
88  ${MODNAME}_fw_modevent,
89  0
90};
91DECLARE_MODULE(${MODNAME}_fw, ${MODNAME}_fw_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
92MODULE_VERSION(${MODNAME}_fw, 1);
93MODULE_DEPEND(${MODNAME}_fw, firmware, 1, 1, 1);
94EOF
95
96FFLAGS="-fno-common -ffreestanding -fno-asynchronous-unwind-tables -fno-omit-frame-pointer -fno-stack-protector"
97cc  -O -pipe   -D_KERNEL -Wall -std=c99 -Werror -DKLD_MODULE ${FFLAGS} -mcmodel=kernel -mno-red-zone -c "${MODNAME}.c"
98ld  -r -d -o "${MODNAME}.ko" "${FWFILE}.fwo" "${MODNAME}.o"
99
100fi
101
102
103# copy firmware module to external modules dir
104cp -v "$WORKDIR/$MODNAME.ko" "${MODULEDIR}/"
105
106rm -rf "${WORKDIR}"
107