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