From 9c4581d03de36644ed28186250aef7eff4197963 Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Mon, 4 Feb 2019 15:30:09 +0100 Subject: [PATCH] Add classes - archiver_stm32mp: help to generate archiver with sdk - extlinuxconf-stm32mp: help to generate u-boot extlinux.conf - flashlayout-stm32mp: help to generate layer for ST flasher - images_types-stubi: help to customize nand image - st-partitions-image: rules to clean images contents Signed-off-by: Christophe Priouzeau --- classes/archiver_stm32mp_clean.bbclass | 40 +++ classes/extlinuxconf-stm32mp.bbclass | 248 +++++++++++++++ classes/flashlayout-stm32mp.bbclass | 398 +++++++++++++++++++++++++ classes/image_types-stubi.bbclass | 131 ++++++++ classes/st-partitions-image.bbclass | 56 ++++ 5 files changed, 873 insertions(+) create mode 100644 classes/archiver_stm32mp_clean.bbclass create mode 100644 classes/extlinuxconf-stm32mp.bbclass create mode 100644 classes/flashlayout-stm32mp.bbclass create mode 100644 classes/image_types-stubi.bbclass create mode 100755 classes/st-partitions-image.bbclass diff --git a/classes/archiver_stm32mp_clean.bbclass b/classes/archiver_stm32mp_clean.bbclass new file mode 100644 index 0000000..af51493 --- /dev/null +++ b/classes/archiver_stm32mp_clean.bbclass @@ -0,0 +1,40 @@ +python archiver_clean_tarball() { + from os import listdir + import tarfile + import shutil, tempfile + import os + + ar_outdir = d.getVar('ARCHIVER_OUTDIR') + #get tarball name + tarball_name = [f for f in listdir(ar_outdir) if f.endswith("tar.gz")] + tmpdir = tempfile.mkdtemp(dir=d.getVar('ARCHIVER_WORKDIR')) + if tarball_name and tarball_name[0] and len(tarball_name[0]) > 0: + tar = tarfile.open(os.path.join(ar_outdir,tarball_name[0])) + tar.extractall(path=tmpdir) + tar.close() + dirs_list = [f for f in listdir(tmpdir) if os.path.isdir(os.path.join(tmpdir, f))] + if len(dirs_list) == 1: + if os.path.exists(os.path.join(tmpdir,dirs_list[0],"git", ".git")): + src_origin = os.path.join(tmpdir,dirs_list[0], '.') + shutil.rmtree(os.path.join(tmpdir,dirs_list[0],"git", ".git")) + os.remove(os.path.join(ar_outdir,tarball_name[0])) + subdirs_list = [f for f in listdir(os.path.join(tmpdir,dirs_list[0])) if os.path.isdir(os.path.join(tmpdir,dirs_list[0], f))] + if len(subdirs_list) == 1: + src_origin = os.path.join(tmpdir,dirs_list[0],subdirs_list[0]) + create_tarball(d, src_origin, '', ar_outdir) +} +do_ar_original[postfuncs] =+ "archiver_clean_tarball" + +ARCHIVER_README = "README.HOW_TO.txt" +archiver_git_uri() { + ret=`echo "${SRC_URI}" | grep branch | wc -l` + if [ $ret -gt 0 ]; then + BRANCH=`echo "${SRC_URI}" | sed "s|.*branch=\([^ ;]*\).*|\1|" ` + else + BRANCH=master + fi + + sed -i -e "s|##GIT_BRANCH##|$BRANCH|g" -e "s|##GIT_SRCREV##|${SRCREV}|g" ${ARCHIVER_OUTDIR}/${ARCHIVER_README} +} +do_ar_original[postfuncs] =+ "archiver_git_uri" + diff --git a/classes/extlinuxconf-stm32mp.bbclass b/classes/extlinuxconf-stm32mp.bbclass new file mode 100644 index 0000000..0869640 --- /dev/null +++ b/classes/extlinuxconf-stm32mp.bbclass @@ -0,0 +1,248 @@ +# Copyright (C) 2017, STMicroelectronics - All Rights Reserved +# Released under the MIT license (see COPYING.MIT for the terms) +# +# -------------------------------------------------------------------- +# Extract from openembedded-core 'uboot-extlinux-config.bbclass' class +# -------------------------------------------------------------------- +# External variables: +# +# UBOOT_EXTLINUX_CONSOLE - Set to "console=ttyX" to change kernel boot +# default console. +# UBOOT_EXTLINUX_LABELS - A list of targets for the automatic config. +# UBOOT_EXTLINUX_KERNEL_ARGS - Add additional kernel arguments. +# UBOOT_EXTLINUX_KERNEL_IMAGE - Kernel image name. +# UBOOT_EXTLINUX_FDTDIR - Device tree directory. +# UBOOT_EXTLINUX_FDT - Device tree file. +# UBOOT_EXTLINUX_INITRD - Indicates a list of filesystem images to +# concatenate and use as an initrd (optional). +# UBOOT_EXTLINUX_MENU_DESCRIPTION - Name to use as description. +# UBOOT_EXTLINUX_ROOT - Root kernel cmdline. +# UBOOT_EXTLINUX_TIMEOUT - Timeout before DEFAULT selection is made. +# Measured in 1/10 of a second. +# UBOOT_EXTLINUX_DEFAULT_LABEL - Target to be selected by default after +# the timeout period +# +# If there's only one label system will boot automatically and menu won't be +# created. If you want to use more than one labels, e.g linux and alternate, +# use overrides to set menu description, console and others variables. +# +# -------------------------------------------------------------------- +# STM32MP specific implementation +# -------------------------------------------------------------------- +# Append new mechanism to allow multi 'extlinux.conf' file generation. +# - multiple targets case: +# each 'extlinux.conf' file generated is created under specific path: +# '${B}/extlinux/extlinux.conf' +# - simple target case: +# the 'extlinux.conf' file generated is created under default path: +# '${B}/extlinux/extlinux.conf' +# +# New external variables added: +# UBOOT_EXTLINUX_TARGETS - A list of targets for multi config file +# generation +# UBOOT_EXTLINUX_BOOTPREFIXES - Bootprefix used in uboot script to select +# extlinux.conf file to use +# +# -------------------------------------------------------------------- +# Output example: +# -------------------------------------------------------------------- +# Following 'extlinux.conf' files are generated under ${UBOOT_EXTLINUX_INSTALL_DIR}: +# ${UBOOT_EXTLINUX_BOOTPREFIXES_${UBOOT_EXTLINUX_TARGETS}[0]}extlinux/extlinux.conf +# ${UBOOT_EXTLINUX_BOOTPREFIXES_${UBOOT_EXTLINUX_TARGETS}[1]}extlinux/extlinux.conf +# +# File content (${UBOOT_EXTLINUX_BOOTPREFIXES_${UBOOT_EXTLINUX_TARGETS}[0]}extlinux/exlinux.conf): +# menu title Select the boot mode +# TIMEOUT ${UBOOT_EXTLINUX_TIMEOUT} +# DEFAULT ${UBOOT_EXTLINUX_DEFAULT_LABEL_${UBOOT_EXTLINUX_TARGETS}[0]} +# LABEL ${UBOOT_EXTLINUX_LABELS_${UBOOT_EXTLINUX_TARGETS}[0]}[0] +# KERNEL ${UBOOT_EXTLINUX_KERNEL} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_KERNEL_${IMAGE_UBOOT_EXTLINUX_LABELS}[0]} > +# FDT ${UBOOT_EXTLINUX_FDT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_FDT_${IMAGE_UBOOT_EXTLINUX_LABELS}[0]} > +# APPEND ${UBOOT_EXTLINUX_ROOT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_ROOT_${IMAGE_UBOOT_EXTLINUX_LABELS}[0]} > +# LABEL ${UBOOT_EXTLINUX_LABELS_${UBOOT_EXTLINUX_TARGETS}[0]}[1] +# KERNEL ${UBOOT_EXTLINUX_KERNEL} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_KERNEL_${IMAGE_UBOOT_EXTLINUX_LABELS}[1]} > +# FDT ${UBOOT_EXTLINUX_FDT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_FDT_${IMAGE_UBOOT_EXTLINUX_LABELS}[1]} > +# APPEND ${UBOOT_EXTLINUX_ROOT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_ROOT_${IMAGE_UBOOT_EXTLINUX_LABELS}[1]} > +# +# File content (${UBOOT_EXTLINUX_BOOTPREFIXES_${UBOOT_EXTLINUX_TARGETS}[0]}extlinux/exlinux.conf): +# menu title Select the boot mode +# TIMEOUT ${UBOOT_EXTLINUX_TIMEOUT} +# DEFAULT ${UBOOT_EXTLINUX_DEFAULT_LABEL_${UBOOT_EXTLINUX_TARGETS}[1]} +# LABEL ${UBOOT_EXTLINUX_LABELS_${UBOOT_EXTLINUX_TARGETS}[1]}[0] +# KERNEL ${UBOOT_EXTLINUX_KERNEL} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_KERNEL_${IMAGE_UBOOT_EXTLINUX_LABELS}[0]} > +# FDT ${UBOOT_EXTLINUX_FDT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_FDT_${IMAGE_UBOOT_EXTLINUX_LABELS}[0]} > +# APPEND ${UBOOT_EXTLINUX_ROOT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_ROOT_${IMAGE_UBOOT_EXTLINUX_LABELS}[0]} > +# LABEL ${UBOOT_EXTLINUX_LABELS_${UBOOT_EXTLINUX_TARGETS}[1]}[1] +# KERNEL ${UBOOT_EXTLINUX_KERNEL} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_KERNEL_${IMAGE_UBOOT_EXTLINUX_LABELS}[1]} > +# FDT ${UBOOT_EXTLINUX_FDT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_FDT_${IMAGE_UBOOT_EXTLINUX_LABELS}[1]} > +# APPEND ${UBOOT_EXTLINUX_ROOT} < OR OVERRIDE WITH : ${UBOOT_EXTLINUX_ROOT_${IMAGE_UBOOT_EXTLINUX_LABELS}[1]} > +# -------------------------------------------------------------------- + +UBOOT_EXTLINUX_TARGETS ?= "" + +UBOOT_EXTLINUX_CONSOLE ??= "console=${console}" +UBOOT_EXTLINUX_LABELS ??= "linux" +UBOOT_EXTLINUX_FDT ??= "" +UBOOT_EXTLINUX_FDTDIR ??= "../" +UBOOT_EXTLINUX_KERNEL_IMAGE ?= "/${KERNEL_IMAGETYPE}" +UBOOT_EXTLINUX_KERNEL_ARGS ?= "rootwait rw" +UBOOT_EXTLINUX_TIMEOUT ?= "20" + +UBOOT_EXTLINUX_CONFIGURE_FILES ??= "" + +python update_extlinuxconf_targets() { + """ + Append dynamically to UBOOT_EXTLINUX_TARGETS new target list generated from + config flag list (UBOOT_EXTLINUX_CONFIG_FLAGS) and supported devicetree list + for each flag (UBOOT_EXTLINUX_DEVICEFLAG_xxx) + """ + import re + + default_targets = d.getVar('UBOOT_EXTLINUX_CONFIGURED_TARGETS') + if not default_targets: + bb.fatal("UBOOT_EXTLINUX_CONFIGURED_TARGETS not defined, please update your config") + if not default_targets.strip(): + bb.fatal("No UBOOT_EXTLINUX_CONFIGURED_TARGETS list defined, nothing to do") + bb.note('UBOOT_EXTLINUX_CONFIGURED_TARGETS: %s' % default_targets) + + config_flags = d.getVar('UBOOT_EXTLINUX_CONFIG_FLAGS') + if not config_flags: + bb.fatal("UBOOT_EXTLINUX_CONFIG_FLAGS not defined, please update your config") + if not config_flags.strip(): + bb.fatal("No UBOOT_EXTLINUX_CONFIG_FLAGS list defined, nothing to do") + bb.note('UBOOT_EXTLINUX_CONFIG_FLAGS: %s' % config_flags) + + for config_label in config_flags.split(): + bb.note('*** Loop for config_label: %s' % config_label) + devicetree_list = d.getVar('UBOOT_EXTLINUX_DEVICEFLAG_%s' % config_label) or '' + if devicetree_list is None: + continue + for devicetree in devicetree_list.split(): + bb.note('*** Loop for devicetree: %s' % devicetree) + target_prefix = re.match('^stm32(.*)$', devicetree) + new_target = target_prefix.group(1) + '_' + config_label + bb.note('>>> New target label: %s' % new_target) + if not new_target in default_targets.split(): + bb.note('Computed target: "%s" is not part of UBOOT_EXTLINUX_CONFIGURED_TARGETS: %s' % (new_target, default_targets)) + bb.note('Target not append to UBOOT_EXTLINUX_TARGETS') + continue + # Append target to UBOOT_EXTLINUX_TARGETS list + d.appendVar('UBOOT_EXTLINUX_TARGETS', ' ' + new_target) + bb.note('>>> Append %s to UBOOT_EXTLINUX_TARGETS' % new_target) + bb.note('>>> UBOOT_EXTLINUX_TARGETS (updated): %s' % d.getVar('UBOOT_EXTLINUX_TARGETS')) +} + +python do_create_multiextlinux_config() { + targets = d.getVar('UBOOT_EXTLINUX_TARGETS') + if not targets: + bb.fatal("UBOOT_EXTLINUX_TARGETS not defined, nothing to do") + if not targets.strip(): + bb.fatal("No targets, nothing to do") + + for target in targets.split(): + + localdata = bb.data.createCopy(d) + overrides = localdata.getVar('OVERRIDES') + if not overrides: + bb.fatal('OVERRIDES not defined') + localdata.setVar('OVERRIDES', target + ':' + overrides) + + # Initialize labels from localdata to allow target override + labels = localdata.getVar('UBOOT_EXTLINUX_LABELS') + if not labels: + bb.fatal("UBOOT_EXTLINUX_LABELS not defined, nothing to do") + if not labels.strip(): + bb.fatal("No labels, nothing to do") + + # Initialize subdir for extlinux.conf file location + if len(targets.split()) > 1: + bootprefix = localdata.getVar('UBOOT_EXTLINUX_BOOTPREFIXES') or "" + subdir = bootprefix + 'extlinux' + else: + subdir = 'extlinux' + + # Initialize config file + cfile = os.path.join(d.getVar('B'), subdir , 'extlinux.conf') + + # Create extlinux folder + bb.utils.mkdirhier(os.path.dirname(cfile)) + + # ************************************************************ + # Copy/Paste extract of 'do_create_extlinux_config()' function + # from openembedded-core 'uboot-extlinux-config.bbclass' class + # ************************************************************ + try: + with open(cfile, 'w') as cfgfile: + cfgfile.write('# Generic Distro Configuration file generated by OpenEmbedded\n') + + if len(labels.split()) > 1: + cfgfile.write('menu title Select the boot mode\n') + + spashscreen_name = localdata.getVar('UBOOT_SPLASH_IMAGE') + if not spashscreen_name: + bb.warn('UBOOT_SPLASH_IMAGE not defined') + else: + cfgfile.write('MENU BACKGROUND ../%s.bmp\n' % (spashscreen_name)) + + timeout = localdata.getVar('UBOOT_EXTLINUX_TIMEOUT') + if timeout: + cfgfile.write('TIMEOUT %s\n' % (timeout)) + + if len(labels.split()) > 1: + default = localdata.getVar('UBOOT_EXTLINUX_DEFAULT_LABEL') + if default: + cfgfile.write('DEFAULT %s\n' % (default)) + + for label in labels.split(): + # ********************************************** + # Add localdata reset to fix var expansion issue + # ********************************************** + localdata = bb.data.createCopy(d) + + overrides = localdata.getVar('OVERRIDES') + if not overrides: + bb.fatal('OVERRIDES not defined') + + localdata.setVar('OVERRIDES', label + ':' + overrides) + + extlinux_console = localdata.getVar('UBOOT_EXTLINUX_CONSOLE') + + menu_description = localdata.getVar('UBOOT_EXTLINUX_MENU_DESCRIPTION') + if not menu_description: + menu_description = label + + root = localdata.getVar('UBOOT_EXTLINUX_ROOT') + if not root: + bb.fatal('UBOOT_EXTLINUX_ROOT not defined') + + kernel_image = localdata.getVar('UBOOT_EXTLINUX_KERNEL_IMAGE') + fdtdir = localdata.getVar('UBOOT_EXTLINUX_FDTDIR') + + fdt = localdata.getVar('UBOOT_EXTLINUX_FDT') + + if fdt: + cfgfile.write('LABEL %s\n\tKERNEL %s\n\tFDT %s\n' % + (menu_description, kernel_image, fdt)) + elif fdtdir: + cfgfile.write('LABEL %s\n\tKERNEL %s\n\tFDTDIR %s\n' % + (menu_description, kernel_image, fdtdir)) + else: + cfgfile.write('LABEL %s\n\tKERNEL %s\n' % (menu_description, kernel_image)) + + kernel_args = localdata.getVar('UBOOT_EXTLINUX_KERNEL_ARGS') + + initrd = localdata.getVar('UBOOT_EXTLINUX_INITRD') + if initrd: + cfgfile.write('\tINITRD %s\n'% initrd) + + kernel_args = root + " " + kernel_args + cfgfile.write('\tAPPEND %s %s\n' % (kernel_args, extlinux_console)) + + except OSError: + bb.fatal('Unable to open %s' % (cfile)) +} +addtask create_multiextlinux_config before do_compile + +do_create_multiextlinux_config[dirs] += "${B}" +do_create_multiextlinux_config[cleandirs] += "${B}" +do_create_multiextlinux_config[prefuncs] += "update_extlinuxconf_targets" +do_create_multiextlinux_config[file-checksums] += "${UBOOT_EXTLINUX_CONFIGURE_FILES}" diff --git a/classes/flashlayout-stm32mp.bbclass b/classes/flashlayout-stm32mp.bbclass new file mode 100644 index 0000000..b8a2514 --- /dev/null +++ b/classes/flashlayout-stm32mp.bbclass @@ -0,0 +1,398 @@ +# ----------------------------------------------------------------------------- +# This class allows to output in deploy folder, along with the built image, the +# 'flashlayout_${PN}' sub-folder, populated with the flashlayout files to use +# with our STM32MP programmer tool to load the binaries in target device and +# partitions. +# +# There are two configurations: +# * static: +# The user provides the flashlayout files to export with the built image. +# * dynamic: +# The user configures the different variables to generate the expected +# flashlayout files. +# +# -------------------- +# Static configuration +# -------------------- +# Set ENABLE_FLASHLAYOUT_DEFAULT to '1'. +# Configure FLASHLAYOUT_DEFAULT_SRC with the static flashlayout file locations. +# +# Configuration example (machine file or local.conf): +# ENABLE_FLASHLAYOUT_DEFAULT = "1" +# FLASHLAYOUT_DEFAULT_SRC = "${STM32MP_BASE}/files/flashlayouts/FlashLayout_sdcard_stm32mp157c-ev1_sample.tsv" +# +# --------------------- +# Dynamic configuration +# --------------------- +# Set ENABLE_FLASHLAYOUT_DEFAULT to '0'. +# In order to automatically generate flashlayout files as well formated TSV file +# there are some variables to configure. +# +# Naming: +# [_][_-FLASHLAYOUT_BOOTSCHEME_LABEL]. +# +# FLASHLAYOUT_BASENAME +# Default to 'FlashLayout' +# FLASHLAYOUT_CONFIG_LABEL +# Set from FLASHLAYOUT_CONFIG_LABELS list (without any '_' in config labels) +# FLASHLAYOUT_TYPE_LABEL +# Set from FLASHLAYOUT_TYPE_LABELS list +# FLASHLAYOUT_BOOTSCHEME_LABEL +# Set from FLASHLAYOUT_BOOTSCHEME_LABELS list (without any '_' in bootscheme labels) +# Note that both are appended only when FLASHLAYOUT_TYPE_LABELS and FLASHLAYOUT_BOOTSCHEME_LABELS contain more than two labels. +# FLASHLAYOUT_SUFFIX +# Default to 'tsv' +# +# File content structure: +# Opt Id Name Type IP Offset Binary +# +# +# +# +# +# +# +# +# Specific configuration: +# FLASHLAYOUT_PARTITION_SIZE +# If configured, it allows to compute the next offset to apply in +# flashlayout file for the following partition. +# Note that according to the device in use for the partition a specific +# alignment size can be specified through DEVICE_ALIGNMENT_SIZE_ +# var where is the current FLASHLAYOUT_PARTITION_DEVICE +# +# Note that override is manage for 'FLASHLAYOUT_PARTITION_LABELS' list with: +# - from FLASHLAYOUT_BOOTSCHEME_LABELS' list +# - from 'FLASHLAYOUT_CONFIG_LABELS' list +# Priority assignment is: +# It means the 'FLASHLAYOUT_PARTITION_LABELS' value can be overriden by setting: +# FLASHLAYOUT_PARTITION_LABELS__ +# FLASHLAYOUT_PARTITION_LABELS_ +# FLASHLAYOUT_PARTITION_LABELS_ +# FLASHLAYOUT_PARTITION_LABELS +# +# Another override mechanism is also implemented for all other partition variables: +# FLASHLAYOUT_PARTITION_ENABLE +# FLASHLAYOUT_PARTITION_ID +# FLASHLAYOUT_PARTITION_TYPE +# FLASHLAYOUT_PARTITION_DEVICE +# FLASHLAYOUT_PARTITION_OFFSET +# FLASHLAYOUT_PARTITION_BIN2LOAD +# We can override these variable with: +# - from 'FLASHLAYOUT_CONFIG_LABELS' list +# - from 'FLASHLAYOUT_BOOTSCHEME_LABELS' list +# - from 'FLASHLAYOUT_PARTITION_LABELS' list +# Priority assignment is: +# FLASHLAYOUT_PARTITION_xxx___ +# FLASHLAYOUT_PARTITION_xxx__ +# FLASHLAYOUT_PARTITION_xxx__ +# FLASHLAYOUT_PARTITION_xxx_ +# FLASHLAYOUT_PARTITION_xxx__ +# FLASHLAYOUT_PARTITION_xxx_ +# FLASHLAYOUT_PARTITION_xxx_ +# FLASHLAYOUT_PARTITION_xxx +# ----------------------------------------------------------------------------- + +ENABLE_FLASHLAYOUT_CONFIG ??= "1" + +FLASHLAYOUT_SUBDIR = "flashlayout_${PN}" +FLASHLAYOUT_DESTDIR = "${IMGDEPLOYDIR}/${FLASHLAYOUT_SUBDIR}" + +FLASHLAYOUT_BASENAME ??= "FlashLayout" +FLASHLAYOUT_SUFFIX ??= "tsv" + +FLASHLAYOUT_BOOTSCHEME_LABELS ??= "" + +ENABLE_FLASHLAYOUT_DEFAULT ??= "0" +FLASHLAYOUT_DEFAULT_SRC ??= "" + +# List all specific dependencies to image_complete task for successfull build +FLASHLAYOUT_DEPEND_TASKS ??= "" + +# List configuration files to monitor to trigger new flashlayout generation +FLASHLAYOUT_CONFIGURE_FILES ??= "" + +# ----------------------------------------------------------------------------- +# Make sure to add the flashlayout file creation after ROOTFS build +# So we should identify image ROOTFS build and only the ROOTFS (for now) +# As we know that PARTITIONS may be built as part of ROOTFS build, let's +# avoid amending the partition images +# ----------------------------------------------------------------------------- +python __anonymous () { + flashlayout_config = d.getVar('ENABLE_FLASHLAYOUT_CONFIG') + if flashlayout_config: + # Gather all current tasks + tasks = filter(lambda k: d.getVarFlag(k, "task", True), d.keys()) + for task in tasks: + # Check that we are dealing with image recipe + if task == 'do_image_complete': + # Init current image name + current_image_name = d.getVar('PN') or "" + # Init RAMFS image if any + initramfs = d.getVar('INITRAMFS_IMAGE') or "" + # Init INITRD image if any + initrd = d.getVar('INITRD_IMAGE') or "" + # Init partition list from PARTITIONS_IMAGE + image_partitions = (d.getVar('PARTITIONS_IMAGE') or "").split() + # We need to clearly identify ROOTFS build, not InitRAMFS one (if any) + if current_image_name not in image_partitions and current_image_name not in initramfs and current_image_name not in initrd: + # We need to make sure to add all extra dependencies as 'depends' + # for image_complete task + if d.getVar('FLASHLAYOUT_DEPEND_TASKS'): + d.appendVarFlag('do_image_complete', 'depends', ' %s' % (d.getVar('FLASHLAYOUT_DEPEND_TASKS',))) + # We can append the flashlayout file creation task to this ROOTFS build + d.appendVar('IMAGE_POSTPROCESS_COMMAND', 'do_create_flashlayout_config ; ') + # Append also the configuration files to properly take into account any updates + d.appendVarFlag('do_image_complete', 'file-checksums', ' ${FLASHLAYOUT_CONFIGURE_FILES} ') +} + +def expand_var(var, bootscheme, config, partition, d): + """ + Compute and return 'var': + 0) Prepend 'partition' to default OVERRIDES + 1) Look for any 'bootscheme_config' expansion for 'var': 'var_bootscheme_config' + 2) Look for any 'bootscheme' expansion for 'var': 'var_bootscheme' + 3) Look for any 'config' expansion for 'var': 'var_config' + 4) Then look for any 'var' override + 5) Default 'var' to 'none' if not defined + This is the priority order assignment for 'var' + """ + # Append 'partition' to OVERRIDES + localdata = bb.data.createCopy(d) + overrides = localdata.getVar('OVERRIDES') + if not overrides: + bb.fatal('OVERRIDES not defined') + localdata.setVar('OVERRIDES', partition + ':' + overrides) + # Compute var according to priority assignment order defined above + expanded_var = localdata.getVar('%s_%s_%s' % (var, bootscheme, config)) + if not expanded_var: + expanded_var = localdata.getVar('%s_%s' % (var, bootscheme)) + if not expanded_var: + expanded_var = localdata.getVar('%s_%s' % (var, config)) + if not expanded_var: + expanded_var = localdata.getVar(var) + if not expanded_var: + expanded_var = "none" + # Return expanded and/or overriden var value + return expanded_var + +def get_offset(new_offset, bootscheme, config, partition, d): + """ + This function return a couple of strings: offset, next_offset + The offset is the one to use in flashlayout file for the requested partition, + and next_offset is the one to use in flashlayout for next partition (if any). + + The offset can be directly configured for the current partition through the + FLASHLAYOUT_PARTITION_OFFSET variable. If this one is set to 'none' for the + current partition, then we use the one provided through 'new_offset'. + + The next_offset is computed by first getting the FLASHLAYOUT_PARTITION_SIZE for + the current partition, and we make sure to align properly the next_offset + according to the DEVICE_ALIGNMENT_SIZE_ where is feed from + FLASHLAYOUT_PARTITION_DEVICE. + """ + import re + + # Set offset + offset = expand_var('FLASHLAYOUT_PARTITION_OFFSET', bootscheme, config, partition, d) + bb.note('>>> Selected FLASHLAYOUT_PARTITION_OFFSET: %s' % offset) + if offset == 'none': + if new_offset == 'none': + bb.fatal('Missing %s partition offset configuration for %s label for %s bootscheme!' % (partition, config, bootscheme)) + offset = new_offset + bb.note('>>> New offset configured: %s' % offset) + + # Set next offset + partition_size = expand_var('FLASHLAYOUT_PARTITION_SIZE', bootscheme, config, partition, d) + bb.note('>>> Selected FLASHLAYOUT_PARTITION_SIZE: %s' % partition_size) + if not partition_size.isdigit(): + bb.note('No partition size provided for %s partition, %s label and %s bootscheme!' % (partition, config, bootscheme)) + next_offset = "none" + else: + if re.match('^0x.*$', offset): + current_device = expand_var('FLASHLAYOUT_PARTITION_DEVICE', bootscheme, config, partition, d) + bb.note('>>> Current device is %s' % current_device) + alignment_size = d.getVar('DEVICE_ALIGNMENT_SIZE_%s' % current_device) or "none" + if alignment_size == 'none': + bb.fatal('Missing DEVICE_ALIGNMENT_SIZE_%s value' % current_device) + if ( int(partition_size) * 1024 ) % int(alignment_size, 16) == 0: + bb.note('>>> The partition size properly follows %s erase size' % alignment_size) + else: + bb.note('>>> The %s alignment size is: %s' % (current_device, alignment_size)) + floor_coef = ( int(partition_size) * 1024 ) // int(alignment_size, 16) + compute_size = ( floor_coef + 1 ) * int(alignment_size, 16) + partition_size = str(compute_size // 1024) + bb.note('>>> New partition size configured to follow %s alignment size: %s' % (alignment_size, partition_size)) + # Compute new offset value + overall_size = int(offset, 16) + int(partition_size) * 1024 + next_offset = '0x{0:0{1}X}'.format(overall_size, 8) + else: + next_offset = "none" + bb.note('>>> New next_offset configured: %s' % next_offset) + + # Return both offset and next offset + return str(offset), str(next_offset) + + +def get_binaryname(labeltype, bootscheme, config, partition, d): + """ + Return proper binary name to use in flashlayout file by applying any specific + computation (replacement, etc) + Make sure also that binary is available on deploy folder + """ + import re + + # Init binary_name for current configuration + binary_name = expand_var('FLASHLAYOUT_PARTITION_BIN2LOAD', bootscheme, config, partition, d) + bb.note('>>> Selected FLASHLAYOUT_PARTITION_BIN2LOAD: %s' % binary_name) + + # Treat TF-A, TEE, U-BOOT and U-BOOT-SPL binary rename case + if re.match('^tf-a.*$', binary_name) or re.match('^u-boot.*$', binary_name) or re.match('^tee-.*$', binary_name): + file_name, file_ext = os.path.splitext(binary_name) + # Init binary_type to use from labeltype + binary_type = labeltype + '-' + bootscheme + bb.note('>>> Binary type used: %s' % binary_type) + # Check for any replace pattern + replace_patterns = expand_var('BIN2BOOT_REPLACE_PATTERNS', bootscheme, config, partition, d) + bb.note('>>> Substitution patterns: %s' % replace_patterns) + # Apply replacement patterns on binary_type + if replace_patterns != 'none': + for replace_pattern in replace_patterns.split(): + pattern2replace = replace_pattern.split(';')[0] + pattern2use = replace_pattern.split(';')[1] + # Replace with pattern middle of string + binary_type = re.sub(r'-%s-' % pattern2replace, '-' + pattern2use + '-', binary_type) + # Replace with pattern end of string + binary_type = re.sub(r'-%s$' % pattern2replace, '-' + pattern2use, binary_type) + bb.note('>>> New "binary_type" to use for binary name": %s' % binary_type) + # Append binary_type to binary name + if re.match('^u-boot-spl.*$', binary_name): + binary_name = file_name + file_ext + '-' + binary_type + else: + binary_name = file_name + '-' + binary_type + file_ext + + # Make sure binary is available in DEPLOY_DIR_IMAGE folder + if binary_name != 'none': + if not os.path.isfile(os.path.join(d.getVar('DEPLOY_DIR_IMAGE'), binary_name)): + # Specific exception for rootfs binary (not yet deployed) + if not os.path.isfile(os.path.join(d.getVar('IMGDEPLOYDIR'), binary_name)): + bb.fatal('Missing %s binary file in deploy folder' % binary_name) + # Return binary_name value + return binary_name + + +python do_create_flashlayout_config() { + import re + import shutil + + # We check first if it is requested to generate any flashlayout files + if d.getVar("ENABLE_FLASHLAYOUT_CONFIG") != "1": + bb.note('ENABLE_FLASHLAYOUT_CONFIG not enabled') + return + + # Create destination folder for flashlayout files + bb.utils.remove(d.getVar('FLASHLAYOUT_DESTDIR'), recurse=True) + bb.utils.mkdirhier(d.getVar('FLASHLAYOUT_DESTDIR')) + + # We check if user as define a static flashlayout file to use instead of dynamic generation + if d.getVar("ENABLE_FLASHLAYOUT_DEFAULT") == "1": + bb.note('ENABLE_FLASHLAYOUT_DEFAULT enabled') + flashlayout_src = d.getVar("FLASHLAYOUT_DEFAULT_SRC") + if not flashlayout_src: + bb.fatal("FLASHLAYOUT_DEFAULT_SRC not defined, please set a proper value") + if not flashlayout_src.strip(): + bb.fatal("No static flashlayout file configured, nothing to do") + for f in flashlayout_src.split(): + if os.path.isfile(f): + flashlayout_staticname=os.path.basename(f) + flashlayout_file = d.expand("${FLASHLAYOUT_DESTDIR}/%s" % flashlayout_staticname) + shutil.copy2(flashlayout_src, flashlayout_file) + bb.note('Copy %s to output file %s' % (f, flashlayout_file)) + return + else: + bb.fatal("Configure static file: %s is not pointing to an existing file" % f) + + # Set bootschemes for partition var override configuration + bootschemes = d.getVar('FLASHLAYOUT_BOOTSCHEME_LABELS') + if not bootschemes: + bb.fatal("FLASHLAYOUT_BOOTSCHEME_LABELS not defined, nothing to do") + if not bootschemes.strip(): + bb.fatal("No bootschemes, nothing to do") + # Make sure there is no '_' in FLASHLAYOUT_BOOTSCHEME_LABELS + for bootscheme in bootschemes.split(): + if re.match('.*_.*', bootscheme): + bb.fatal("Please remove all '_' for bootschemes defined in FLASHLAYOUT_BOOTSCHEME_LABELS") + bb.note('FLASHLAYOUT_BOOTSCHEME_LABELS: %s' % bootschemes) + + for bootscheme in bootschemes.split(): + bb.note('*** Loop for bootscheme label: %s' % bootscheme) + + # Get the different flashlayout config label + configs = expand_var('FLASHLAYOUT_CONFIG_LABELS', bootscheme, '', '', d) + # Make sure there is no '_' in FLASHLAYOUT_CONFIG_LABELS + for config in configs.split(): + if re.match('.*_.*', config): + bb.fatal("Please remove all '_' for configs defined in FLASHLAYOUT_CONFIG_LABELS") + bb.note('FLASHLAYOUT_CONFIG_LABELS: %s' % configs) + + for config in configs.split(): + bb.note('*** Loop for config label: %s' % config) + # Set labeltypes list + labeltypes = expand_var('FLASHLAYOUT_TYPE_LABELS', bootscheme, config, '', d) + bb.note('FLASHLAYOUT_TYPE_LABELS: %s' % labeltypes) + if labeltypes == 'none': + bb.note("FLASHLAYOUT_TYPE_LABELS is none, so no flashlayout file to generate.") + continue + for labeltype in labeltypes.split(): + bb.note('*** Loop for label type: %s' % labeltype) + # Init flashlayout file name + if config == 'none': + config_append = '' + else: + config_append = '_' + config + if len(labeltypes.split()) < 2 and len(bootschemes.split()) < 2: + labeltype_append = '' + else: + labeltype_append = '_' + labeltype + '-' + bootscheme + flashlayout_file = d.expand("${FLASHLAYOUT_DESTDIR}/${FLASHLAYOUT_BASENAME}%s%s.${FLASHLAYOUT_SUFFIX}" % (config_append, labeltype_append)) + # Get the partition list to write in flashlayout file + partitions = expand_var('FLASHLAYOUT_PARTITION_LABELS', bootscheme, config, '', d) + bb.note('FLASHLAYOUT_PARTITION_LABELS: %s' % partitions) + if partitions == 'none': + bb.note("FLASHLAYOUT_PARTITION_LABELS is none, so no flashlayout file to generate.") + continue + # Generate flashlayout file for labeltype + try: + with open(flashlayout_file, 'w') as fl_file: + # Write to flashlayout file the first line header + fl_file.write('#Opt\tId\tName\tType\tIP\tOffset\tBinary\n') + # Init partition next offset to 'none' + partition_nextoffset = "none" + for partition in partitions.split(): + bb.note('*** Loop for partition: %s' % partition) + # Init partition settings + partition_enable = expand_var('FLASHLAYOUT_PARTITION_ENABLE', bootscheme, config, partition, d) + partition_id = expand_var('FLASHLAYOUT_PARTITION_ID', bootscheme, config, partition, d) + partition_name = partition + partition_type = expand_var('FLASHLAYOUT_PARTITION_TYPE', bootscheme, config, partition, d) + partition_device = expand_var('FLASHLAYOUT_PARTITION_DEVICE', bootscheme, config, partition, d) + # Get partition offset + partition_offset, partition_nextoffset = get_offset(partition_nextoffset, bootscheme, config, partition, d) + # Get binary name + partition_bin2load = get_binaryname(labeltype, bootscheme, config, partition, d) + # Be verbose in log file + bb.note('>>> Layout inputs: %s' % fl_file.name) + bb.note('>>> FLASHLAYOUT_PARTITION_ENABLE: %s' % partition_enable) + bb.note('>>> FLASHLAYOUT_PARTITION_ID: %s' % partition_id) + bb.note('>>> FLASHLAYOUT_PARTITION_LABEL: %s' % partition_name) + bb.note('>>> FLASHLAYOUT_PARTITION_TYPE: %s' % partition_type) + bb.note('>>> FLASHLAYOUT_PARTITION_DEVICE: %s' % partition_device) + bb.note('>>> FLASHLAYOUT_PARTITION_OFFSET: %s' % partition_offset) + bb.note('>>> FLASHLAYOUT_PARTITION_BIN2LOAD: %s' % partition_bin2load) + bb.note('>>> done') + # Write to flashlayout file the partition configuration + fl_file.write('%s\t%s\t%s\t%s\t%s\t%s\t%s\n' % + (partition_enable, partition_id, partition_name, partition_type, partition_device, partition_offset, partition_bin2load)) + except OSError: + bb.fatal('Unable to open %s' % (fl_file)) +} diff --git a/classes/image_types-stubi.bbclass b/classes/image_types-stubi.bbclass new file mode 100644 index 0000000..3eb1548 --- /dev/null +++ b/classes/image_types-stubi.bbclass @@ -0,0 +1,131 @@ +inherit image_types + +do_image_stmultiubi[depends] += "mtd-utils-native:do_populate_sysroot" + +python stmultiub_environment () { + if d.getVar('MULTIUBI_BUILD'): + try: + f =open( ("%s/stmultiubi_environment" % d.getVar('T')), 'w') + for build in d.getVar('MULTIUBI_BUILD').split(): + f.write( "export MKUBIFS_ARGS_%s=\"%s\"\n" % (build, d.getVar(('MKUBIFS_ARGS_' + build))) ) + f.write( "export UBINIZE_ARGS_%s=\"%s\"\n" % (build, d.getVar(('UBINIZE_ARGS_' + build))) ) + f.close() + except: + pass +} + +IMAGE_PREPROCESS_COMMAND += "stmultiub_environment;" + +IMAGE_CMD_stmultiubi () { + . ${T}/stmultiubi_environment + + # Split MKUBIFS_ARGS_ and UBINIZE_ARGS_ + for name in ${MULTIUBI_BUILD}; do + eval local mkubifs_args=\"\$MKUBIFS_ARGS_${name}\" + eval local ubinize_args=\"\$UBINIZE_ARGS_${name}\" + multiubi_mkfs "${mkubifs_args}" "${ubinize_args}" "${name}" + + cd ${IMGDEPLOYDIR} + if [ -e ubinize_${name}-${IMAGE_NAME}.cfg ]; then + # Set correct name for cfg file to allow automatic cleanup + mv ubinize_${name}-${IMAGE_NAME}.cfg ${IMAGE_NAME}_${name}.ubinize.cfg.ubi + # Create symlinks + ln -sf ${IMAGE_NAME}_${name}.ubinize.cfg.ubi ${IMAGE_LINK_NAME}_${name}.ubinize.cfg.ubi + fi + cd - + done +} + +ENABLE_MULTIVOLUME_UBI ?= "1" + +st_multivolume_ubifs() { + # This function depends on IMAGE_FSTYPES 'stmultiubi' + if [ "${@bb.utils.contains('IMAGE_FSTYPES', 'stmultiubi', '1', '0', d)}" != "1" ]; then + return + fi + + if [ "${ENABLE_MULTIVOLUME_UBI}" != "1" ]; then + return + fi + + # ----------------------------------------------------------------------------- + # Define the list of volumes for the multi UBIFS with 'STM32MP_UBI_VOLUME' var. + # The format to follow is: + # STM32MP_UBI_VOLUME = ": :" + # Note that: + # - 'VOL_NAME' should follow 'IMAGE_LINK_NAME' format + # - 'VOL_SIZE' is set in KiB + # ----------------------------------------------------------------------------- + + # We check that user as explicitly provided multi volume UBIFS var + # and that partition images are also provided + if [ -n "${STM32MP_UBI_VOLUME}" ] && [ -n "${PARTITIONS_IMAGE}" ]; then + + # We should only generate multi volume UBIFS for rootfs image and not + # any of the partition image one + for partition in ${PARTITIONS_IMAGE}; do + [ "${partition}-${DISTRO}-${MACHINE}" = "${IMAGE_LINK_NAME}" ] && return + done + + . ${T}/stmultiubi_environment + + for name in ${MULTIUBI_BUILD}; do + # Init var to populate 'vol_id' incrementally + volume_id=0 + for ubivolume in ${STM32MP_UBI_VOLUME}; do + # Init UBI volume information + if [ -z "$(echo ${ubivolume} | grep ':')" ]; then + bbfatal "Missing ':' separator between UBI volume name and UBI volume size '${ubivolume}'" + fi + volume_name=$(echo ${ubivolume} | cut -d':' -f1) + volume_size=$(echo ${ubivolume} | cut -d':' -f2) + # Set ubinize config file for current volume + if [ -e ${IMGDEPLOYDIR}/${volume_name}_${name}.ubinize.cfg.ubi ]; then + ubinize_cfg=${IMGDEPLOYDIR}/${volume_name}_${name}.ubinize.cfg.ubi + elif [ -e ${DEPLOY_DIR_IMAGE}/${volume_name}_${name}.ubinize.cfg.ubi ]; then + ubinize_cfg=${DEPLOY_DIR_IMAGE}/${volume_name}_${name}.ubinize.cfg.ubi + else + bbfatal "Can't find any '${name}' ubinize config file for ${volume_name} in ${IMGDEPLOYDIR} or ${DEPLOY_DIR_IMAGE} folders" + fi + # Create temporary copy of ubinize config file for update + cp ${ubinize_cfg} ${WORKDIR}/ + # Update ubifs path in cfg file with DEPLOY_DIR_IMAGE to avoid issue with RM_WORK feature + if [ -e ${DEPLOY_DIR_IMAGE}/${volume_name}_${name}.ubinize.cfg.ubi ]; then + sed 's|^image=.*/\('"${volume_name}"'.*\.ubifs\)$|image='"${DEPLOY_DIR_IMAGE}"'/\1|' -i ${WORKDIR}/$(basename ${ubinize_cfg}) + fi + # Update generic name in cfg file + sed 's|\[ubifs\]|\['"${volume_name}"'\]|' -i ${WORKDIR}/$(basename ${ubinize_cfg}) + # Update volume id in cfg file + sed 's|vol_id=0|vol_id='"${volume_id}"'|' -i ${WORKDIR}/$(basename ${ubinize_cfg}) + volume_id=$(expr ${volume_id} + 1) + # Replace 'vol_flags' entry with 'vol_size' one in cfg file + sed 's|vol_flags=.*|vol_size='"${volume_size}KiB"'|' -i ${WORKDIR}/$(basename ${ubinize_cfg}) + # Append ubinize config file to multivolume one + cat ${WORKDIR}/$(basename ${ubinize_cfg}) >> ${IMGDEPLOYDIR}/${IMAGE_NAME}_${name}_multivolume.ubinize.cfg.ubi + # Clean temporary file + rm -f ${WORKDIR}/$(basename ${ubinize_cfg}) + done + # Add 'vol_flags' entry in ubinize multivolume config file + echo "vol_flags=autoresize" >> ${IMGDEPLOYDIR}/${IMAGE_NAME}_${name}_multivolume.ubinize.cfg.ubi + + # Generate multivolume UBI + eval local ubinize_args=\"\$UBINIZE_ARGS_${name}\" + ubinize -o ${IMGDEPLOYDIR}/${IMAGE_NAME}_${name}_multivolume${IMAGE_NAME_SUFFIX}.ubi ${ubinize_args} ${IMGDEPLOYDIR}/${IMAGE_NAME}_${name}_multivolume.ubinize.cfg.ubi + + # Create own symlinks for 'named' volumes + cd ${IMGDEPLOYDIR} + if [ -e ${IMAGE_NAME}_${name}_multivolume${IMAGE_NAME_SUFFIX}.ubi ]; then + ln -sf ${IMAGE_NAME}_${name}_multivolume${IMAGE_NAME_SUFFIX}.ubi ${IMAGE_LINK_NAME}_${name}_multivolume.ubi + ln -sf ${IMAGE_NAME}_${name}_multivolume.ubinize.cfg.ubi ${IMAGE_LINK_NAME}_${name}_multivolume.ubinize.cfg.ubi + fi + cd - + + # Cleanup also DEPLOY_DIR_IMAGE from any other ubi artifacts + # This avoid duplicating data in DEPLOY_DIR_IMAGE + rm -f ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}-*_${name}_multivolume${IMAGE_NAME_SUFFIX}.ubi + rm -f ${DEPLOY_DIR_IMAGE}/${IMAGE_LINK_NAME}-*_${name}_multivolume.ubinize.cfg.ubi + done + fi +} + +IMAGE_POSTPROCESS_COMMAND += " st_multivolume_ubifs ;" diff --git a/classes/st-partitions-image.bbclass b/classes/st-partitions-image.bbclass new file mode 100755 index 0000000..0b93ff4 --- /dev/null +++ b/classes/st-partitions-image.bbclass @@ -0,0 +1,56 @@ +# Appends partition images generation to image build +# +# The format to specify it, in the machine, is: +# +# PARTITIONS_IMAGE ??= "partition_image_name_1 partition_image_name_2" +# +# The partition generation might be disabled by resetting ENABLE_PARTITIONS_IMAGE var +# in an image recipe (for example) +# + +ENABLE_PARTITIONS_IMAGE ?= "1" +PARTITIONS_IMAGE ?= "" + +python __anonymous () { + if d.getVar('ENABLE_PARTITIONS_IMAGE') != "1": + return + + # Init partition list from PARTITIONS_IMAGE + image_partitions = (d.getVar('PARTITIONS_IMAGE') or "").split() + + if len(image_partitions) > 0: + # Gather all current tasks + tasks = filter(lambda k: d.getVarFlag(k, "task", True), d.keys()) + for task in tasks: + # Check that we are dealing with image recipe + if task == 'do_image_complete': + # Init current image name + current_image_name = d.getVar('PN') or "" + # Init RAMFS image if any + initramfs = d.getVar('INITRAMFS_IMAGE') or "" + + # We need to append partition images generation only to image + # that are not one of the defined partitions and not the InitRAMFS image. + # Without this check we would create circular dependency + if current_image_name not in image_partitions and current_image_name not in initramfs: + for partition in image_partitions: + d.appendVarFlag('do_image_complete', 'depends', ' %s:do_image_complete' % partition) +} + +image_rootfs_image_clean_task () { + for name in ${PARTITIONS_IMAGE}; + do + if `echo ${IMAGE_NAME} | grep -q $name` ; + then + return; + fi + done + bbnote "Clean mount point on ${IMAGE_NAME}:" + LIST=`ls -l ${IMAGE_ROOTFS}` + for dir in ${PARTITIONS_MOUNTPOINT_IMAGE}; + do + bbnote "$dir on ${IMAGE_NAME} are cleanned because it's a mount point." + rm -rf ${IMAGE_ROOTFS}/$dir/* + done +} +IMAGE_PREPROCESS_COMMAND_append = " image_rootfs_image_clean_task; "