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