1# ex:ts=4:sw=4:sts=4:et 2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- 3# 4# Copyright (c) 2014, Intel Corporation. 5# All rights reserved. 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License version 2 as 9# published by the Free Software Foundation. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License along 17# with this program; if not, write to the Free Software Foundation, Inc., 18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19# 20# DESCRIPTION 21# This implements the 'bootimg-efi' source plugin class for 'wic' 22# 23# AUTHORS 24# Tom Zanussi <tom.zanussi (at] linux.intel.com> 25# 26 27import logging 28import os 29import shutil 30 31from wic import WicError 32from wic.engine import get_custom_config 33from wic.pluginbase import SourcePlugin 34from wic.misc import (exec_cmd, exec_native_cmd, 35 get_bitbake_var, BOOTDD_EXTRA_SPACE) 36 37logger = logging.getLogger('wic') 38 39class BootimgEFIPlugin(SourcePlugin): 40 """ 41 Create EFI boot partition. 42 This plugin supports GRUB 2 and systemd-boot bootloaders. 43 """ 44 45 name = 'bootimg-efi' 46 47 @classmethod 48 def do_configure_grubefi(cls, creator, cr_workdir): 49 """ 50 Create loader-specific (grub-efi) config 51 """ 52 configfile = creator.ks.bootloader.configfile 53 custom_cfg = None 54 if configfile: 55 custom_cfg = get_custom_config(configfile) 56 if custom_cfg: 57 # Use a custom configuration for grub 58 grubefi_conf = custom_cfg 59 logger.debug("Using custom configuration file " 60 "%s for grub.cfg", configfile) 61 else: 62 raise WicError("configfile is specified but failed to " 63 "get it from %s." % configfile) 64 65 if not custom_cfg: 66 # Create grub configuration using parameters from wks file 67 bootloader = creator.ks.bootloader 68 69 grubefi_conf = "" 70 grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n" 71 grubefi_conf += "default=boot\n" 72 grubefi_conf += "timeout=%s\n" % bootloader.timeout 73 grubefi_conf += "menuentry 'boot'{\n" 74 75 kernel = "/bzImage" 76 77 grubefi_conf += "linux %s root=%s rootwait %s\n" \ 78 % (kernel, creator.rootdev, bootloader.append) 79 grubefi_conf += "}\n" 80 81 logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg", 82 cr_workdir) 83 cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w") 84 cfg.write(grubefi_conf) 85 cfg.close() 86 87 @classmethod 88 def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params): 89 """ 90 Create loader-specific systemd-boot/gummiboot config 91 """ 92 install_cmd = "install -d %s/loader" % hdddir 93 exec_cmd(install_cmd) 94 95 install_cmd = "install -d %s/loader/entries" % hdddir 96 exec_cmd(install_cmd) 97 98 bootloader = creator.ks.bootloader 99 100 loader_conf = "" 101 loader_conf += "default boot\n" 102 loader_conf += "timeout %d\n" % bootloader.timeout 103 104 initrd = source_params.get('initrd') 105 106 if initrd: 107 # obviously we need to have a common common deploy var 108 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 109 if not bootimg_dir: 110 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 111 112 cp_cmd = "cp %s/%s %s" % (bootimg_dir, initrd, hdddir) 113 exec_cmd(cp_cmd, True) 114 else: 115 logger.debug("Ignoring missing initrd") 116 117 logger.debug("Writing systemd-boot config " 118 "%s/hdd/boot/loader/loader.conf", cr_workdir) 119 cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w") 120 cfg.write(loader_conf) 121 cfg.close() 122 123 configfile = creator.ks.bootloader.configfile 124 custom_cfg = None 125 if configfile: 126 custom_cfg = get_custom_config(configfile) 127 if custom_cfg: 128 # Use a custom configuration for systemd-boot 129 boot_conf = custom_cfg 130 logger.debug("Using custom configuration file " 131 "%s for systemd-boots's boot.conf", configfile) 132 else: 133 raise WicError("configfile is specified but failed to " 134 "get it from %s.", configfile) 135 136 if not custom_cfg: 137 # Create systemd-boot configuration using parameters from wks file 138 kernel = "/bzImage" 139 140 boot_conf = "" 141 boot_conf += "title boot\n" 142 boot_conf += "linux %s\n" % kernel 143 boot_conf += "options LABEL=Boot root=%s %s\n" % \ 144 (creator.rootdev, bootloader.append) 145 146 if initrd: 147 boot_conf += "initrd /%s\n" % initrd 148 149 logger.debug("Writing systemd-boot config " 150 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir) 151 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w") 152 cfg.write(boot_conf) 153 cfg.close() 154 155 156 @classmethod 157 def do_configure_partition(cls, part, source_params, creator, cr_workdir, 158 oe_builddir, bootimg_dir, kernel_dir, 159 native_sysroot): 160 """ 161 Called before do_prepare_partition(), creates loader-specific config 162 """ 163 hdddir = "%s/hdd/boot" % cr_workdir 164 165 install_cmd = "install -d %s/EFI/BOOT" % hdddir 166 exec_cmd(install_cmd) 167 168 try: 169 if source_params['loader'] == 'grub-efi': 170 cls.do_configure_grubefi(creator, cr_workdir) 171 elif source_params['loader'] == 'systemd-boot': 172 cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params) 173 else: 174 raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader']) 175 except KeyError: 176 raise WicError("bootimg-efi requires a loader, none specified") 177 178 179 @classmethod 180 def do_prepare_partition(cls, part, source_params, creator, cr_workdir, 181 oe_builddir, bootimg_dir, kernel_dir, 182 rootfs_dir, native_sysroot): 183 """ 184 Called to do the actual content population for a partition i.e. it 185 'prepares' the partition to be incorporated into the image. 186 In this case, prepare content for an EFI (grub) boot partition. 187 """ 188 if not kernel_dir: 189 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 190 if not kernel_dir: 191 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 192 193 staging_kernel_dir = kernel_dir 194 195 hdddir = "%s/hdd/boot" % cr_workdir 196 197 install_cmd = "install -m 0644 %s/bzImage %s/bzImage" % \ 198 (staging_kernel_dir, hdddir) 199 exec_cmd(install_cmd) 200 201 202 try: 203 if source_params['loader'] == 'grub-efi': 204 shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, 205 "%s/grub.cfg" % cr_workdir) 206 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]: 207 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:]) 208 exec_cmd(cp_cmd, True) 209 shutil.move("%s/grub.cfg" % cr_workdir, 210 "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir) 211 elif source_params['loader'] == 'systemd-boot': 212 for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]: 213 cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:]) 214 exec_cmd(cp_cmd, True) 215 else: 216 raise WicError("unrecognized bootimg-efi loader: %s" % 217 source_params['loader']) 218 except KeyError: 219 raise WicError("bootimg-efi requires a loader, none specified") 220 221 startup = os.path.join(kernel_dir, "startup.nsh") 222 if os.path.exists(startup): 223 cp_cmd = "cp %s %s/" % (startup, hdddir) 224 exec_cmd(cp_cmd, True) 225 226 du_cmd = "du -bks %s" % hdddir 227 out = exec_cmd(du_cmd) 228 blocks = int(out.split()[0]) 229 230 extra_blocks = part.get_extra_block_count(blocks) 231 232 if extra_blocks < BOOTDD_EXTRA_SPACE: 233 extra_blocks = BOOTDD_EXTRA_SPACE 234 235 blocks += extra_blocks 236 237 logger.debug("Added %d extra blocks to %s to get to %d total blocks", 238 extra_blocks, part.mountpoint, blocks) 239 240 # dosfs image, created by mkdosfs 241 bootimg = "%s/boot.img" % cr_workdir 242 243 dosfs_cmd = "mkdosfs -n efi -i %s -C %s %d" % \ 244 (part.fsuuid, bootimg, blocks) 245 exec_native_cmd(dosfs_cmd, native_sysroot) 246 247 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) 248 exec_native_cmd(mcopy_cmd, native_sysroot) 249 250 chmod_cmd = "chmod 644 %s" % bootimg 251 exec_cmd(chmod_cmd) 252 253 du_cmd = "du -Lbks %s" % bootimg 254 out = exec_cmd(du_cmd) 255 bootimg_size = out.split()[0] 256 257 part.size = int(bootimg_size) 258 part.source_file = bootimg 259