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-pcbios' source plugin class for 'wic' 22# 23# AUTHORS 24# Tom Zanussi <tom.zanussi (at] linux.intel.com> 25# 26 27import logging 28import os 29import re 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 BootimgPcbiosPlugin(SourcePlugin): 40 """ 41 Create MBR boot partition and install syslinux on it. 42 """ 43 44 name = 'bootimg-pcbios' 45 46 @classmethod 47 def _get_bootimg_dir(cls, bootimg_dir, dirname): 48 """ 49 Check if dirname exists in default bootimg_dir or in STAGING_DIR. 50 """ 51 staging_datadir = get_bitbake_var("STAGING_DATADIR") 52 for result in (bootimg_dir, staging_datadir): 53 if os.path.exists("%s/%s" % (result, dirname)): 54 return result 55 56 # STAGING_DATADIR is expanded with MLPREFIX if multilib is enabled 57 # but dependency syslinux is still populated to original STAGING_DATADIR 58 nonarch_datadir = re.sub('/[^/]*recipe-sysroot', '/recipe-sysroot', staging_datadir) 59 if os.path.exists(os.path.join(nonarch_datadir, dirname)): 60 return nonarch_datadir 61 62 raise WicError("Couldn't find correct bootimg_dir, exiting") 63 64 @classmethod 65 def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir, 66 bootimg_dir, kernel_dir, native_sysroot): 67 """ 68 Called after all partitions have been prepared and assembled into a 69 disk image. In this case, we install the MBR. 70 """ 71 bootimg_dir = cls._get_bootimg_dir(bootimg_dir, 'syslinux') 72 mbrfile = "%s/syslinux/" % bootimg_dir 73 if creator.ptable_format == 'msdos': 74 mbrfile += "mbr.bin" 75 elif creator.ptable_format == 'gpt': 76 mbrfile += "gptmbr.bin" 77 else: 78 raise WicError("Unsupported partition table: %s" % 79 creator.ptable_format) 80 81 if not os.path.exists(mbrfile): 82 raise WicError("Couldn't find %s. If using the -e option, do you " 83 "have the right MACHINE set in local.conf? If not, " 84 "is the bootimg_dir path correct?" % mbrfile) 85 86 full_path = creator._full_path(workdir, disk_name, "direct") 87 logger.debug("Installing MBR on disk %s as %s with size %s bytes", 88 disk_name, full_path, disk.min_size) 89 90 dd_cmd = "dd if=%s of=%s conv=notrunc" % (mbrfile, full_path) 91 exec_cmd(dd_cmd, native_sysroot) 92 93 @classmethod 94 def do_configure_partition(cls, part, source_params, creator, cr_workdir, 95 oe_builddir, bootimg_dir, kernel_dir, 96 native_sysroot): 97 """ 98 Called before do_prepare_partition(), creates syslinux config 99 """ 100 hdddir = "%s/hdd/boot" % cr_workdir 101 102 install_cmd = "install -d %s" % hdddir 103 exec_cmd(install_cmd) 104 105 bootloader = creator.ks.bootloader 106 107 custom_cfg = None 108 if bootloader.configfile: 109 custom_cfg = get_custom_config(bootloader.configfile) 110 if custom_cfg: 111 # Use a custom configuration for grub 112 syslinux_conf = custom_cfg 113 logger.debug("Using custom configuration file %s " 114 "for syslinux.cfg", bootloader.configfile) 115 else: 116 raise WicError("configfile is specified but failed to " 117 "get it from %s." % bootloader.configfile) 118 119 if not custom_cfg: 120 # Create syslinux configuration using parameters from wks file 121 splash = os.path.join(cr_workdir, "/hdd/boot/splash.jpg") 122 if os.path.exists(splash): 123 splashline = "menu background splash.jpg" 124 else: 125 splashline = "" 126 127 syslinux_conf = "" 128 syslinux_conf += "PROMPT 0\n" 129 syslinux_conf += "TIMEOUT " + str(bootloader.timeout) + "\n" 130 syslinux_conf += "\n" 131 syslinux_conf += "ALLOWOPTIONS 1\n" 132 syslinux_conf += "SERIAL 0 115200\n" 133 syslinux_conf += "\n" 134 if splashline: 135 syslinux_conf += "%s\n" % splashline 136 syslinux_conf += "DEFAULT boot\n" 137 syslinux_conf += "LABEL boot\n" 138 139 kernel = "/vmlinuz" 140 syslinux_conf += "KERNEL " + kernel + "\n" 141 142 syslinux_conf += "APPEND label=boot root=%s %s\n" % \ 143 (creator.rootdev, bootloader.append) 144 145 logger.debug("Writing syslinux config %s/hdd/boot/syslinux.cfg", 146 cr_workdir) 147 cfg = open("%s/hdd/boot/syslinux.cfg" % cr_workdir, "w") 148 cfg.write(syslinux_conf) 149 cfg.close() 150 151 @classmethod 152 def do_prepare_partition(cls, part, source_params, creator, cr_workdir, 153 oe_builddir, bootimg_dir, kernel_dir, 154 rootfs_dir, native_sysroot): 155 """ 156 Called to do the actual content population for a partition i.e. it 157 'prepares' the partition to be incorporated into the image. 158 In this case, prepare content for legacy bios boot partition. 159 """ 160 bootimg_dir = cls._get_bootimg_dir(bootimg_dir, 'syslinux') 161 162 staging_kernel_dir = kernel_dir 163 164 hdddir = "%s/hdd/boot" % cr_workdir 165 166 cmds = ("install -m 0644 %s/bzImage %s/vmlinuz" % 167 (staging_kernel_dir, hdddir), 168 "install -m 444 %s/syslinux/ldlinux.sys %s/ldlinux.sys" % 169 (bootimg_dir, hdddir), 170 "install -m 0644 %s/syslinux/vesamenu.c32 %s/vesamenu.c32" % 171 (bootimg_dir, hdddir), 172 "install -m 444 %s/syslinux/libcom32.c32 %s/libcom32.c32" % 173 (bootimg_dir, hdddir), 174 "install -m 444 %s/syslinux/libutil.c32 %s/libutil.c32" % 175 (bootimg_dir, hdddir)) 176 177 for install_cmd in cmds: 178 exec_cmd(install_cmd) 179 180 du_cmd = "du -bks %s" % hdddir 181 out = exec_cmd(du_cmd) 182 blocks = int(out.split()[0]) 183 184 extra_blocks = part.get_extra_block_count(blocks) 185 186 if extra_blocks < BOOTDD_EXTRA_SPACE: 187 extra_blocks = BOOTDD_EXTRA_SPACE 188 189 blocks += extra_blocks 190 191 logger.debug("Added %d extra blocks to %s to get to %d total blocks", 192 extra_blocks, part.mountpoint, blocks) 193 194 # dosfs image, created by mkdosfs 195 bootimg = "%s/boot%s.img" % (cr_workdir, part.lineno) 196 197 dosfs_cmd = "mkdosfs -n boot -i %s -S 512 -C %s %d" % \ 198 (part.fsuuid, bootimg, blocks) 199 exec_native_cmd(dosfs_cmd, native_sysroot) 200 201 mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) 202 exec_native_cmd(mcopy_cmd, native_sysroot) 203 204 syslinux_cmd = "syslinux %s" % bootimg 205 exec_native_cmd(syslinux_cmd, native_sysroot) 206 207 chmod_cmd = "chmod 644 %s" % bootimg 208 exec_cmd(chmod_cmd) 209 210 du_cmd = "du -Lbks %s" % bootimg 211 out = exec_cmd(du_cmd) 212 bootimg_size = out.split()[0] 213 214 part.size = int(bootimg_size) 215 part.source_file = bootimg 216