From 690262acdba2511b14798c04b19d9dcc7df2d538 Mon Sep 17 00:00:00 2001 From: Anton Gerasimov Date: Thu, 21 Feb 2019 15:54:39 +0100 Subject: Add universal uEnv recipe Signed-off-by: Anton Gerasimov --- README.adoc | 16 +++++- classes/image_types_ostree.bbclass | 7 ++- classes/sota.bbclass | 17 +++++- classes/sota_raspberrypi.bbclass | 8 ++- .../ota-u-boot-script/files/uEnv-fileenv.txt | 1 + recipes-sota/ota-u-boot-script/files/uEnv-fit.txt | 1 + .../ota-u-boot-script/files/uEnv-rollback.txt | 8 +++ recipes-sota/ota-u-boot-script/files/uEnv.txt | 34 ++++++++++++ .../ota-u-boot-script/ota-u-boot-script.bb | 63 ++++++++++++++++++++++ 9 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 recipes-sota/ota-u-boot-script/files/uEnv-fileenv.txt create mode 100644 recipes-sota/ota-u-boot-script/files/uEnv-fit.txt create mode 100644 recipes-sota/ota-u-boot-script/files/uEnv-rollback.txt create mode 100644 recipes-sota/ota-u-boot-script/files/uEnv.txt create mode 100644 recipes-sota/ota-u-boot-script/ota-u-boot-script.bb diff --git a/README.adoc b/README.adoc index 27ecabf..d425095 100644 --- a/README.adoc +++ b/README.adoc @@ -70,9 +70,20 @@ If your board isn't supported yet, you can add board integration code yourself. 1. Make the board boot into http://www.denx.de/wiki/U-Boot[U-Boot] 2. Make U-boot import variables from /boot/loader/uEnv.txt and load the kernel with initramfs and kernel command line arguments according to what is set in this file. -You may take a look into https://github.com/advancedtelematic/meta-updater-minnowboard[Minnowboard] or https://github.com/advancedtelematic/meta-updater-raspberrypi[Raspberry Pi] integration layers for examples. +There is a flexible universal U-boot script provided by meta-updater to do OSTree-enabled boot, `ota-u-boot-script`. It is not being deployed by default, so you should enable it in your machine configuration. This script can be configured with following variables: -Although we have used U-Boot so far, other boot loaders can be configured work with OSTree as well. +* `SOTA_BOOTLOADER_BOOTCOMMAND` - command U-Boot will use to load the kernel. Normally is either `bootm` or `bootz`. +* `SOTA_BOOTLOADER_BOOT_PART` - boot partition the script will use. Now only used for storing the U-Boot environment. Should be a full partition name, e.g. `mmc 0:1`. +* `SOTA_BOOTLOADER_MAIN_PART` - the partition where the OSTree sysroot resides. Should be a full partition name, e.g. `mmc 0:1` +* `SOTA_BOOTLOADER_KERNEL_ADDR` - address to load the kernel to. Can't refer to another variable, should be a (normally hex) number e.g. `0x02700000`. +* `SOTA_BOOTLOADER_RAMDISK_ADDR` - address to load the ramdisk to. Can't refer to another variable, should be a (normally hex) number e.g. `0x02700000`. Set to empty when using FIT image with ramdisk packed (`KERNEL_IMAGETYPE = "fitImage"`). +* `SOTA_BOOTLOADER_FDT_ADDR` - address to load the device tree to. Can't refer to another variable, should be a (normally hex) number e.g. `0x02700000`. Set to empty when no device tree is used. +* `SOTA_BOOTLOADER_ROOT_DEVICE` - the partition where the OSTree sysroot resides as linux device path, e.g. `/dev/mmcblk0p2`. +* `SOTA_BOOTLOADER_EXTRA_PARAMS` - extra parameters to add to kernel command line. Note that these parameters will be non-updatable, it is recommended in most cases to use `OSTREE_KERNEL_ARGS` instead. + +Although meta-updater is best integrated with U-Boot so far, basic support for Grub also exists. In addition to these two bootloaders libostree also supports SysLinux. + +Normally there still has to be some platform-dependent integration snippet that would source the script provided by meta-updater and/or OSTree. For an example of such snippets you can look into https://github.com/advancedtelematic/meta-updater-raspberrypi[Raspberry Pi] (U-Boot) and https://github.com/advancedtelematic/meta-updater-minnowboard[Minnowboard] (Grub, directly loads snippet provided by libostree) integration layers. == SOTA-related variables in local.conf @@ -82,6 +93,7 @@ Although we have used U-Boot so far, other boot loaders can be configured work w * `OSTREE_COMMIT_SUBJECT` - Commit subject used by OSTree. Defaults to `Commit-id: ${IMAGE_NAME}` * `OSTREE_UPDATE_SUMMARY` - Set this to '1' to update summary of OSTree repository on each commit. '0' by default. * `OSTREE_DEPLOY_DEVICETREE` - Set this to '1' to include devicetree(s) to boot +* `OSTREE_KERNEL_ARGS` - Parameters to kernel command line. * `INITRAMFS_IMAGE` - initramfs/initrd image that is used as a proxy while booting into OSTree deployment. Do not change this setting unless you are sure that your initramfs can serve as such a proxy. * `SOTA_PACKED_CREDENTIALS` - when set, your ostree commit will be pushed to a remote repo as a bitbake step. This should be the path to a zipped credentials file in https://github.com/advancedtelematic/aktualizr/blob/master/docs/credentials.adoc[the format accepted by garage-push]. * `SOTA_DEPLOY_CREDENTIALS` - when set to '1' (default value), deploys credentials to the built image. Override it in `local.conf` to built a generic image that can be provisioned manually after the build. diff --git a/classes/image_types_ostree.bbclass b/classes/image_types_ostree.bbclass index 29da78e..a6c9155 100644 --- a/classes/image_types_ostree.bbclass +++ b/classes/image_types_ostree.bbclass @@ -112,7 +112,12 @@ IMAGE_CMD_ostree () { touch boot/initramfs-${checksum} else if [ "${OSTREE_DEPLOY_DEVICETREE}" = "1" ] && [ -n "${KERNEL_DEVICETREE}" ]; then - checksum=$(cat ${DEPLOY_DIR_IMAGE}/${OSTREE_KERNEL} ${DEPLOY_DIR_IMAGE}/${INITRAMFS_IMAGE}-${MACHINE}.${INITRAMFS_FSTYPES} ${KERNEL_DEVICETREE} | sha256sum | cut -f 1 -d " ") + kernel_ostree_fullpath="" + for blob in ${KERNEL_DEVICETREE}; do + kernel_ostree_fullpath="$kernel_ostree_fullpath ${DEPLOY_DIR_IMAGE}/$blob" + done + + checksum=$(cat ${DEPLOY_DIR_IMAGE}/${OSTREE_KERNEL} ${DEPLOY_DIR_IMAGE}/${INITRAMFS_IMAGE}-${MACHINE}.${INITRAMFS_FSTYPES} $kernel_ostree_fullpath | sha256sum | cut -f 1 -d " ") for DTS_FILE in ${KERNEL_DEVICETREE}; do DTS_FILE_BASENAME=$(basename ${DTS_FILE}) cp ${DEPLOY_DIR_IMAGE}/${DTS_FILE_BASENAME} boot/devicetree-${DTS_FILE_BASENAME}-${checksum} diff --git a/classes/sota.bbclass b/classes/sota.bbclass index 92b4c43..236a3bb 100644 --- a/classes/sota.bbclass +++ b/classes/sota.bbclass @@ -21,7 +21,11 @@ WKS_FILE_sota ?= "sdimage-sota.wks" EXTRA_IMAGEDEPENDS_append_sota = " parted-native mtools-native dosfstools-native" -INITRAMFS_FSTYPES ?= "${@oe.utils.ifelse(d.getVar('OSTREE_BOOTLOADER') == 'u-boot', 'cpio.gz.u-boot', 'cpio.gz')}" +# Has to be an override, because 'INITRAMFS_FSTYPES ?=' is not strong enough to override the default value +INITRAMFS_FSTYPES_sota ?= "${@oe.utils.ifelse(d.getVar('OSTREE_BOOTLOADER') == 'u-boot' and d.getVar('KERNEL_IMAGETYPE') != 'fitImage', 'cpio.gz.u-boot', 'cpio.gz')}" + +# Deploy config fragment list to OSTree root fs +IMAGE_INSTALL_append = "${@oe.utils.ifelse(d.getVar('KERNEL_IMAGETYPE') == 'fitImage', ' fit-conf', ' ')}" # Please redefine OSTREE_REPO in order to have a persistent OSTree repo export OSTREE_REPO ?= "${DEPLOY_DIR_IMAGE}/ostree_repo" @@ -38,6 +42,15 @@ GARAGE_TARGET_NAME ?= "${OSTREE_BRANCHNAME}" GARAGE_TARGET_VERSION ?= "" GARAGE_TARGET_URL ?= "https://example.com/" +SOTA_BOOTLOADER_EXTRA_PARAMS ??= "" +SOTA_BOOTLOADER_BOOTCOMMAND ??= "bootm" +SOTA_BOOTLOADER_KERNEL_ADDR ??= "0x02700000" +SOTA_BOOTLOADER_RAMDISK_ADDR ??= "" +SOTA_BOOTLOADER_FDT_ADDR ??= "" +SOTA_BOOTLOADER_BOOT_PART ??= "mmc 0:1" +SOTA_BOOTLOADER_MAIN_PART ??= "mmc 0:2" +SOTA_BOOTLOADER_ROOT_DEVICE ??= "/dev/mmcblk0p2" + SOTA_MACHINE ??="none" SOTA_MACHINE_rpi ?= "raspberrypi" SOTA_MACHINE_porter ?= "porter" @@ -49,4 +62,6 @@ SOTA_MACHINE_am335x-evm ?= "am335x-evm-wifi" SOTA_OVERRIDES_BLACKLIST = "ostree ota" SOTA_REQUIRED_VARIABLES = "OSTREE_REPO OSTREE_BRANCHNAME OSTREE_OSNAME OSTREE_BOOTLOADER OSTREE_BOOT_PARTITION GARAGE_SIGN_REPO GARAGE_TARGET_NAME" +do_image_wic[depends] += " ota-u-boot-script:do_deploy " + inherit sota_sanity sota_${SOTA_MACHINE} image_repo_manifest diff --git a/classes/sota_raspberrypi.bbclass b/classes/sota_raspberrypi.bbclass index e1c0054..88b5f21 100644 --- a/classes/sota_raspberrypi.bbclass +++ b/classes/sota_raspberrypi.bbclass @@ -2,16 +2,12 @@ RPI_USE_U_BOOT_sota = "1" KERNEL_CLASSES_append_sota = " kernel-fitimage" KERNEL_IMAGETYPE_sota = "fitImage" -INITRAMFS_FSTYPES = "cpio.gz" OSTREE_KERNEL = "${KERNEL_IMAGETYPE}-${INITRAMFS_IMAGE}-${MACHINE}-${KERNEL_FIT_LINK_NAME}" # DTB needs to be relocated to apply overlays UBOOT_DTB_LOADADDRESS = "0x05000000" UBOOT_DTBO_LOADADDRESS = "0x06000000" -# Deploy config fragment list to OSTree root fs -IMAGE_INSTALL_append = " fit-conf" - PREFERRED_PROVIDER_virtual/bootloader_sota ?= "u-boot" UBOOT_ENTRYPOINT_sota ?= "0x00008000" @@ -19,7 +15,7 @@ IMAGE_FSTYPES_remove_sota = "rpi-sdimg" OSTREE_BOOTLOADER ?= "u-boot" # OSTree puts its own boot.scr to bcm2835-bootfiles -IMAGE_BOOT_FILES_sota = "bcm2835-bootfiles/* u-boot.bin;${SDIMG_KERNELIMAGE}" +IMAGE_BOOT_FILES_sota = "bcm2835-bootfiles/* uEnv.txt u-boot.bin;${SDIMG_KERNELIMAGE}" # Just the overlays that will be used should be listed KERNEL_DEVICETREE_raspberrypi2_sota ?= " bcm2709-rpi-2-b.dtb " @@ -35,3 +31,5 @@ OSTREE_KERNEL_ARGS_sota ?= " 8250.nr_uarts=1 bcm2708_fb.fbwidth=656 bcm2708_fb.f SOTA_CLIENT_FEATURES_append = " ubootenv" +SOTA_ROLLBACK_MECHANISM = "file-env" + diff --git a/recipes-sota/ota-u-boot-script/files/uEnv-fileenv.txt b/recipes-sota/ota-u-boot-script/files/uEnv-fileenv.txt new file mode 100644 index 0000000..6a179b7 --- /dev/null +++ b/recipes-sota/ota-u-boot-script/files/uEnv-fileenv.txt @@ -0,0 +1 @@ +bootcmd_create_envfile=if test ! -e $sota_boot_part uboot.env; then saveenv; fi; diff --git a/recipes-sota/ota-u-boot-script/files/uEnv-fit.txt b/recipes-sota/ota-u-boot-script/files/uEnv-fit.txt new file mode 100644 index 0000000..51eaf73 --- /dev/null +++ b/recipes-sota/ota-u-boot-script/files/uEnv-fit.txt @@ -0,0 +1 @@ +bootcmd_fitconf=run bootcmd_getroot; if test -e ${sota_main_part} "${ostree_root}/usr/lib/fit_conf"; then load ${sota_main_part} $loadaddr "${ostree_root}/usr/lib/fit_conf"; env import -t $loadaddr $filesize; fi; diff --git a/recipes-sota/ota-u-boot-script/files/uEnv-rollback.txt b/recipes-sota/ota-u-boot-script/files/uEnv-rollback.txt new file mode 100644 index 0000000..07b6b22 --- /dev/null +++ b/recipes-sota/ota-u-boot-script/files/uEnv-rollback.txt @@ -0,0 +1,8 @@ +bootcmd_rollbackenv=setenv kernel_image ${kernel_image2}; setenv ramdisk_image ${ramdisk_image2}; setenv fdt_file ${fdt_file2}; setenv bootargs ${bootargs2} + +bootlimit=3 + +bootcmd_set_rollback=if test ! "${rollback}" = "1"; then setenv rollback 1; setenv upgrade_available 0; saveenv; fi +altbootcmd=run bootcmd_create_envfile; run bootcmd_otenv; run bootcmd_set_rollback; if test -n "${kernel_image2}"; then run bootcmd_rollbackenv; fi; run bootcmd_args; run bootcmd_fitconf; run bootcmd_load; run bootcmd_run; reset + + diff --git a/recipes-sota/ota-u-boot-script/files/uEnv.txt b/recipes-sota/ota-u-boot-script/files/uEnv.txt new file mode 100644 index 0000000..d890257 --- /dev/null +++ b/recipes-sota/ota-u-boot-script/files/uEnv.txt @@ -0,0 +1,34 @@ +bootcmd_fitconf= +bootcmd_create_envfile= +fit_conf= + +sota_bootcommand=@@SOTA_BOOTLOADER_BOOTCOMMAND@@ +sota_kernel_addr=@@SOTA_BOOTLOADER_KERNEL_ADDR@@ +sota_ramdisk_addr=@@SOTA_BOOTLOADER_RAMDISK_ADDR@@ +sota_fdt_addr=@@SOTA_BOOTLOADER_FDT_ADDR@@ +sota_boot_part=@@SOTA_BOOTLOADER_BOOT_PART@@ +sota_main_part=@@SOTA_BOOTLOADER_MAIN_PART@@ +sota_root_device=@@SOTA_BOOTLOADER_ROOT_DEVICE@@ + +@@INITFINISHED@@ + +bootcmd_resetvars=setenv kernel_image; setenv bootargs; setenv kernel_image2; setenv bootargs2 +bootcmd_otenv=run bootcmd_resetvars; load ${sota_main_part} $loadaddr /boot/loader/uEnv.txt; env import -t $loadaddr $filesize + +bootcmd_args=setenv bootargs "$bootargs $bootargs_fdt ostree_root=$sota_root_device root=/dev/ram0 rw rootwait rootdelay=2 ramdisk_size=8192 panic=1 @@SOTA_BOOTLOADER_EXTRA_PARAMS@@" + +bootcmd_getroot=setexpr ostree_root gsub "^.*ostree=([^ ]*).*$" "\\\\1" "${bootargs}"; + +bootcmd_load_kernel=load $sota_main_part $sota_kernel_addr "/boot"$kernel_image + +bootcmd_load_ramdisk=if test -n "${sota_ramdisk_addr}"; then load $sota_main_part $sota_ramdisk_addr "/boot"$ramdisk_image; fi + +bootcmd_load_fdt=if test -n "${sota_fdt_addr}"; then load $sota_main_part $sota_fdt_addr "/boot"$fdt_file; fi + +bootcmd_load=run bootcmd_load_kernel; run bootcmd_load_ramdisk; run bootcmd_load_fdt; + +bootcmd_run=$sota_bootcommand $sota_kernel_addr$fit_conf $sota_ramdisk_addr $sota_fdt_addr + +bootcmd=if test "${rollback}" = "1"; then run altbootcmd; else run bootcmd_create_envfile; run bootcmd_otenv; run bootcmd_args; run bootcmd_fitconf; run bootcmd_load; run bootcmd_run; if test ! "${upgrade_available}" = "1"; then setenv upgrade_available 1; saveenv; fi; reset; fi + + diff --git a/recipes-sota/ota-u-boot-script/ota-u-boot-script.bb b/recipes-sota/ota-u-boot-script/ota-u-boot-script.bb new file mode 100644 index 0000000..de00148 --- /dev/null +++ b/recipes-sota/ota-u-boot-script/ota-u-boot-script.bb @@ -0,0 +1,63 @@ +DESCRIPTION = "Boot script template for OTA-enabled image" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" + +inherit deploy + +SRC_URI = "file://uEnv-fileenv.txt \ + file://uEnv-fit.txt \ + file://uEnv-rollback.txt \ + file://uEnv.txt" + +python () { + d.setVar('SOTA_BOOTLOADER_EXTRA_PARAMS', d.getVar('SOTA_BOOTLOADER_EXTRA_PARAMS').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_BOOTCOMMAND', d.getVar('SOTA_BOOTLOADER_BOOTCOMMAND').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_KERNEL_ADDR', d.getVar('SOTA_BOOTLOADER_KERNEL_ADDR').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_RAMDISK_ADDR', d.getVar('SOTA_BOOTLOADER_RAMDISK_ADDR').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_FDT_ADDR', d.getVar('SOTA_BOOTLOADER_FDT_ADDR').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_BOOT_PART', d.getVar('SOTA_BOOTLOADER_BOOT_PART').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_MAIN_PART', d.getVar('SOTA_BOOTLOADER_MAIN_PART').replace('/', '\/')) + d.setVar('SOTA_BOOTLOADER_ROOT_DEVICE', d.getVar('SOTA_BOOTLOADER_ROOT_DEVICE').replace('/', '\/')) +} + +do_compile() { + + UENV_TEMPLATE="${WORKDIR}/uEnv.template" + # Initialization portion + sed -n '0,/@@INITFINISHED@@/p' < ${WORKDIR}/uEnv.txt | head -n -1 > $UENV_TEMPLATE + + # Support for FIT images + if [ "${KERNEL_IMAGETYPE}" = "fitImage" ]; then + cat ${WORKDIR}/uEnv-fit.txt >> $UENV_TEMPLATE + fi + + # Rollback support + if [ -n "${SOTA_ROLLBACK_MECHANISM}" ]; then + cat ${WORKDIR}/uEnv-rollback.txt >> $UENV_TEMPLATE + + if [ "${SOTA_ROLLBACK_MECHANISM}" = "file-env" ]; then + cat ${WORKDIR}/uEnv-fileenv.txt >> $UENV_TEMPLATE + fi + fi + + # The rest of the base template + sed -n '/@@INITFINISHED@@/,$p' < ${WORKDIR}/uEnv.txt | sed -n '2,$p' >> $UENV_TEMPLATE + + # Substitute the variables + sed -e 's/@@SOTA_BOOTLOADER_EXTRA_PARAMS@@/${SOTA_BOOTLOADER_EXTRA_PARAMS}/' \ + -e 's/@@SOTA_BOOTLOADER_BOOTCOMMAND@@/${SOTA_BOOTLOADER_BOOTCOMMAND}/' \ + -e 's/@@SOTA_BOOTLOADER_KERNEL_ADDR@@/${SOTA_BOOTLOADER_KERNEL_ADDR}/' \ + -e 's/@@SOTA_BOOTLOADER_RAMDISK_ADDR@@/${SOTA_BOOTLOADER_RAMDISK_ADDR}/' \ + -e 's/@@SOTA_BOOTLOADER_FDT_ADDR@@/${SOTA_BOOTLOADER_FDT_ADDR}/' \ + -e 's/@@SOTA_BOOTLOADER_BOOT_PART@@/${SOTA_BOOTLOADER_BOOT_PART}/' \ + -e 's/@@SOTA_BOOTLOADER_MAIN_PART@@/${SOTA_BOOTLOADER_MAIN_PART}/' \ + -e 's/@@SOTA_BOOTLOADER_ROOT_DEVICE@@/${SOTA_BOOTLOADER_ROOT_DEVICE}/' \ + "$UENV_TEMPLATE" > ${WORKDIR}/uEnv-final.txt +} + +do_deploy() { + install -d ${DEPLOYDIR} + install -m 0644 ${WORKDIR}/uEnv-final.txt ${DEPLOYDIR}/uEnv.txt +} + +addtask deploy after do_compile before do_build -- cgit v1.2.3-54-g00ecf