summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/plugins/source/bootimg-efi.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/plugins/source/bootimg-efi.py')
-rw-r--r--scripts/lib/wic/plugins/source/bootimg-efi.py507
1 files changed, 0 insertions, 507 deletions
diff --git a/scripts/lib/wic/plugins/source/bootimg-efi.py b/scripts/lib/wic/plugins/source/bootimg-efi.py
deleted file mode 100644
index 13a9cddf4e..0000000000
--- a/scripts/lib/wic/plugins/source/bootimg-efi.py
+++ /dev/null
@@ -1,507 +0,0 @@
1#
2# Copyright (c) 2014, Intel Corporation.
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6# DESCRIPTION
7# This implements the 'bootimg-efi' source plugin class for 'wic'
8#
9# AUTHORS
10# Tom Zanussi <tom.zanussi (at] linux.intel.com>
11#
12
13import logging
14import os
15import tempfile
16import shutil
17import re
18
19from glob import glob
20
21from wic import WicError
22from wic.engine import get_custom_config
23from wic.pluginbase import SourcePlugin
24from wic.misc import (exec_cmd, exec_native_cmd,
25 get_bitbake_var, BOOTDD_EXTRA_SPACE)
26
27logger = logging.getLogger('wic')
28
29class BootimgEFIPlugin(SourcePlugin):
30 """
31 Create EFI boot partition.
32 This plugin supports GRUB 2 and systemd-boot bootloaders.
33 """
34
35 name = 'bootimg-efi'
36
37 @classmethod
38 def _copy_additional_files(cls, hdddir, initrd, dtb):
39 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
40 if not bootimg_dir:
41 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
42
43 if initrd:
44 initrds = initrd.split(';')
45 for rd in initrds:
46 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir)
47 exec_cmd(cp_cmd, True)
48 else:
49 logger.debug("Ignoring missing initrd")
50
51 if dtb:
52 if ';' in dtb:
53 raise WicError("Only one DTB supported, exiting")
54 cp_cmd = "cp %s/%s %s" % (bootimg_dir, dtb, hdddir)
55 exec_cmd(cp_cmd, True)
56
57 @classmethod
58 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params):
59 """
60 Create loader-specific (grub-efi) config
61 """
62 configfile = creator.ks.bootloader.configfile
63 custom_cfg = None
64 if configfile:
65 custom_cfg = get_custom_config(configfile)
66 if custom_cfg:
67 # Use a custom configuration for grub
68 grubefi_conf = custom_cfg
69 logger.debug("Using custom configuration file "
70 "%s for grub.cfg", configfile)
71 else:
72 raise WicError("configfile is specified but failed to "
73 "get it from %s." % configfile)
74
75 initrd = source_params.get('initrd')
76 dtb = source_params.get('dtb')
77
78 cls._copy_additional_files(hdddir, initrd, dtb)
79
80 if not custom_cfg:
81 # Create grub configuration using parameters from wks file
82 bootloader = creator.ks.bootloader
83 title = source_params.get('title')
84
85 grubefi_conf = ""
86 grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n"
87 grubefi_conf += "default=boot\n"
88 grubefi_conf += "timeout=%s\n" % bootloader.timeout
89 grubefi_conf += "menuentry '%s'{\n" % (title if title else "boot")
90
91 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
92 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
93 if get_bitbake_var("INITRAMFS_IMAGE"):
94 kernel = "%s-%s.bin" % \
95 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
96
97 label = source_params.get('label')
98 label_conf = "root=%s" % creator.rootdev
99 if label:
100 label_conf = "LABEL=%s" % label
101
102 grubefi_conf += "linux /%s %s rootwait %s\n" \
103 % (kernel, label_conf, bootloader.append)
104
105 if initrd:
106 initrds = initrd.split(';')
107 grubefi_conf += "initrd"
108 for rd in initrds:
109 grubefi_conf += " /%s" % rd
110 grubefi_conf += "\n"
111
112 if dtb:
113 grubefi_conf += "devicetree /%s\n" % dtb
114
115 grubefi_conf += "}\n"
116
117 logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg",
118 cr_workdir)
119 cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w")
120 cfg.write(grubefi_conf)
121 cfg.close()
122
123 @classmethod
124 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params):
125 """
126 Create loader-specific systemd-boot/gummiboot config
127 """
128 install_cmd = "install -d %s/loader" % hdddir
129 exec_cmd(install_cmd)
130
131 install_cmd = "install -d %s/loader/entries" % hdddir
132 exec_cmd(install_cmd)
133
134 bootloader = creator.ks.bootloader
135
136 unified_image = source_params.get('create-unified-kernel-image') == "true"
137
138 loader_conf = ""
139 if not unified_image:
140 loader_conf += "default boot\n"
141 loader_conf += "timeout %d\n" % bootloader.timeout
142
143 initrd = source_params.get('initrd')
144 dtb = source_params.get('dtb')
145
146 if not unified_image:
147 cls._copy_additional_files(hdddir, initrd, dtb)
148
149 logger.debug("Writing systemd-boot config "
150 "%s/hdd/boot/loader/loader.conf", cr_workdir)
151 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w")
152 cfg.write(loader_conf)
153 cfg.close()
154
155 configfile = creator.ks.bootloader.configfile
156 custom_cfg = None
157 if configfile:
158 custom_cfg = get_custom_config(configfile)
159 if custom_cfg:
160 # Use a custom configuration for systemd-boot
161 boot_conf = custom_cfg
162 logger.debug("Using custom configuration file "
163 "%s for systemd-boots's boot.conf", configfile)
164 else:
165 raise WicError("configfile is specified but failed to "
166 "get it from %s.", configfile)
167
168 if not custom_cfg:
169 # Create systemd-boot configuration using parameters from wks file
170 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
171 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
172 if get_bitbake_var("INITRAMFS_IMAGE"):
173 kernel = "%s-%s.bin" % \
174 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
175
176 title = source_params.get('title')
177
178 boot_conf = ""
179 boot_conf += "title %s\n" % (title if title else "boot")
180 boot_conf += "linux /%s\n" % kernel
181
182 label = source_params.get('label')
183 label_conf = "LABEL=Boot root=%s" % creator.rootdev
184 if label:
185 label_conf = "LABEL=%s" % label
186
187 boot_conf += "options %s %s\n" % \
188 (label_conf, bootloader.append)
189
190 if initrd:
191 initrds = initrd.split(';')
192 for rd in initrds:
193 boot_conf += "initrd /%s\n" % rd
194
195 if dtb:
196 boot_conf += "devicetree /%s\n" % dtb
197
198 if not unified_image:
199 logger.debug("Writing systemd-boot config "
200 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir)
201 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
202 cfg.write(boot_conf)
203 cfg.close()
204
205
206 @classmethod
207 def do_configure_partition(cls, part, source_params, creator, cr_workdir,
208 oe_builddir, bootimg_dir, kernel_dir,
209 native_sysroot):
210 """
211 Called before do_prepare_partition(), creates loader-specific config
212 """
213 hdddir = "%s/hdd/boot" % cr_workdir
214
215 install_cmd = "install -d %s/EFI/BOOT" % hdddir
216 exec_cmd(install_cmd)
217
218 try:
219 if source_params['loader'] == 'grub-efi':
220 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params)
221 elif source_params['loader'] == 'systemd-boot':
222 cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params)
223 elif source_params['loader'] == 'uefi-kernel':
224 pass
225 else:
226 raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader'])
227 except KeyError:
228 raise WicError("bootimg-efi requires a loader, none specified")
229
230 if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None:
231 logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES')
232 else:
233 boot_files = None
234 for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), (None, None)):
235 if fmt:
236 var = fmt % id
237 else:
238 var = ""
239
240 boot_files = get_bitbake_var("IMAGE_EFI_BOOT_FILES" + var)
241 if boot_files:
242 break
243
244 logger.debug('Boot files: %s', boot_files)
245
246 # list of tuples (src_name, dst_name)
247 deploy_files = []
248 for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files):
249 if ';' in src_entry:
250 dst_entry = tuple(src_entry.split(';'))
251 if not dst_entry[0] or not dst_entry[1]:
252 raise WicError('Malformed boot file entry: %s' % src_entry)
253 else:
254 dst_entry = (src_entry, src_entry)
255
256 logger.debug('Destination entry: %r', dst_entry)
257 deploy_files.append(dst_entry)
258
259 cls.install_task = [];
260 for deploy_entry in deploy_files:
261 src, dst = deploy_entry
262 if '*' in src:
263 # by default install files under their basename
264 entry_name_fn = os.path.basename
265 if dst != src:
266 # unless a target name was given, then treat name
267 # as a directory and append a basename
268 entry_name_fn = lambda name: \
269 os.path.join(dst,
270 os.path.basename(name))
271
272 srcs = glob(os.path.join(kernel_dir, src))
273
274 logger.debug('Globbed sources: %s', ', '.join(srcs))
275 for entry in srcs:
276 src = os.path.relpath(entry, kernel_dir)
277 entry_dst_name = entry_name_fn(entry)
278 cls.install_task.append((src, entry_dst_name))
279 else:
280 cls.install_task.append((src, dst))
281
282 @classmethod
283 def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
284 oe_builddir, bootimg_dir, kernel_dir,
285 rootfs_dir, native_sysroot):
286 """
287 Called to do the actual content population for a partition i.e. it
288 'prepares' the partition to be incorporated into the image.
289 In this case, prepare content for an EFI (grub) boot partition.
290 """
291 if not kernel_dir:
292 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
293 if not kernel_dir:
294 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
295
296 staging_kernel_dir = kernel_dir
297
298 hdddir = "%s/hdd/boot" % cr_workdir
299
300 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
301 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
302 if get_bitbake_var("INITRAMFS_IMAGE"):
303 kernel = "%s-%s.bin" % \
304 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
305
306 if source_params.get('create-unified-kernel-image') == "true":
307 initrd = source_params.get('initrd')
308 if not initrd:
309 raise WicError("initrd= must be specified when create-unified-kernel-image=true, exiting")
310
311 deploy_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
312 efi_stub = glob("%s/%s" % (deploy_dir, "linux*.efi.stub"))
313 if len(efi_stub) == 0:
314 raise WicError("Unified Kernel Image EFI stub not found, exiting")
315 efi_stub = efi_stub[0]
316
317 with tempfile.TemporaryDirectory() as tmp_dir:
318 label = source_params.get('label')
319 label_conf = "root=%s" % creator.rootdev
320 if label:
321 label_conf = "LABEL=%s" % label
322
323 bootloader = creator.ks.bootloader
324 cmdline = open("%s/cmdline" % tmp_dir, "w")
325 cmdline.write("%s %s" % (label_conf, bootloader.append))
326 cmdline.close()
327
328 initrds = initrd.split(';')
329 initrd = open("%s/initrd" % tmp_dir, "wb")
330 for f in initrds:
331 with open("%s/%s" % (deploy_dir, f), 'rb') as in_file:
332 shutil.copyfileobj(in_file, initrd)
333 initrd.close()
334
335 # Searched by systemd-boot:
336 # https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images
337 install_cmd = "install -d %s/EFI/Linux" % hdddir
338 exec_cmd(install_cmd)
339
340 staging_dir_host = get_bitbake_var("STAGING_DIR_HOST")
341 target_sys = get_bitbake_var("TARGET_SYS")
342
343 objdump_cmd = "%s-objdump" % target_sys
344 objdump_cmd += " -p %s" % efi_stub
345 objdump_cmd += " | awk '{ if ($1 == \"SectionAlignment\"){print $2} }'"
346
347 ret, align_str = exec_native_cmd(objdump_cmd, native_sysroot)
348 align = int(align_str, 16)
349
350 objdump_cmd = "%s-objdump" % target_sys
351 objdump_cmd += " -h %s | tail -2" % efi_stub
352 ret, output = exec_native_cmd(objdump_cmd, native_sysroot)
353
354 offset = int(output.split()[2], 16) + int(output.split()[3], 16)
355
356 osrel_off = offset + align - offset % align
357 osrel_path = "%s/usr/lib/os-release" % staging_dir_host
358 osrel_sz = os.stat(osrel_path).st_size
359
360 cmdline_off = osrel_off + osrel_sz
361 cmdline_off = cmdline_off + align - cmdline_off % align
362 cmdline_sz = os.stat(cmdline.name).st_size
363
364 dtb_off = cmdline_off + cmdline_sz
365 dtb_off = dtb_off + align - dtb_off % align
366
367 dtb = source_params.get('dtb')
368 if dtb:
369 if ';' in dtb:
370 raise WicError("Only one DTB supported, exiting")
371 dtb_path = "%s/%s" % (deploy_dir, dtb)
372 dtb_params = '--add-section .dtb=%s --change-section-vma .dtb=0x%x' % \
373 (dtb_path, dtb_off)
374 linux_off = dtb_off + os.stat(dtb_path).st_size
375 linux_off = linux_off + align - linux_off % align
376 else:
377 dtb_params = ''
378 linux_off = dtb_off
379
380 linux_path = "%s/%s" % (staging_kernel_dir, kernel)
381 linux_sz = os.stat(linux_path).st_size
382
383 initrd_off = linux_off + linux_sz
384 initrd_off = initrd_off + align - initrd_off % align
385
386 # https://www.freedesktop.org/software/systemd/man/systemd-stub.html
387 objcopy_cmd = "%s-objcopy" % target_sys
388 objcopy_cmd += " --enable-deterministic-archives"
389 objcopy_cmd += " --preserve-dates"
390 objcopy_cmd += " --add-section .osrel=%s" % osrel_path
391 objcopy_cmd += " --change-section-vma .osrel=0x%x" % osrel_off
392 objcopy_cmd += " --add-section .cmdline=%s" % cmdline.name
393 objcopy_cmd += " --change-section-vma .cmdline=0x%x" % cmdline_off
394 objcopy_cmd += dtb_params
395 objcopy_cmd += " --add-section .linux=%s" % linux_path
396 objcopy_cmd += " --change-section-vma .linux=0x%x" % linux_off
397 objcopy_cmd += " --add-section .initrd=%s" % initrd.name
398 objcopy_cmd += " --change-section-vma .initrd=0x%x" % initrd_off
399 objcopy_cmd += " %s %s/EFI/Linux/linux.efi" % (efi_stub, hdddir)
400
401 exec_native_cmd(objcopy_cmd, native_sysroot)
402 else:
403 if source_params.get('install-kernel-into-boot-dir') != 'false':
404 install_cmd = "install -m 0644 %s/%s %s/%s" % \
405 (staging_kernel_dir, kernel, hdddir, kernel)
406 exec_cmd(install_cmd)
407
408 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"):
409 for src_path, dst_path in cls.install_task:
410 install_cmd = "install -m 0644 -D %s %s" \
411 % (os.path.join(kernel_dir, src_path),
412 os.path.join(hdddir, dst_path))
413 exec_cmd(install_cmd)
414
415 try:
416 if source_params['loader'] == 'grub-efi':
417 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir,
418 "%s/grub.cfg" % cr_workdir)
419 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]:
420 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:])
421 exec_cmd(cp_cmd, True)
422 shutil.move("%s/grub.cfg" % cr_workdir,
423 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir)
424 elif source_params['loader'] == 'systemd-boot':
425 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]:
426 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:])
427 exec_cmd(cp_cmd, True)
428 elif source_params['loader'] == 'uefi-kernel':
429 kernel = get_bitbake_var("KERNEL_IMAGETYPE")
430 if not kernel:
431 raise WicError("Empty KERNEL_IMAGETYPE %s\n" % target)
432 target = get_bitbake_var("TARGET_SYS")
433 if not target:
434 raise WicError("Unknown arch (TARGET_SYS) %s\n" % target)
435
436 if re.match("x86_64", target):
437 kernel_efi_image = "bootx64.efi"
438 elif re.match('i.86', target):
439 kernel_efi_image = "bootia32.efi"
440 elif re.match('aarch64', target):
441 kernel_efi_image = "bootaa64.efi"
442 elif re.match('arm', target):
443 kernel_efi_image = "bootarm.efi"
444 else:
445 raise WicError("UEFI stub kernel is incompatible with target %s" % target)
446
447 for mod in [x for x in os.listdir(kernel_dir) if x.startswith(kernel)]:
448 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, kernel_efi_image)
449 exec_cmd(cp_cmd, True)
450 else:
451 raise WicError("unrecognized bootimg-efi loader: %s" %
452 source_params['loader'])
453 except KeyError:
454 raise WicError("bootimg-efi requires a loader, none specified")
455
456 startup = os.path.join(kernel_dir, "startup.nsh")
457 if os.path.exists(startup):
458 cp_cmd = "cp %s %s/" % (startup, hdddir)
459 exec_cmd(cp_cmd, True)
460
461 for paths in part.include_path or []:
462 for path in paths:
463 cp_cmd = "cp -r %s %s/" % (path, hdddir)
464 exec_cmd(cp_cmd, True)
465
466 du_cmd = "du -bks %s" % hdddir
467 out = exec_cmd(du_cmd)
468 blocks = int(out.split()[0])
469
470 extra_blocks = part.get_extra_block_count(blocks)
471
472 if extra_blocks < BOOTDD_EXTRA_SPACE:
473 extra_blocks = BOOTDD_EXTRA_SPACE
474
475 blocks += extra_blocks
476
477 logger.debug("Added %d extra blocks to %s to get to %d total blocks",
478 extra_blocks, part.mountpoint, blocks)
479
480 # required for compatibility with certain devices expecting file system
481 # block count to be equal to partition block count
482 if blocks < part.fixed_size:
483 blocks = part.fixed_size
484 logger.debug("Overriding %s to %d total blocks for compatibility",
485 part.mountpoint, blocks)
486
487 # dosfs image, created by mkdosfs
488 bootimg = "%s/boot.img" % cr_workdir
489
490 label = part.label if part.label else "ESP"
491
492 dosfs_cmd = "mkdosfs -n %s -i %s -C %s %d" % \
493 (label, part.fsuuid, bootimg, blocks)
494 exec_native_cmd(dosfs_cmd, native_sysroot)
495
496 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir)
497 exec_native_cmd(mcopy_cmd, native_sysroot)
498
499 chmod_cmd = "chmod 644 %s" % bootimg
500 exec_cmd(chmod_cmd)
501
502 du_cmd = "du -Lbks %s" % bootimg
503 out = exec_cmd(du_cmd)
504 bootimg_size = out.split()[0]
505
506 part.size = int(bootimg_size)
507 part.source_file = bootimg