diff --git a/config/bootscripts/boot-generic.cmd.template b/config/bootscripts/boot-generic.cmd.template new file mode 100644 index 0000000000..6c7dc181a8 --- /dev/null +++ b/config/bootscripts/boot-generic.cmd.template @@ -0,0 +1,537 @@ +# DO NOT EDIT THIS FILE +# +# Please edit /boot/armbianEnv.txt to set supported parameters +# + +# This bootscript was generated on ${BOOTSCRIPT_TEMPLATE__CREATE_DATE} + +# NOTE +# This file is the result of rendering a template using 'envsubst'. +# Any variable starting with 'BOOTSCRIPT_TEMPLATE__' is expected to be rendered. +# The build system will check if any variable is left after rendering and will +# exit with error if any unrendered variables are found. +# Check the following files for more details: +# lib/functions/bsp/armbian-bsp-cli-deb.sh +# lib/functions/rootfs/distro-agnostic.sh + +# NOTE +# If you intend to use 'outside' of 'global' variables from U-Boot, make sure that you do not change them! +# The boot logic will attempt a list of 'boot_targets' that all might rely on (environment) variables that +# have been set by U-Boot, either compile-time or as part of U-Boot's default 'bootcmd'. +# Any variable that this bootscript uses needs to be set explicitly and not conflict with any pre-set variables. +# Variables that we might change will be saved in preset_x and variables we use will be copied into l_x. + +# default environment variables +setenv align_overlap_oboe_avoidance "on" +setenv align_to "${BOOTSCRIPT_TEMPLATE__ALIGN_TO}" +setenv consoleargs_display "${BOOTSCRIPT_TEMPLATE__DISPLAY_CONSOLE}" +setenv consoleargs_serial "${BOOTSCRIPT_TEMPLATE__SERIAL_CONSOLE}" +setenv console "both" +setenv docker_optimizations "on" +setenv earlycon "off" +setenv exit_on_critical_errors "on" +setenv family "${BOOTSCRIPT_TEMPLATE__BOARD_FAMILY}" +setenv fdt_extrasize "0x00010000" +setenv kver +setenv load_addr_calc +setenv overlay_error "false" +setenv preset_fdtdir "${fdtdir}" +setenv preset_fdtfile "${fdtfile}" +setenv preset_kernel_comp_addr_r "${kernel_comp_addr_r}" +setenv preset_kernel_comp_size "${kernel_comp_size}" +setenv rootdev "/dev/mmcblk${devnum}p${distro_bootpart}" +setenv rootfstype "${BOOTSCRIPT_TEMPLATE__ROOTFS_TYPE}" +setenv vendor "${BOOTSCRIPT_TEMPLATE__BOARD_VENDOR}" +setenv verbosity "1" + +# load addresses +setenv load_addr "${BOOTSCRIPT_TEMPLATE__LOAD_ADDR}" + +# NOTE +# No 'BOOTSCRIPT_TEMPLATE__' references beyond this point. + +# environment run variables +setenv func_align_addr_next ' + test "${align_overlap_oboe_avoidance}" = "on" && setexpr l_addr_next ${l_addr_next} + 1 ; + setexpr l_modulo ${l_addr_next} % ${align_to} ; + if itest ${l_modulo} -gt 0 ; then + setexpr l_addr_next ${l_addr_next} / ${align_to} ; + setexpr l_addr_next ${l_addr_next} + 1 ; + setexpr l_addr_next ${l_addr_next} * ${align_to} ; + fi' +setenv func_inform 'test "${verbosity}" = "" || itest ${verbosity} -gt 0 && echo "${l_message}"' +setenv func_warn 'echo "** WARNING: ${l_message}"' +setenv func_critical_error ' + echo "!! CRITICAL: ${l_message}" ; + if test "${exit_on_critical_errors}" = "on" ; then + false ; + else + true ; + fi' + +# set some defaults in case there are no pre-sets +if test "${envfile}" = "" ; then + setenv l_envfile 'armbianEnv.txt' +else + setenv l_envfile "${envfile}" +fi + +echo "Boot script loaded from ${devtype} ${devnum}:${distro_bootpart}." + +# load (merge) on-disk environment +setenv l_file "${prefix}${l_envfile}" +if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${l_file} ; then + if env import -t ${load_addr} ${filesize} ; then + setenv l_message "Loaded/imported environment ${l_file} to/from ${load_addr}." + run func_inform + else + setenv l_message "Could not import environment ${l_file} - using default environment!" + run func_warn + fi + else + setenv l_message "Could not load environment ${l_file} - using default environment!" + run func_warn + fi +fi + +# compose kernel commandline options (bootargs) +setenv consoleargs +if test "${console}" = "display" || test "${console}" = "both" ; then + if test -n "${consoleargs_display}" ; then + setenv consoleargs "${consoleargs_display} ${consoleargs}" + fi +fi +if test "${console}" = "serial" || test "${console}" = "both" ; then + if test -n "${consoleargs_serial}" ; then + setenv consoleargs "${consoleargs_serial} ${consoleargs}" + fi +fi +if test "${earlycon}" = "on" ; then + setenv consoleargs "earlycon ${consoleargs}" +fi +if test "${bootlogo}" = "true" ; then + setenv consoleargs "splash plymouth.ignore-serial-consoles ${consoleargs}" +else + setenv consoleargs "splash=verbose ${consoleargs}" +fi + +part uuid ${devtype} ${devnum}:${distro_bootpart} l_ubootpart + +setenv bootargs "root=${rootdev} rootfstype=${rootfstype} rootwait ${consoleargs} consoleblank=0 loglevel=${verbosity} ubootpart=${l_ubootpart} usb-storage.quirks=${usbstoragequirks} ${extraargs} ${extraboardargs}" + +if test "${docker_optimizations}" = "on" ; then + setenv bootargs "${bootargs} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory" +fi + +if test "${vendor}" = "allwinner" ; then + if test "${disp_mem_reserves}" = "off" ; then + setenv bootargs "${bootargs} sunxi_ve_mem_reserve=0 sunxi_g2d_mem_reserve=0 sunxi_fb_mem_reserve=16" + fi +fi +if test "${vendor}" = "marvell" ; then + # +fi +if test "${vendor}" = "rockchip" ; then + # +fi + +if test "${load_addr_calc}" = "" ; then + if setexpr load_addr_calc 1 + 1 ; then + setenv load_addr_calc 'on' + else + setenv load_addr_calc 'off' + fi +fi +if test "${load_addr_calc}" != "on" ; then + setenv load_addr_calc 'off' + + setenv l_message "Using fixed load addresses." + run func_inform + setenv l_message " fdt_addr_r: ${fdt_addr_r}" + run func_inform + setenv l_message " kernel_addr_r: ${kernel_addr_r}" + run func_inform + setenv l_message " ramdisk_addr_r: ${ramdisk_addr_r}" + run func_inform +fi + +if test "${kver}" != "" ; then + setenv l_message "Using version override ${kver} for image loading." + run func_inform +fi + +# set a default kernel image type in case 'setexpr' not available +if test "${cpu}" = "armv8" ; then + # aarch64 uses a flat kernel image + setenv l_kernel_image_type "flat" + setenv l_bootfile "Image${kver}" +else + if test "${cpu}" = "armv7" ; then + # aarch32 mostly uses compressed kernel image + setenv l_kernel_image_type "compressed" + setenv l_bootfile "zImage${kver}" + else + # per default use compressed kernel image + setenv l_kernel_image_type "compressed" + setenv l_bootfile "zImage${kver}" + fi +fi + +setenv l_ramdiskfile "uInitrd${kver}" + +# $fdtdir: +# some boards use "${prefix}dtb/" others use "${prefix}dtb/${vendor}/" as base location for the DT files +# user can also override by specifying an fdtdir=... in armbianEnv.txt +# try any U-Boot built-in (or pre-set) fdtdir as last resort +# $fdtfile: +# some boards use a "filename.dts" others use "${vendor}/filename.dts" +# user can also override by specifying an fdtfile=... in armbianEnv.txt +# strip any leading path components and try any U-Boot built-in (or pre-set) fdtfile as last resort + +setenv l_fdtfile_basename +setexpr l_fdtfile_basename sub ".*/" "" "${fdtfile}" +if test "${l_fdtfile_basename}" = "" ; then + setenv l_fdtfile_basename "${fdtfile}" +fi + +setenv l_fdtdir "${fdtdir}" +setenv l_fdtfile "${l_fdtfile_basename}" +if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true +else + setenv l_fdtdir "${prefix}dtb${kver}/${vendor}" + setenv l_fdtfile "${l_fdtfile_basename}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + setenv l_fdtdir "${prefix}dtb${kver}" + setenv l_fdtfile "${l_fdtfile_basename}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + setenv l_fdtdir "${fdtdir}" + setenv l_fdtfile "${fdtfile}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + setenv l_fdtdir "${preset_fdtdir}" + setenv l_fdtfile "${preset_fdtfile}" + if test -e ${devtype} ${devnum}:${distro_bootpart} "${l_fdtdir}/${l_fdtfile}" ; then + true + else + false + fi + fi + fi + fi +fi +if itest $? -ne 0 ; then + setenv l_message "Cannot find DT!" + run func_critical_error || exit +fi + +# load the device tree blob +setenv l_file "${l_fdtdir}/${l_fdtfile}" +if load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${l_file} ; then + setenv l_message "Loaded DT ${l_file} to ${fdt_addr_r}." + run func_inform + + setenv l_fdt_filesize ${filesize} + fdt addr ${fdt_addr_r} + fdt resize ${fdt_extrasize} +else + setenv l_message "Could not load DT ${l_file}!" + run func_critical_error || exit +fi + +# process "overlays=..." from $l_envfile +if test "${overlays}" != "" ; then + setenv l_message "Loading kernel provided DT overlay(s) from ${l_fdtdir}/overlay to ${load_addr} .." + run func_inform + + # as some families offer overlays with different (or no) prefixes, try to guess the most commonly seen ones + # just changing overlay_prefix= will not work for all available overlays, as some have prefixes and some do not + + setenv each_overlay + for each_overlay in ${overlays} ; do + setenv l_overlay_prefix "${overlay_prefix}" + setenv l_file "${l_fdtdir}/overlay/${l_overlay_prefix}-${each_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + true + else + setenv l_overlay_prefix "${vendor}" + setenv l_file "${l_fdtdir}/overlay/${l_overlay_prefix}-${each_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + setenv l_message "Found DT overlay ${l_overlay_prefix}-${each_overlay} instead of ${overlay_prefix}-${each_overlay} in ${l_fdtdir}/overlay!" + run func_warn + setenv l_message "Consider setting overlay_prefix=${l_overlay_prefix} in your ${l_envfile}." + run func_inform + true + else + setenv l_overlay_prefix "${vendor}-${soc}" + setenv l_file "${l_fdtdir}/overlay/${l_overlay_prefix}-${each_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + setenv l_message "Found DT overlay ${l_overlay_prefix}-${each_overlay} instead of ${overlay_prefix}-${each_overlay} in ${l_fdtdir}/overlay!" + run func_warn + setenv l_message "Consider setting overlay_prefix=${l_overlay_prefix} in your ${l_envfile}." + run func_inform + true + else + false + fi + fi + fi + if itest $? -eq 0 ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${l_file} ; then + if fdt apply ${load_addr} ; then + setenv l_message "Applied DT overlay ${each_overlay} (${l_file})." + run func_inform + else + setenv overlay_error "true" + setenv l_message "Could NOT apply DT overlay ${each_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT load DT overlay ${each_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT find DT overlay ${each_overlay}!" + run func_warn + fi + done +fi + +# process "user_overlays=..." from $l_envfile +if test "${user_overlays}" != "" ; then + setenv l_message "Loading user provided DT overlay(s) from ${prefix}overlay-user to ${load_addr} .." + run func_inform + + setenv each_user_overlay + for each_user_overlay in ${user_overlays} ; do + setenv l_file "${prefix}overlay-user/${each_user_overlay}.dtbo" + if test -e ${devtype} ${devnum}:${distro_bootpart} ${l_file} ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${l_file} ; then + if fdt apply ${load_addr} ; then + setenv l_message "Applied user DT overlay ${each_user_overlay} (${l_file})." + run func_inform + else + setenv overlay_error "true" + setenv l_message "Could NOT apply user DT overlay ${each_user_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT load user DT overlay ${each_user_overlay} (${l_file})!" + run func_warn + fi + else + setenv l_message "Could NOT find user DT overlay ${each_user_overlay} (${l_file})!" + run func_warn + fi + done +fi +if test "${overlay_error}" = "true" ; then + setenv l_message "Could not apply DT overlays!" + run func_warn + + setenv l_file "${l_fdtdir}/${l_fdtfile}" + if load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${l_file} ; then + setenv l_message "Loaded original DT ${l_file} to ${fdt_addr_r}." + run func_inform + + setenv l_fdt_filesize ${filesize} + fdt addr ${fdt_addr_r} + fdt resize ${fdt_extrasize} + else + setenv l_message "Could not load original DT ${l_file}!" + run func_critical_error || exit + fi +else + # process any available DT fixup scripts + setenv l_fixup_scripts "${prefix}fixup.scr" + if test "${overlay_prefix}" != "" ; then + setenv l_fixup_scripts "${l_fdtdir}/overlay/${overlay_prefix}-fixup.scr ${l_fixup_scripts}" + fi + if test "${vendor}" != "" ; then + if test "${vendor}" != "${overlay_prefix}" ; then + setenv l_fixup_scripts "${l_fdtdir}/overlay/${vendor}-fixup.scr ${l_fixup_scripts}" + fi + fi + + setenv each_fixup_script + for each_fixup_script in ${l_fixup_scripts} ; do + if test -e ${devtype} ${devnum}:${distro_bootpart} ${each_fixup_script} ; then + if load ${devtype} ${devnum}:${distro_bootpart} ${load_addr} ${each_fixup_script} ; then + if source ${load_addr} ; then + setenv l_message "Loaded/sourced fixup script ${each_fixup_script} to/at ${load_addr}." + run func_inform + else + setenv l_message "Fixup script ${each_fixup_script} returned an error!" + run func_warn + fi + else + setenv l_message "Could not load fixup script ${each_fixup_script}!" + run func_warn + fi + fi + done +fi + +# resize (trim) device tree after all overlays have been applied and fixup scripts have been run +fdt resize + + +# determine the load address for the kernel image +if test "${load_addr_calc}" = "on" ; then + # get the total size of the DT + setenv l_fdt_totalsize + fdt header get l_fdt_totalsize totalsize + + if test "${l_fdt_totalsize}" = "" ; then + # could not get the total size of the DT so calculate it instead + setenv l_message "Calculating DT size." + run func_inform + + # 'fdt resize' will align upwards to 4k address boundary + setexpr l_fdt_totalsize ${l_fdt_filesize} / 0x1000 + setexpr l_fdt_totalsize ${l_fdt_totalsize} + 1 + setexpr l_fdt_totalsize ${l_fdt_totalsize} * 0x1000 + if test "${fdt_extrasize}" != "" ; then + setexpr l_fdt_totalsize ${l_fdt_totalsize} + ${fdt_extrasize} + fi + fi + + setexpr l_addr_next ${fdt_addr_r} + ${l_fdt_totalsize} + run func_align_addr_next + + setenv l_kernel_addr_r ${l_addr_next} +else + setenv l_kernel_addr_r ${kernel_addr_r} +fi + +setenv l_file "${prefix}${l_bootfile}" +if load ${devtype} ${devnum}:${distro_bootpart} ${l_kernel_addr_r} ${l_file} ; then + if test "${load_addr_calc}" = "on" ; then + setenv kernel_comp_size ${filesize} + fi + + setenv l_message "Loaded ${l_kernel_image_type} kernel image ${l_file} to ${l_kernel_addr_r}." + run func_inform +else + if test "${load_addr_calc}" = "on" ; then + setenv kernel_comp_addr_r "${preset_kernel_comp_addr_r}" + setenv kernel_comp_size "${preset_kernel_comp_size}" + fi + setenv l_message "Could not load ${l_kernel_image_type} kernel image ${l_file}!" + run func_critical_error || exit +fi + +# determine the load address for the initial ramdisk +if test "${load_addr_calc}" = "on" ; then + # vmlinux image + 0x38 contain magic (le-double) 'ARMd' + setexpr l_ptr ${l_kernel_addr_r} + 0x00000038 + setexpr.w l_magic_lsw *${l_ptr} + + setexpr l_ptr ${l_kernel_addr_r} + 0x0000003a + setexpr.w l_magic_msw *${l_ptr} + + if test "${l_magic_msw}${l_magic_lsw}" != "" && itest "${l_magic_msw}${l_magic_lsw}" -eq 0x644d5241 ; then + setenv l_kernel_image_type "flat" + else + setenv l_kernel_image_type "compressed" + fi + + if test "${l_kernel_image_type}" = "flat" ; then + # vmlinux image + 0x10 contains image_size + setexpr l_ptr ${l_kernel_addr_r} + 0x00000010 + setexpr.l l_image_size *${l_ptr} + + setenv l_message "Using ${l_kernel_image_type} kernel image image_size 0x${l_image_size} bytes to calculate initial ramdisk load address." + run func_inform + + # vmlinux image + 0x08 contains text_offset + setexpr l_ptr ${l_kernel_addr_r} + 0x00000008 + setexpr.l l_text_offset *${l_ptr} + + setenv l_message "Using ${l_kernel_image_type} kernel image text_offset 0x${l_text_offset} bytes to offset initial ramdisk load address." + run func_inform + + setexpr l_addr_next ${l_kernel_addr_r} + ${l_image_size} + run func_align_addr_next + + # take into account that U-Boot's booti_setup() might relocate the kernel image + setexpr l_addr_next ${l_addr_next} + ${l_text_offset} + else + setexpr l_addr_next ${l_kernel_addr_r} + ${filesize} + run func_align_addr_next + + setenv l_message "Using ${l_kernel_image_type} kernel image filesize 0x${filesize} bytes to calculate initial ramdisk load address." + run func_inform + fi + + setenv l_ramdisk_addr_r ${l_addr_next} +else + setenv l_ramdisk_addr_r ${ramdisk_addr_r} +fi + +setenv l_file "${prefix}${l_ramdiskfile}" +if load ${devtype} ${devnum}:${distro_bootpart} ${l_ramdisk_addr_r} ${l_file} ; then + if test "${load_addr_calc}" = "on" ; then + setexpr l_addr_next ${l_ramdisk_addr_r} + ${filesize} + run func_align_addr_next + + setenv kernel_comp_addr_r ${l_addr_next} + fi + + setenv l_message "Loaded initial ramdisk ${l_file} to ${l_ramdisk_addr_r}." + run func_inform +else + if test "${load_addr_calc}" = "on" ; then + setenv kernel_comp_addr_r "${preset_kernel_comp_addr_r}" + setenv kernel_comp_size "${preset_kernel_comp_size}" + fi + setenv l_message "Could not load initial ramdisk ${l_file}!" + run func_critical_error || exit +fi + +# attempt to prepare for kernel address space randomization +if kaslrseed ; then +else + setenv l_message "Not able to prepare for KASLR." + run func_inform +fi + +setenv l_message "Kernel commandline arguments:" +run func_inform + +setenv each_bootarg +for each_bootarg in ${bootargs} ; do + setenv l_message " ${each_bootarg}" + run func_inform +done + +if test "${l_kernel_image_type}" = "flat" ; then + booti ${l_kernel_addr_r} ${l_ramdisk_addr_r} ${fdt_addr_r} +else + if test "${l_kernel_image_type}" = "compressed" ; then + bootz ${l_kernel_addr_r} ${l_ramdisk_addr_r} ${fdt_addr_r} + else + # default booting command + bootz ${l_kernel_addr_r} ${l_ramdisk_addr_r} ${fdt_addr_r} + fi +fi + +# booting failed, restore environment variables that are not unique +# to this bootmeth +if test "${load_addr_calc}" = "on" ; then + # restore original presets + setenv kernel_comp_addr_r "${preset_kernel_comp_addr_r}" + setenv kernel_comp_size "${preset_kernel_comp_size}" +fi + +setenv l_message "Could not boot kernel!" +run func_critical_error || exit + +# Recompile with: +# mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr diff --git a/lib/functions/bsp/armbian-bsp-cli-deb.sh b/lib/functions/bsp/armbian-bsp-cli-deb.sh index 6682dcd8e3..b24d1bf48f 100644 --- a/lib/functions/bsp/armbian-bsp-cli-deb.sh +++ b/lib/functions/bsp/armbian-bsp-cli-deb.sh @@ -141,7 +141,22 @@ function compile_armbian-bsp-cli() { EOF # Using bootscript, copy it to /usr/share/armbian - run_host_command_logged cp -pv "${bootscript_info[bootscript_file_fullpath]}" "${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}" + + case "${bootscript_info[bootscript_src]}" in + *'.template') + display_alert "Rendering boot script template" "${bootscript_info[bootscript_file_fullpath]} -> ${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}" "info" + run_host_command_logged cat "${bootscript_info[bootscript_file_fullpath]}" | + render_bootscript_template > "${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}" + + if ! proof_rendered_bootscript_template "${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}" ; then + exit_with_error "Render of bootscript template was not successful. Inspect '${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}' for unrendered variables." + fi + ;; + *) + display_alert "Deploying boot script" "${bootscript_info[bootscript_file_fullpath]} -> ${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}" "info" + run_host_command_logged cp -pv "${bootscript_info[bootscript_file_fullpath]}" "${destination}/usr/share/armbian/${bootscript_info[bootscript_dst]}" + ;; + esac if [[ "${bootscript_info[has_bootenv]}" == "yes" ]]; then run_host_command_logged cp -pv "${bootscript_info[bootenv_file_fullpath]}" "${destination}"/usr/share/armbian/armbianEnv.txt diff --git a/lib/functions/host/prepare-host.sh b/lib/functions/host/prepare-host.sh index 3c3a351620..ab8efaa89a 100644 --- a/lib/functions/host/prepare-host.sh +++ b/lib/functions/host/prepare-host.sh @@ -187,7 +187,7 @@ function adaptative_prepare_host_dependencies() { dwarves # dwarves has been replaced by "pahole" and is now a transitional package e2fsprogs flex - gawk gnupg gpg + gawk gettext gnupg gpg imagemagick # required for plymouth: converting images / spinners jq # required for parsing JSON, specially rootfs-caching related. kmod # this causes initramfs rebuild, but is usually pre-installed, so no harm done unless it's an upgrade diff --git a/lib/functions/rootfs/distro-agnostic.sh b/lib/functions/rootfs/distro-agnostic.sh index 9b47e10f65..3ce2de462a 100644 --- a/lib/functions/rootfs/distro-agnostic.sh +++ b/lib/functions/rootfs/distro-agnostic.sh @@ -7,6 +7,72 @@ # This file is a part of the Armbian Build Framework # https://github.com/armbian/build/ +function bootscript_export_display_console() { + unset BOOTSCRIPT_TEMPLATE__DISPLAY_CONSOLE + typeset ITEM + typeset CONSOLEARGS + + for ITEM in ${DISPLAYCON//,/ } ; do + CONSOLEARGS="${CONSOLEARGS:-}${CONSOLEARGS:+ }console=${ITEM//:/,}" + done + + for ITEM in $SRC_CMDLINE ; do + if [[ ! 'console' == "${ITEM%%=*}" ]] ; then + continue + fi + if [[ "${ITEM#*=}" =~ 'tty'[AGSU]* ]] ; then + continue + fi + CONSOLEARGS="${CONSOLEARGS:-}${CONSOLEARGS:+ }${ITEM:?}" + done + CONSOLEARGS="$(echo "${CONSOLEARGS:-}" | xargs -n1 | sort -u | xargs)" + + export BOOTSCRIPT_TEMPLATE__DISPLAY_CONSOLE="${CONSOLEARGS:-}" +} + +function bootscript_export_serial_console() { + unset BOOTSCRIPT_TEMPLATE__SERIAL_CONSOLE + typeset ITEM + typeset CONSOLEARGS + + for ITEM in ${SERIALCON//,/ } ; do + CONSOLEARGS="${CONSOLEARGS:-}${CONSOLEARGS:+ }console=${ITEM//:/,}" + done + + for ITEM in $SRC_CMDLINE ; do + if [[ ! 'console' == "${ITEM%%=*}" ]] ; then + continue + fi + if [[ ! "${ITEM#*=}" =~ 'tty'[AGSU]* ]] ; then + continue + fi + CONSOLEARGS="${CONSOLEARGS:-}${CONSOLEARGS:+ }${ITEM:?}" + done + CONSOLEARGS="$(echo "${CONSOLEARGS:-}" | xargs -n1 | sort -u | xargs)" + + export BOOTSCRIPT_TEMPLATE__SERIAL_CONSOLE="${CONSOLEARGS:-}" +} + +function render_bootscript_template() { ( + typeset BOOTSCRIPT_TEMPLATE__CREATE_DATE + typeset SHELL_FORMAT + + BOOTSCRIPT_TEMPLATE__CREATE_DATE="$(date -Ru)" + + bootscript_export_display_console + bootscript_export_serial_console + + SHELL_FORMAT="$(set | sed -En '/^BOOTSCRIPT_TEMPLATE__/ { s/=.*$//; s/^/$/; p; }')" + display_alert "Bootscript template variables to be rendered" "${SHELL_FORMAT:-N/A}" "debug" + + export $(set | sed -En '/^BOOTSCRIPT_TEMPLATE__/s/=.*$//p') + envsubst "'${SHELL_FORMAT}'" +) } + +function proof_rendered_bootscript_template() { + ! egrep '\$\{?BOOTSCRIPT_TEMPLATE__' "${1:?}" +} + function install_distribution_agnostic() { display_alert "Installing distro-agnostic part of rootfs" "install_distribution_agnostic" "debug" @@ -121,9 +187,16 @@ function install_distribution_agnostic() { fi # NOTE: this needs to be executed before family_tweaks + local bootscript_src_path local bootscript_src=${BOOTSCRIPT%%:*} local bootscript_dst=${BOOTSCRIPT##*:} + if [[ -f "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" ]]; then + bootscript_src_path="${USERPATCHES_PATH}/bootscripts" + else + bootscript_src_path="${SRC}/config/bootscripts" + fi + # create extlinux config file @TODO: refactor into extensions u-boot, extlinux if [[ $SRC_EXTLINUX == yes ]]; then display_alert "Using extlinux, SRC_EXTLINUX: ${SRC_EXTLINUX}" "$NAME_KERNEL - $NAME_INITRD" "info" @@ -159,12 +232,20 @@ function install_distribution_agnostic() { else # ... not extlinux ... if [[ -n "${BOOTSCRIPT}" ]]; then # @TODO: && "${BOOTCONFIG}" != "none" - display_alert "Deploying boot script" "$bootscript_src" "info" - if [ -f "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" ]; then - run_host_command_logged cp -pv "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" "${SDCARD}/boot/${bootscript_dst}" - else - run_host_command_logged cp -pv "${SRC}/config/bootscripts/${bootscript_src}" "${SDCARD}/boot/${bootscript_dst}" - fi + case "${bootscript_src}" in + *'.template') + display_alert "Rendering boot script template" "${bootscript_src_path}/${bootscript_src}" "info" + run_host_command_logged cat "${bootscript_src_path}/${bootscript_src}" | render_bootscript_template > "${SDCARD}/boot/${bootscript_dst}" + + if ! proof_rendered_bootscript_template "${SDCARD}/boot/${bootscript_dst}" ; then + exit_with_error "Render of bootscript template was not successful. Inspect '${SDCARD}/boot/${bootscript_dst}' for unrendered variables." + fi + ;; + *) + display_alert "Deploying boot script" "${bootscript_src_path}/${bootscript_src}" "info" + run_host_command_logged cp -pv "${bootscript_src_path}/${bootscript_src}" "${SDCARD}/boot/${bootscript_dst}" + ;; + esac fi if [[ -n $BOOTENV_FILE ]]; then