[intel] Add PCI ID for I219-V and -LM 16,17
[ipxe.git] / src / util / genfsimg
1 #!/bin/sh
2 #
3 # Generate a filesystem-based image
4
5 set -e
6 set -u
7
8 # Print usage message
9 #
10 help() {
11     echo "usage: ${0} [OPTIONS] foo.lkrn|foo.efi [bar.lkrn|bar.efi,...]"
12     echo
13     echo "where OPTIONS are:"
14     echo " -h         show this help"
15     echo " -o FILE    save image to file"
16     echo " -p PAD     pad filesystem (in kB)"
17     echo " -s SCRIPT  use executable script"
18 }
19
20 # Get hex byte from binary file
21 #
22 get_byte() {
23     local FILENAME
24     local OFFSET
25
26     FILENAME="${1}"
27     OFFSET="${2}"
28
29     od -j "${OFFSET}" -N 1 -A n -t x1 -- "${FILENAME}" | tr -d " "
30 }
31
32 # Get hex word from binary file
33 #
34 get_word() {
35     local FILENAME
36     local OFFSET
37
38     FILENAME="${1}"
39     OFFSET="${2}"
40
41     od -j "${OFFSET}" -N 2 -A n -t x1 -- "${FILENAME}" | tr -d " "
42 }
43
44 # Get appropriate EFI boot filename for CPU architecture
45 #
46 efi_boot_name() {
47     local FILENAME
48     local PESIG
49     local ARCH
50
51     FILENAME="${1}"
52
53     MZSIG=$(get_word "${FILENAME}" 0)
54     if [ "${MZSIG}" != "4d5a" ] ; then
55         echo "${FILENAME}: invalid MZ header" >&2
56         exit 1
57     fi
58     PEOFF=$(get_byte "${FILENAME}" 0x3c)
59     PESIG=$(get_word "${FILENAME}" 0x${PEOFF})
60     if [ "${PESIG}" != "5045" ] ; then
61         echo "${FILENAME}: invalid PE header" >&2
62         exit 1
63     fi
64     ARCH=$(get_word "${FILENAME}" $(( 0x${PEOFF} + 4 )) )
65     case "${ARCH}" in
66         "4c01" )
67             echo "BOOTIA32.EFI"
68             ;;
69         "6486" )
70             echo "BOOTX64.EFI"
71             ;;
72         "c201" )
73             echo "BOOTARM.EFI"
74             ;;
75         "64aa" )
76             echo "BOOTAA64.EFI"
77             ;;
78         * )
79             echo "${FILENAME}: unrecognised EFI architecture ${ARCH}" >&2
80             exit 1
81     esac
82 }
83
84 # Copy syslinux file
85 #
86 copy_syslinux_file() {
87     local FILENAME
88     local DESTDIR
89     local SRCDIR
90
91     FILENAME="${1}"
92     DESTDIR="${2}"
93
94     for SRCDIR in \
95         /usr/lib/syslinux \
96         /usr/lib/syslinux/bios \
97         /usr/lib/syslinux/modules/bios \
98         /usr/share/syslinux \
99         /usr/share/syslinux/bios \
100         /usr/share/syslinux/modules/bios \
101         /usr/local/share/syslinux \
102         /usr/local/share/syslinux/bios \
103         /usr/local/share/syslinux/bios/core \
104         /usr/local/share/syslinux/bios/com32/elflink/ldlinux \
105         /usr/local/share/syslinux/modules/bios \
106         /usr/lib/ISOLINUX \
107         ; do
108         if [ -e "${SRCDIR}/${FILENAME}" ] ; then
109             install -m 644 "${SRCDIR}/${FILENAME}" "${DESTDIR}/"
110             return 0
111         fi
112     done
113     echo "${0}: could not find ${FILENAME}" >&2
114     return 1
115 }
116
117 # Parse command-line options
118 #
119 OUTFILE=
120 PAD=0
121 SCRIPT=
122 while getopts "hlo:p:s:" OPTION ; do
123     case "${OPTION}" in
124         h)
125             help
126             exit 0
127             ;;
128         o)
129             OUTFILE="${OPTARG}"
130             ;;
131         p)
132             PAD="${OPTARG}"
133             ;;
134         s)
135             SCRIPT="${OPTARG}"
136             ;;
137         *)
138             help
139             exit 1
140             ;;
141     esac
142 done
143 if [ -z "${OUTFILE}" ]; then
144     echo "${0}: no output file given" >&2
145     help
146     exit 1
147 fi
148 shift $(( OPTIND - 1 ))
149 if [ $# -eq 0 ] ; then
150     echo "${0}: no input files given" >&2
151     help
152     exit 1
153 fi
154
155 # Create temporary working directory
156 #
157 WORKDIR=$(mktemp -d "${OUTFILE}.XXXXXX")
158 ISODIR="${WORKDIR}/iso"
159 FATDIR="${WORKDIR}/fat"
160 mkdir -p "${ISODIR}" "${FATDIR}"
161
162 # Configure output
163 #
164 case "${OUTFILE}" in
165     *.iso)
166         ISOIMG="${OUTFILE}"
167         FATIMG="${ISODIR}/esp.img"
168         BIOSDIR="${ISODIR}"
169         SYSLINUXCFG="${ISODIR}/isolinux.cfg"
170         ;;
171     *)
172         ISOIMG=
173         FATIMG="${OUTFILE}"
174         BIOSDIR="${FATDIR}"
175         SYSLINUXCFG="${FATDIR}/syslinux.cfg"
176         ;;
177 esac
178
179 # Copy files to temporary working directory
180 #
181 LKRN=
182 EFI=
183 for FILENAME ; do
184     case "${FILENAME}" in
185         *.lkrn)
186             DESTDIR="${BIOSDIR}"
187             DESTFILE=$(basename "${FILENAME}")
188             if [ -z "${LKRN}" ] ; then
189                 echo "SAY iPXE boot image" > "${SYSLINUXCFG}"
190                 echo "TIMEOUT 30" >> "${SYSLINUXCFG}"
191                 echo "DEFAULT ${DESTFILE}" >> "${SYSLINUXCFG}"
192                 if [ -n "${SCRIPT}" ] ; then
193                     cp "${SCRIPT}" "${BIOSDIR}/autoexec.ipxe"
194                 fi
195             fi
196             echo "LABEL ${DESTFILE}" >> "${SYSLINUXCFG}"
197             echo " KERNEL ${DESTFILE}" >> "${SYSLINUXCFG}"
198             if [ -n "${SCRIPT}" ] ; then
199                 echo " APPEND initrd=autoexec.ipxe" >> "${SYSLINUXCFG}"
200             fi
201             LKRN=1
202             ;;
203         *.efi)
204             DESTDIR="${FATDIR}/EFI/BOOT"
205             DESTFILE=$(efi_boot_name "${FILENAME}")
206             if [ -z "${EFI}" ] ; then
207                 mkdir -p "${DESTDIR}"
208                 if [ -n "${SCRIPT}" ] ; then
209                     cp "${SCRIPT}" "${FATDIR}/autoexec.ipxe"
210                 fi
211             fi
212             EFI=1
213             ;;
214         *)
215             echo "${0}: unrecognised input filename ${FILENAME}" >&2
216             help
217             exit 1
218             ;;
219     esac
220     if [ -e "${DESTDIR}/${DESTFILE}" ] ; then
221         echo "${0}: duplicate ${DESTFILE} from ${FILENAME}" >&2
222         exit 1
223     fi
224     cp "${FILENAME}" "${DESTDIR}/${DESTFILE}"
225 done
226
227 # Configure ISO image, if applicable
228 #
229 # Note that the BIOS boot files are required even for an EFI-only ISO,
230 # since isohybrid will refuse to work without them.
231 #
232 if [ -n "${ISOIMG}" ] ; then
233     ISOARGS="-J -R -l"
234     copy_syslinux_file "isolinux.bin" "${ISODIR}"
235     copy_syslinux_file "ldlinux.c32" "${ISODIR}" 2>/dev/null || true
236     ISOARGS="${ISOARGS} -no-emul-boot -eltorito-boot isolinux.bin"
237     ISOARGS="${ISOARGS} -boot-load-size 4 -boot-info-table"
238     if [ -n "${EFI}" ] ; then
239         ISOARGS="${ISOARGS} -eltorito-alt-boot -no-emul-boot -e esp.img"
240     else
241         FATIMG=
242     fi
243     if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then
244         DATE_FMT="+%Y%m%d%H%M%S00"
245         BUILD_DATE=$(date -u -d "@${SOURCE_DATE_EPOCH}" "${DATE_FMT}" \
246                           2>/dev/null || \
247                      date -u -r "${SOURCE_DATE_EPOCH}" "${DATE_FMT}" \
248                           2>/dev/null || \
249                      date -u "${DATE_FMT}")
250         ISOARGS="${ISOARGS} --set_all_file_dates ${BUILD_DATE}"
251         ISOARGS="${ISOARGS} --modification-date=${BUILD_DATE}"
252     fi
253 fi
254
255 # Create FAT filesystem image, if applicable
256 #
257 if [ -n "${FATIMG}" ] ; then
258     FATSIZE=$(du -s -k "${FATDIR}" | cut -f1)
259     FATSIZE=$(( FATSIZE + PAD + 256 ))
260     touch "${FATIMG}"
261     if [ "${FATSIZE}" -le "1440" ] ; then
262         FATSIZE=1440
263         FATARGS="-f 1440"
264     else
265         FATCYLS=$(( ( FATSIZE + 503 ) / 504 ))
266         FATSIZE=$(( FATCYLS * 504 ))
267         FATARGS="-s 63 -h 16 -t ${FATCYLS}"
268     fi
269     truncate -s "${FATSIZE}K" "${FATIMG}"
270     mformat -v iPXE -i "${FATIMG}" ${FATARGS} ::
271     mcopy -i "${FATIMG}" -s "${FATDIR}"/* ::
272     if [ "${BIOSDIR}" = "${FATDIR}" ] ; then
273         syslinux "${FATIMG}"
274     fi
275 fi
276
277 # Create ISO filesystem image, if applicable
278 #
279 if [ -n "${ISOIMG}" ] ; then
280     MKISOFS=
281     MKISOFS_MISSING=
282     MKISOFS_NOTSUP=
283     for CMD in genisoimage mkisofs xorrisofs ; do
284         if ! "${CMD}" --version >/dev/null 2>&1 ; then
285             MKISOFS_MISSING="${MKISOFS_MISSING} ${CMD}"
286             continue
287         fi
288         if ! "${CMD}" ${ISOARGS} --version "${ISODIR}" >/dev/null 2>&1 ; then
289             MKISOFS_NOTSUP="${MKISOFS_NOTSUP} ${CMD}"
290             continue
291         fi
292         MKISOFS="${CMD}"
293         break
294     done
295     if [ -z "${MKISOFS}" ] ; then
296         if [ -n "${MKISOFS_MISSING}" ] ; then
297             echo "${0}:${MKISOFS_MISSING}: not installed" >&2
298         fi
299         if [ -n "${MKISOFS_NOTSUP}" ] ; then
300             echo "${0}:${MKISOFS_NOTSUP}: cannot handle ${ISOARGS}" >&2
301         fi
302         echo "${0}: cannot find a suitable mkisofs or equivalent" >&2
303         exit 1
304     fi
305     "${MKISOFS}" -quiet -volid "iPXE" -preparer "iPXE build system" \
306             -appid "iPXE - Open Source Network Boot Firmware" \
307             -publisher "ipxe.org" -sysid "iPXE" -o "${ISOIMG}" \
308             ${ISOARGS} "${ISODIR}"
309     if isohybrid --version >/dev/null 2>&1 ; then
310         ISOHYBRIDARGS=
311         if [ -n "${EFI}" ] ; then
312             ISOHYBRIDARGS="${ISOHYBRIDARGS} --uefi"
313         fi
314         if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then
315             ISOHYBRIDARGS="${ISOHYBRIDARGS} --id ${SOURCE_DATE_EPOCH}"
316         fi
317         isohybrid ${ISOHYBRIDARGS} "${ISOIMG}"
318     fi
319 fi
320
321 # Clean up temporary working directory
322 #
323 rm -rf "${WORKDIR}"