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 shutil 16 17from wic import WicError 18from wic.engine import get_custom_config 19from wic.pluginbase import SourcePlugin 20from wic.misc import (exec_cmd, exec_native_cmd, 21 get_bitbake_var, BOOTDD_EXTRA_SPACE) 22 23logger = logging.getLogger('wic') 24 25class BootimgEFIPlugin(SourcePlugin): 26 """ 27 Create EFI boot partition. 28 This plugin supports GRUB 2 and systemd-boot bootloaders. 29 """ 30 31 name = 'bootimg-efi' 32 33 @classmethod 34 def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params): 35 """ 36 Create loader-specific (grub-efi) config 37 """ 38 configfile = creator.ks.bootloader.configfile 39 custom_cfg = None 40 if configfile: 41 custom_cfg = get_custom_config(configfile) 42 if custom_cfg: 43 # Use a custom configuration for grub 44 grubefi_conf = custom_cfg 45 logger.debug("Using custom configuration file " 46 "%s for grub.cfg", configfile) 47 else: 48 raise WicError("configfile is specified but failed to " 49 "get it from %s." % configfile) 50 51 initrd = source_params.get('initrd') 52 53 if initrd: 54 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 55 if not bootimg_dir: 56 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 57 58 initrds = initrd.split(';') 59 for rd in initrds: 60 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir) 61 exec_cmd(cp_cmd, True) 62 else: 63 logger.debug("Ignoring missing initrd") 64 65 if not custom_cfg: 66 # Create grub configuration using parameters from wks file 67 bootloader = creator.ks.bootloader 68 title = source_params.get('title') 69 70 grubefi_conf = "" 71 grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n" 72 grubefi_conf += "default=boot\n" 73 grubefi_conf += "timeout=%s\n" % bootloader.timeout 74 grubefi_conf += "menuentry '%s'{\n" % (title if title else "boot") 75 76 kernel = get_bitbake_var("KERNEL_IMAGETYPE") 77 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1": 78 if get_bitbake_var("INITRAMFS_IMAGE"): 79 kernel = "%s-%s.bin" % \ 80 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 81 82 label = source_params.get('label') 83 label_conf = "root=%s" % creator.rootdev 84 if label: 85 label_conf = "LABEL=%s" % label 86 87 grubefi_conf += "linux /%s %s rootwait %s\n" \ 88 % (kernel, label_conf, bootloader.append) 89 90 if initrd: 91 initrds = initrd.split(';') 92 grubefi_conf += "initrd" 93 for rd in initrds: 94 grubefi_conf += " /%s" % rd 95 grubefi_conf += "\n" 96 97 grubefi_conf += "}\n" 98 99 logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg", 100 cr_workdir) 101 cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w") 102 cfg.write(grubefi_conf) 103 cfg.close() 104 105 @classmethod 106 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params): 107 """ 108 Create loader-specific systemd-boot/gummiboot config 109 """ 110 install_cmd = "install -d %s/loader" % hdddir 111 exec_cmd(install_cmd) 112 113 install_cmd = "install -d %s/loader/entries" % hdddir 114 exec_cmd(install_cmd) 115 116 bootloader = creator.ks.bootloader 117 118 loader_conf = "" 119 loader_conf += "default boot\n" 120 loader_conf += "timeout %d\n" % bootloader.timeout 121 122 initrd = source_params.get('initrd') 123 124 if initrd: 125 # obviously we need to have a common common deploy var 126 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 127 if not bootimg_dir: 128 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 129 130 initrds = initrd.split(';') 131 for rd in initrds: 132 cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir) 133 exec_cmd(cp_cmd, True) 134 else: 135 logger.debug("Ignoring missing initrd") 136 137 logger.debug("Writing systemd-boot config " 138 "%s/hdd/boot/loader/loader.conf", cr_workdir) 139 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w") 140 cfg.write(loader_conf) 141 cfg.close() 142 143 configfile = creator.ks.bootloader.configfile 144 custom_cfg = None 145 if configfile: 146 custom_cfg = get_custom_config(configfile) 147 if custom_cfg: 148 # Use a custom configuration for systemd-boot 149 boot_conf = custom_cfg 150 logger.debug("Using custom configuration file " 151 "%s for systemd-boots's boot.conf", configfile) 152 else: 153 raise WicError("configfile is specified but failed to " 154 "get it from %s.", configfile) 155 156 if not custom_cfg: 157 # Create systemd-boot configuration using parameters from wks file 158 kernel = get_bitbake_var("KERNEL_IMAGETYPE") 159 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1": 160 if get_bitbake_var("INITRAMFS_IMAGE"): 161 kernel = "%s-%s.bin" % \ 162 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 163 164 title = source_params.get('title') 165 166 boot_conf = "" 167 boot_conf += "title %s\n" % (title if title else "boot") 168 boot_conf += "linux /%s\n" % kernel 169 170 label = source_params.get('label') 171 label_conf = "LABEL=Boot root=%s" % creator.rootdev 172 if label: 173 label_conf = "LABEL=%s" % label 174 175 boot_conf += "options %s %s\n" % \ 176 (label_conf, bootloader.append) 177 178 if initrd: 179 initrds = initrd.split(';') 180 for rd in initrds: 181 boot_conf += "initrd /%s\n" % rd 182 183 logger.debug("Writing systemd-boot config " 184 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir) 185 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w") 186 cfg.write(boot_conf) 187 cfg.close() 188 189 190 @classmethod 191 def do_configure_partition(cls, part, source_params, creator, cr_workdir, 192 oe_builddir, bootimg_dir, kernel_dir, 193 native_sysroot): 194 """ 195 Called before do_prepare_partition(), creates loader-specific config 196 """ 197 hdddir = "%s/hdd/boot" % cr_workdir 198 199 install_cmd = "install -d %s/EFI/BOOT" % hdddir 200 exec_cmd(install_cmd) 201 202 try: 203 if source_params['loader'] == 'grub-efi': 204 cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params) 205 elif source_params['loader'] == 'systemd-boot': 206 cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params) 207 else: 208 raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader']) 209 except KeyError: 210 raise WicError("bootimg-efi requires a loader, none specified") 211 212 213 @classmethod 214 def do_prepare_partition(cls, part, source_params, creator, cr_workdir, 215 oe_builddir, bootimg_dir, kernel_dir, 216 rootfs_dir, native_sysroot): 217 """ 218 Called to do the actual content population for a partition i.e. it 219 'prepares' the partition to be incorporated into the image. 220 In this case, prepare content for an EFI (grub) boot partition. 221 """ 222 if not kernel_dir: 223 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 224 if not kernel_dir: 225 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 226 227 staging_kernel_dir = kernel_dir 228 229 hdddir = "%s/hdd/boot" % cr_workdir 230 231 kernel = get_bitbake_var("KERNEL_IMAGETYPE") 232 if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1": 233 if get_bitbake_var("INITRAMFS_IMAGE"): 234 kernel = "%s-%s.bin" % \ 235 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 236 237 install_cmd = "install -m 0644 %s/%s %s/%s" % \ 238 (staging_kernel_dir, kernel, hdddir, kernel) 239 exec_cmd(install_cmd) 240 241 242 try: 243 if source_params['loader'] == 'grub-efi': 244 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, 245 "%s/grub.cfg" % cr_workdir) 246 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]: 247 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:]) 248 exec_cmd(cp_cmd, True) 249 shutil.move("%s/grub.cfg" % cr_workdir, 250 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir) 251 elif source_params['loader'] == 'systemd-boot': 252 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]: 253 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:]) 254 exec_cmd(cp_cmd, True) 255 else: 256 raise WicError("unrecognized bootimg-efi loader: %s" % 257 source_params['loader']) 258 except KeyError: 259 raise WicError("bootimg-efi requires a loader, none specified") 260 261 startup = os.path.join(kernel_dir, "startup.nsh") 262 if os.path.exists(startup): 263 cp_cmd = "cp %s %s/" % (startup, hdddir) 264 exec_cmd(cp_cmd, True) 265 266 du_cmd = "du -bks %s" % hdddir 267 out = exec_cmd(du_cmd) 268 blocks = int(out.split()[0]) 269 270 extra_blocks = part.get_extra_block_count(blocks) 271 272 if extra_blocks < BOOTDD_EXTRA_SPACE: 273 extra_blocks = BOOTDD_EXTRA_SPACE 274 275 blocks += extra_blocks 276 277 logger.debug("Added %d extra blocks to %s to get to %d total blocks", 278 extra_blocks, part.mountpoint, blocks) 279 280 # dosfs image, created by mkdosfs 281 bootimg = "%s/boot.img" % cr_workdir 282 283 label = part.label if part.label else "ESP" 284 285 dosfs_cmd = "mkdosfs -n %s -i %s -C %s %d" % \ 286 (label, part.fsuuid, bootimg, blocks) 287 exec_native_cmd(dosfs_cmd, native_sysroot) 288 289 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) 290 exec_native_cmd(mcopy_cmd, native_sysroot) 291 292 chmod_cmd = "chmod 644 %s" % bootimg 293 exec_cmd(chmod_cmd) 294 295 du_cmd = "du -Lbks %s" % bootimg 296 out = exec_cmd(du_cmd) 297 bootimg_size = out.split()[0] 298 299 part.size = int(bootimg_size) 300 part.source_file = bootimg 301