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