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