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