1# 2# SPDX-License-Identifier: GPL-2.0-only 3# 4# DESCRIPTION 5# This implements the 'bootimg-partition' source plugin class for 6# 'wic'. The plugin creates an image of boot partition, copying over 7# files listed in IMAGE_BOOT_FILES bitbake variable. 8# 9# AUTHORS 10# Maciej Borzecki <maciej.borzecki (at] open-rnd.pl> 11# 12 13import logging 14import os 15import re 16 17from glob import glob 18 19from wic import WicError 20from wic.engine import get_custom_config 21from wic.pluginbase import SourcePlugin 22from wic.misc import exec_cmd, get_bitbake_var 23 24logger = logging.getLogger('wic') 25 26class BootimgPartitionPlugin(SourcePlugin): 27 """ 28 Create an image of boot partition, copying over files 29 listed in IMAGE_BOOT_FILES bitbake variable. 30 """ 31 32 name = 'bootimg-partition' 33 34 @classmethod 35 def do_configure_partition(cls, part, source_params, cr, cr_workdir, 36 oe_builddir, bootimg_dir, kernel_dir, 37 native_sysroot): 38 """ 39 Called before do_prepare_partition(), create u-boot specific boot config 40 """ 41 hdddir = "%s/boot.%d" % (cr_workdir, part.lineno) 42 install_cmd = "install -d %s" % hdddir 43 exec_cmd(install_cmd) 44 45 if not kernel_dir: 46 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 47 if not kernel_dir: 48 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 49 50 boot_files = None 51 for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), (None, None)): 52 if fmt: 53 var = fmt % id 54 else: 55 var = "" 56 57 boot_files = get_bitbake_var("IMAGE_BOOT_FILES" + var) 58 if boot_files is not None: 59 break 60 61 if boot_files is None: 62 raise WicError('No boot files defined, IMAGE_BOOT_FILES unset for entry #%d' % part.lineno) 63 64 logger.debug('Boot files: %s', boot_files) 65 66 # list of tuples (src_name, dst_name) 67 deploy_files = [] 68 for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files): 69 if ';' in src_entry: 70 dst_entry = tuple(src_entry.split(';')) 71 if not dst_entry[0] or not dst_entry[1]: 72 raise WicError('Malformed boot file entry: %s' % src_entry) 73 else: 74 dst_entry = (src_entry, src_entry) 75 76 logger.debug('Destination entry: %r', dst_entry) 77 deploy_files.append(dst_entry) 78 79 cls.install_task = []; 80 for deploy_entry in deploy_files: 81 src, dst = deploy_entry 82 if '*' in src: 83 # by default install files under their basename 84 entry_name_fn = os.path.basename 85 if dst != src: 86 # unless a target name was given, then treat name 87 # as a directory and append a basename 88 entry_name_fn = lambda name: \ 89 os.path.join(dst, 90 os.path.basename(name)) 91 92 srcs = glob(os.path.join(kernel_dir, src)) 93 94 logger.debug('Globbed sources: %s', ', '.join(srcs)) 95 for entry in srcs: 96 src = os.path.relpath(entry, kernel_dir) 97 entry_dst_name = entry_name_fn(entry) 98 cls.install_task.append((src, entry_dst_name)) 99 else: 100 cls.install_task.append((src, dst)) 101 102 if source_params.get('loader') != "u-boot": 103 return 104 105 configfile = cr.ks.bootloader.configfile 106 custom_cfg = None 107 if configfile: 108 custom_cfg = get_custom_config(configfile) 109 if custom_cfg: 110 # Use a custom configuration for extlinux.conf 111 extlinux_conf = custom_cfg 112 logger.debug("Using custom configuration file " 113 "%s for extlinux.cfg", configfile) 114 else: 115 raise WicError("configfile is specified but failed to " 116 "get it from %s." % configfile) 117 118 if not custom_cfg: 119 # The kernel types supported by the sysboot of u-boot 120 kernel_types = ["zImage", "Image", "fitImage", "uImage", "vmlinux"] 121 has_dtb = False 122 fdt_dir = '/' 123 kernel_name = None 124 125 # Find the kernel image name, from the highest precedence to lowest 126 for image in kernel_types: 127 for task in cls.install_task: 128 src, dst = task 129 if re.match(image, src): 130 kernel_name = os.path.join('/', dst) 131 break 132 if kernel_name: 133 break 134 135 for task in cls.install_task: 136 src, dst = task 137 # We suppose that all the dtb are in the same directory 138 if re.search(r'\.dtb', src) and fdt_dir == '/': 139 has_dtb = True 140 fdt_dir = os.path.join(fdt_dir, os.path.dirname(dst)) 141 break 142 143 if not kernel_name: 144 raise WicError('No kernel file founded') 145 146 # Compose the extlinux.conf 147 extlinux_conf = "default Yocto\n" 148 extlinux_conf += "label Yocto\n" 149 extlinux_conf += " kernel %s\n" % kernel_name 150 if has_dtb: 151 extlinux_conf += " fdtdir %s\n" % fdt_dir 152 bootloader = cr.ks.bootloader 153 extlinux_conf += "append root=%s rootwait %s\n" \ 154 % (cr.rootdev, bootloader.append if bootloader.append else '') 155 156 install_cmd = "install -d %s/extlinux/" % hdddir 157 exec_cmd(install_cmd) 158 cfg = open("%s/extlinux/extlinux.conf" % hdddir, "w") 159 cfg.write(extlinux_conf) 160 cfg.close() 161 162 163 @classmethod 164 def do_prepare_partition(cls, part, source_params, cr, cr_workdir, 165 oe_builddir, bootimg_dir, kernel_dir, 166 rootfs_dir, native_sysroot): 167 """ 168 Called to do the actual content population for a partition i.e. it 169 'prepares' the partition to be incorporated into the image. 170 In this case, does the following: 171 - sets up a vfat partition 172 - copies all files listed in IMAGE_BOOT_FILES variable 173 """ 174 hdddir = "%s/boot.%d" % (cr_workdir, part.lineno) 175 176 if not kernel_dir: 177 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 178 if not kernel_dir: 179 raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") 180 181 logger.debug('Kernel dir: %s', bootimg_dir) 182 183 184 for task in cls.install_task: 185 src_path, dst_path = task 186 logger.debug('Install %s as %s', src_path, dst_path) 187 install_cmd = "install -m 0644 -D %s %s" \ 188 % (os.path.join(kernel_dir, src_path), 189 os.path.join(hdddir, dst_path)) 190 exec_cmd(install_cmd) 191 192 logger.debug('Prepare boot partition using rootfs in %s', hdddir) 193 part.prepare_rootfs(cr_workdir, oe_builddir, hdddir, 194 native_sysroot, False) 195