blob: ec9d0b7d526e1c1bbb0de72e1ae4a3155e3df33e [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Copyright (C) 2004, Advanced Micro Devices, Inc. All Rights Reserved
2# Released under the MIT license (see packages/COPYING)
3
4# Creates a bootable image using syslinux, your kernel and an optional
5# initrd
6
7#
8# End result is two things:
9#
10# 1. A .hddimg file which is an msdos filesystem containing syslinux, a kernel,
11# an initrd and a rootfs image. These can be written to harddisks directly and
12# also booted on USB flash disks (write them there with dd).
13#
14# 2. A CD .iso image
15
16# Boot process is that the initrd will boot and process which label was selected
17# in syslinux. Actions based on the label are then performed (e.g. installing to
18# an hdd)
19
20# External variables (also used by syslinux.bbclass)
21# ${INITRD} - indicates a list of filesystem images to concatenate and use as an initrd (optional)
22# ${COMPRESSISO} - Transparent compress ISO, reduce size ~40% if set to 1
23# ${NOISO} - skip building the ISO image if set to 1
24# ${NOHDD} - skip building the HDD image if set to 1
25# ${HDDIMG_ID} - FAT image volume-id
26# ${ROOTFS} - indicates a filesystem image to include as the root filesystem (optional)
27
28do_bootimg[depends] += "dosfstools-native:do_populate_sysroot \
29 mtools-native:do_populate_sysroot \
30 cdrtools-native:do_populate_sysroot \
31 virtual/kernel:do_deploy \
32 ${@oe.utils.ifelse(d.getVar('COMPRESSISO', False),'zisofs-tools-native:do_populate_sysroot','')}"
33
34PACKAGES = " "
35EXCLUDE_FROM_WORLD = "1"
36
37HDDDIR = "${S}/hddimg"
38ISODIR = "${S}/iso"
39EFIIMGDIR = "${S}/efi_img"
40COMPACT_ISODIR = "${S}/iso.z"
41COMPRESSISO ?= "0"
42
43BOOTIMG_VOLUME_ID ?= "boot"
44BOOTIMG_EXTRA_SPACE ?= "512"
45
46EFI = "${@bb.utils.contains("MACHINE_FEATURES", "efi", "1", "0", d)}"
47EFI_PROVIDER ?= "grub-efi"
48EFI_CLASS = "${@bb.utils.contains("MACHINE_FEATURES", "efi", "${EFI_PROVIDER}", "", d)}"
49
50KERNEL_IMAGETYPE ??= "bzImage"
51
52# Include legacy boot if MACHINE_FEATURES includes "pcbios" or if it does not
53# contain "efi". This way legacy is supported by default if neither is
54# specified, maintaining the original behavior.
55def pcbios(d):
56 pcbios = bb.utils.contains("MACHINE_FEATURES", "pcbios", "1", "0", d)
57 if pcbios == "0":
58 pcbios = bb.utils.contains("MACHINE_FEATURES", "efi", "0", "1", d)
59 return pcbios
60
61PCBIOS = "${@pcbios(d)}"
62
63# The syslinux is required for the isohybrid command and boot catalog
64inherit syslinux
65inherit ${EFI_CLASS}
66
67populate() {
68 DEST=$1
69 install -d ${DEST}
70
71 # Install kernel, initrd, and rootfs.img in DEST for all loaders to use.
72 install -m 0644 ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE} ${DEST}/vmlinuz
73
74 # initrd is made of concatenation of multiple filesystem images
75 if [ -n "${INITRD}" ]; then
76 rm -f ${DEST}/initrd
77 for fs in ${INITRD}
78 do
79 if [ -s "${fs}" ]; then
80 cat ${fs} >> ${DEST}/initrd
81 else
82 bbfatal "${fs} is invalid. initrd image creation failed."
83 fi
84 done
85 chmod 0644 ${DEST}/initrd
86 fi
87
88 if [ -n "${ROOTFS}" ] && [ -s "${ROOTFS}" ]; then
89 install -m 0644 ${ROOTFS} ${DEST}/rootfs.img
90 fi
91
92}
93
94build_iso() {
95 # Only create an ISO if we have an INITRD and NOISO was not set
96 if [ -z "${INITRD}" ] || [ "${NOISO}" = "1" ]; then
97 bbnote "ISO image will not be created."
98 return
99 fi
100 # ${INITRD} is a list of multiple filesystem images
101 for fs in ${INITRD}
102 do
103 if [ ! -s "${fs}" ]; then
104 bbnote "ISO image will not be created. ${fs} is invalid."
105 return
106 fi
107 done
108
109
110 populate ${ISODIR}
111
112 if [ "${PCBIOS}" = "1" ]; then
113 syslinux_iso_populate ${ISODIR}
114 fi
115 if [ "${EFI}" = "1" ]; then
116 efi_iso_populate ${ISODIR}
117 build_fat_img ${EFIIMGDIR} ${ISODIR}/efi.img
118 fi
119
120 # EFI only
121 if [ "${PCBIOS}" != "1" ] && [ "${EFI}" = "1" ] ; then
122 # Work around bug in isohybrid where it requires isolinux.bin
123 # In the boot catalog, even though it is not used
124 mkdir -p ${ISODIR}/${ISOLINUXDIR}
125 install -m 0644 ${STAGING_DATADIR}/syslinux/isolinux.bin ${ISODIR}${ISOLINUXDIR}
126 fi
127
128 if [ "${COMPRESSISO}" = "1" ] ; then
129 # create compact directory, compress iso
130 mkdir -p ${COMPACT_ISODIR}
131 mkzftree -z 9 -p 4 -F ${ISODIR}/rootfs.img ${COMPACT_ISODIR}/rootfs.img
132
133 # move compact iso to iso, then remove compact directory
134 mv ${COMPACT_ISODIR}/rootfs.img ${ISODIR}/rootfs.img
135 rm -Rf ${COMPACT_ISODIR}
136 mkisofs_compress_opts="-R -z -D -l"
137 else
138 mkisofs_compress_opts="-r"
139 fi
140
141 # Check the size of ${ISODIR}/rootfs.img, use mkisofs -iso-level 3
142 # when it exceeds 3.8GB, the specification is 4G - 1 bytes, we need
143 # leave a few space for other files.
144 mkisofs_iso_level=""
145
146 if [ -n "${ROOTFS}" ] && [ -s "${ROOTFS}" ]; then
147 rootfs_img_size=`stat -c '%s' ${ISODIR}/rootfs.img`
148 # 4080218931 = 3.8 * 1024 * 1024 * 1024
149 if [ $rootfs_img_size -gt 4080218931 ]; then
150 bbnote "${ISODIR}/rootfs.img execeeds 3.8GB, using '-iso-level 3' for mkisofs"
151 mkisofs_iso_level="-iso-level 3"
152 fi
153 fi
154
155 if [ "${PCBIOS}" = "1" ] && [ "${EFI}" != "1" ] ; then
156 # PCBIOS only media
157 mkisofs -V ${BOOTIMG_VOLUME_ID} \
158 -o ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.iso \
159 -b ${ISO_BOOTIMG} -c ${ISO_BOOTCAT} \
160 $mkisofs_compress_opts \
161 ${MKISOFS_OPTIONS} $mkisofs_iso_level ${ISODIR}
162 else
163 # EFI only OR EFI+PCBIOS
164 mkisofs -A ${BOOTIMG_VOLUME_ID} -V ${BOOTIMG_VOLUME_ID} \
165 -o ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.iso \
166 -b ${ISO_BOOTIMG} -c ${ISO_BOOTCAT} \
167 $mkisofs_compress_opts ${MKISOFS_OPTIONS} $mkisofs_iso_level \
168 -eltorito-alt-boot -eltorito-platform efi \
169 -b efi.img -no-emul-boot \
170 ${ISODIR}
171 isohybrid_args="-u"
172 fi
173
174 isohybrid $isohybrid_args ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.iso
175
176 cd ${DEPLOY_DIR_IMAGE}
177 rm -f ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.iso
178 ln -s ${IMAGE_NAME}.iso ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.iso
179}
180
181build_fat_img() {
182 FATSOURCEDIR=$1
183 FATIMG=$2
184
185 # Calculate the size required for the final image including the
186 # data and filesystem overhead.
187 # Sectors: 512 bytes
188 # Blocks: 1024 bytes
189
190 # Determine the sector count just for the data
191 SECTORS=$(expr $(du --apparent-size -ks ${FATSOURCEDIR} | cut -f 1) \* 2)
192
193 # Account for the filesystem overhead. This includes directory
194 # entries in the clusters as well as the FAT itself.
195 # Assumptions:
196 # FAT32 (12 or 16 may be selected by mkdosfs, but the extra
197 # padding will be minimal on those smaller images and not
198 # worth the logic here to caclulate the smaller FAT sizes)
199 # < 16 entries per directory
200 # 8.3 filenames only
201
202 # 32 bytes per dir entry
203 DIR_BYTES=$(expr $(find ${FATSOURCEDIR} | tail -n +2 | wc -l) \* 32)
204 # 32 bytes for every end-of-directory dir entry
205 DIR_BYTES=$(expr $DIR_BYTES + $(expr $(find ${FATSOURCEDIR} -type d | tail -n +2 | wc -l) \* 32))
206 # 4 bytes per FAT entry per sector of data
207 FAT_BYTES=$(expr $SECTORS \* 4)
208 # 4 bytes per FAT entry per end-of-cluster list
209 FAT_BYTES=$(expr $FAT_BYTES + $(expr $(find ${FATSOURCEDIR} -type d | tail -n +2 | wc -l) \* 4))
210
211 # Use a ceiling function to determine FS overhead in sectors
212 DIR_SECTORS=$(expr $(expr $DIR_BYTES + 511) / 512)
213 # There are two FATs on the image
214 FAT_SECTORS=$(expr $(expr $(expr $FAT_BYTES + 511) / 512) \* 2)
215 SECTORS=$(expr $SECTORS + $(expr $DIR_SECTORS + $FAT_SECTORS))
216
217 # Determine the final size in blocks accounting for some padding
218 BLOCKS=$(expr $(expr $SECTORS / 2) + ${BOOTIMG_EXTRA_SPACE})
219
220 # Ensure total sectors is an integral number of sectors per
221 # track or mcopy will complain. Sectors are 512 bytes, and we
222 # generate images with 32 sectors per track. This calculation is
223 # done in blocks, thus the mod by 16 instead of 32.
224 BLOCKS=$(expr $BLOCKS + $(expr 16 - $(expr $BLOCKS % 16)))
225
226 # mkdosfs will sometimes use FAT16 when it is not appropriate,
227 # resulting in a boot failure from SYSLINUX. Use FAT32 for
228 # images larger than 512MB, otherwise let mkdosfs decide.
229 if [ $(expr $BLOCKS / 1024) -gt 512 ]; then
230 FATSIZE="-F 32"
231 fi
232
233 # mkdosfs will fail if ${FATIMG} exists. Since we are creating an
234 # new image, it is safe to delete any previous image.
235 if [ -e ${FATIMG} ]; then
236 rm ${FATIMG}
237 fi
238
239 if [ -z "${HDDIMG_ID}" ]; then
240 mkdosfs ${FATSIZE} -n ${BOOTIMG_VOLUME_ID} -S 512 -C ${FATIMG} \
241 ${BLOCKS}
242 else
243 mkdosfs ${FATSIZE} -n ${BOOTIMG_VOLUME_ID} -S 512 -C ${FATIMG} \
244 ${BLOCKS} -i ${HDDIMG_ID}
245 fi
246
247 # Copy FATSOURCEDIR recursively into the image file directly
248 mcopy -i ${FATIMG} -s ${FATSOURCEDIR}/* ::/
249}
250
251build_hddimg() {
252 # Create an HDD image
253 if [ "${NOHDD}" != "1" ] ; then
254 populate ${HDDDIR}
255
256 if [ "${PCBIOS}" = "1" ]; then
257 syslinux_hddimg_populate ${HDDDIR}
258 fi
259 if [ "${EFI}" = "1" ]; then
260 efi_hddimg_populate ${HDDDIR}
261 fi
262
263 # Check the size of ${HDDDIR}/rootfs.img, error out if it
264 # exceeds 4GB, it is the single file's max size of FAT fs.
265 if [ -f ${HDDDIR}/rootfs.img ]; then
266 rootfs_img_size=`stat -c '%s' ${HDDDIR}/rootfs.img`
267 max_size=`expr 4 \* 1024 \* 1024 \* 1024`
268 if [ $rootfs_img_size -gt $max_size ]; then
269 bberror "${HDDDIR}/rootfs.img execeeds 4GB,"
270 bberror "this doesn't work on FAT filesystem, you can try either of:"
271 bberror "1) Reduce the size of rootfs.img"
272 bbfatal "2) Use iso, vmdk or vdi to instead of hddimg\n"
273 fi
274 fi
275
276 build_fat_img ${HDDDIR} ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.hddimg
277
278 if [ "${PCBIOS}" = "1" ]; then
279 syslinux_hddimg_install
280 fi
281
282 chmod 644 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.hddimg
283
284 cd ${DEPLOY_DIR_IMAGE}
285 rm -f ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.hddimg
286 ln -s ${IMAGE_NAME}.hddimg ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}.hddimg
287 fi
288}
289
290python do_bootimg() {
291 if d.getVar("PCBIOS", True) == "1":
292 bb.build.exec_func('build_syslinux_cfg', d)
293 if d.getVar("EFI", True) == "1":
294 bb.build.exec_func('build_efi_cfg', d)
295 bb.build.exec_func('build_hddimg', d)
296 bb.build.exec_func('build_iso', d)
297}
298
299IMAGE_TYPEDEP_iso = "ext4"
300IMAGE_TYPEDEP_hddimg = "ext4"
301IMAGE_TYPES_MASKED += "iso hddimg"
302
303addtask bootimg before do_build