Changes between Version 14 and Version 15 of buildroot


Ignore:
Timestamp:
12/21/2019 12:15:53 AM (3 years ago)
Author:
Tim Harvey
Comment:

added SWUpdate section

Legend:

Unmodified
Added
Removed
Modified
  • buildroot

    v14 v15  
    278278 * pciutils usb-utils
    279279 * disk partitioning tools
     280
     281
     282[=#swupdate]
     283== SWUpdate
     284SWUpdate is a framework for providing firmware udpates. It is extremely flexible and provides support for many different scenarios. Because it exists as a package for buildroot it is a great choice for providing firmware updates when using a buildroot solution.
     285
     286Here we will provide an example of building an SWUpdate Over-The-Air (OTA) update for buildroot with the following considerations:
     287 - Newport
     288 - Symmetric Image Update (Two copies of rootfs which works well when your filesystem is relatively small compared to memory/flash space)
     289 - We will not bother updating boot firmware (can be added later)
     290 - We will not bother updating GSC firmware (can be added later)
     291 - We will build the Gateworks 4.14 kernel for newport with a minimal kernel config
     292 - We will use an uncompressed kernel image (just avoids needing to kernel a kernel.itb)
     293 - We will use a modified uboot environment to handle our root partition  toggling
     294
     295Here are the relevant files to add to your buildroot directory:
     296 * '''configs/newport_swupdate_defconfig''': Buildroot defconfig (represents the minimal 'changes' made to buildroot default config):
     297{{{#!bash
     298BR2_aarch64=y
     299BR2_KERNEL_HEADERS_4_14=y
     300
     301# we will add some files to the rootfs from the 'overlay' subdir
     302BR2_ROOTFS_OVERLAY="overlay"
     303
     304#
     305# Kernel:
     306#  we will build the gateworks linux kernel using arm64 defconfig
     307#  plus some additional configs via newport_kernel_defconfig
     308BR2_LINUX_KERNEL=y
     309BR2_LINUX_KERNEL_CUSTOM_GIT=y
     310BR2_LINUX_KERNEL_CUSTOM_REPO_URL="https://github.com/Gateworks/linux-newport.git"
     311BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="v4.14.4-newport"
     312BR2_LINUX_KERNEL_USE_ARCH_DEFAULT_CONFIG=y
     313BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="newport_kernel_defconfig"
     314BR2_LINUX_KERNEL_INSTALL_TARGET=y
     315
     316#
     317# Packages:
     318#  we need u-boot env tools for fw_setenv support in our scripts
     319#  we need zlib for gzip support in SWUpdate
     320#  we will use swupdate.config to configure SWUpdate
     321BR2_PACKAGE_UBOOT_TOOLS=y
     322BR2_PACKAGE_ZLIB=y
     323BR2_PACKAGE_SWUPDATE=y
     324BR2_PACKAGE_SWUPDATE_CONFIG="swupdate.config"
     325}}}
     326  - Note that SWUpdate reuqires ZLIB if we are going to use gzip compression
     327 * '''newport_kernel_defconfig''': Kernel config fragment that adds OcteonTX and newport drivers to arm64 kernel defconfig
     328{{{#!bash
     329# Additionally OcteonTX peripheral drivers
     330CONFIG_PCI_HOST_THUNDER_PEM=y
     331CONFIG_PCI_HOST_THUNDER_ECAM=y
     332CONFIG_CAN=y
     333CONFIG_CAN_MCP251X=y
     334CONFIG_THUNDER_NIC_PF=y
     335CONFIG_THUNDER_NIC_VF=y
     336CONFIG_MDIO_BITBANG=y
     337CONFIG_I2C=y
     338CONFIG_I2C_THUNDERX=y
     339CONFIG_SPI_THUNDERX=y
     340CONFIG_GPIO_THUNDERX=y
     341CONFIG_MMC_CAVIUM_THUNDERX=y
     342CONFIG_EDAC_THUNDERX=y
     343CONFIG_EXT4_FS=y
     344# Gateworks Newport GSC drivers
     345CONFIG_SENSORS_GSC=y
     346CONFIG_MFD_GSC=y
     347}}}
     348 * '''overlay/etc/fw_env.config''': config file for u-boot env tools fw_setenv
     349{{{#!bash
     350# Device offset size
     351/dev/mmcblk0 0xff0000 0x8000
     352/dev/mmcblk0 0xff8000 0x8000
     353}}}
     354  - Note that this file is whitespace sensitive
     355 * '''swupdate.config''': config file to build swupdate executable which resides on your firmware and drives the update process
     356{{{#!bash
     357# We do not need MTD or LUA support
     358# CONFIG_MTD is not set
     359# CONFIG_LUA is not set
     360# We need the raw handler to image to an MMC partition
     361CONFIG_RAW=y
     362# We need the shellscript handler for our update.sh shellscript
     363CONFIG_SHELLSCRIPTHANDLER=y
     364# We need the bootloader handler to alter the u-boot environment
     365CONFIG_BOOTLOADERHANDLER=y
     366}}}
     367 * '''sw-description''': part of the actual firmware OTA which describes the process and file manifest of the update image. See [https://sbabic.github.io/swupdate/sw-description.html# here] for syntax
     368{{{#!bash
     369software =
     370{
     371        version = "0.1.0";
     372        description = "Firmware update for XXXXX Project";
     373
     374        /* images installed to the system */
     375        images: (
     376                {
     377                        filename = "rootfs.ext4.gz";
     378                        device = "/dev/update";
     379                        type = "raw";
     380                        compressed = true;
     381                }
     382        );
     383
     384        scripts: (
     385                {
     386                        filename = "update.sh";
     387                        type = "shellscript";
     388                }
     389        );
     390}
     391}}}
     392 - '''update.sh''': This is the script that SWUpdate runs which we use as both a preinst and psotinst script (via cmdline). We determine the current root device and, flip it, and symlink /dev/update to the device to update to. We don't have to do the image install as we've configured SWUpdate to do that for us in sw-descrption images.
     393{{{#!bash
     394#!/bin/sh
     395
     396if [ $# -lt 1 ]; then
     397        exit 0;
     398fi
     399
     400function get_current_root_device
     401{
     402        for i in `cat /proc/cmdline`; do
     403                if [ ${i:0:5} = "root=" ]; then
     404                        CURRENT_ROOT="${i:5}"
     405                fi
     406        done
     407}
     408
     409# ping-pong between /dev/mmcblk0p2 and /dev/mmcblk0p3
     410# (adapt for your partitioning scheme and/or root device type)
     411function get_update_part
     412{
     413        CURRENT_PART="${CURRENT_ROOT: -/dev/mmcblk0p2}"
     414        if [ $CURRENT_PART = "/dev/mmcblk0p2" ]; then
     415                UPDATE_PART="3";
     416        else
     417                UPDATE_PART="2";
     418        fi
     419}
     420
     421function get_update_device
     422{
     423        UPDATE_ROOT=${CURRENT_ROOT%?}${UPDATE_PART}
     424}
     425
     426
     427if [ $1 == "preinst" ]; then
     428        # get the current root device
     429        get_current_root_device
     430
     431        # get the device to be updated
     432        get_update_part
     433        get_update_device
     434
     435        # create a symlink for the update process
     436        ln -sf $UPDATE_ROOT /dev/update
     437fi
     438
     439if [ $1 == "postinst" ]; then
     440        # get the current root device
     441        get_current_root_device
     442
     443        # get the device to be updated
     444        get_update_part
     445        get_update_device
     446
     447        # toggle rootpart between 2 and 3
     448        # we do it twice to write to both primary/secondary env
     449        fw_setenv mmcbootpart $UPDATE_PART
     450        fw_setenv mmcbootpart $UPDATE_PART
     451fi
     452}}}
     453
     454Once this is in place you can use the following to build:
     455{{{#!bash
     456# build buildroot rootfs
     457make newport_swupdate_defconfig
     458make
     459
     460# build swupdate image
     461cp output/images/rootfs.ext4.gz .
     462for i in sw-description update.sh rootfs.ext4.gz; do
     463        echo $i; done | cpio -ov -H crc > my-software.swu
     464}}}
     465
     466Here are some one-time steps you will need to do to your boot firmware:
     467 * create an MBR partition table that defines LinuxA and LinuxB partitions we will ping-pong between. Note that the FATFS must not be changed from the original boot firmware generated MBR and that we also create a general userdata partition.
     468{{{#!bash
     469# 1: 2048:30720 (15MiB) FAT12 (required by boot firmware)
     470# 2: 65536:4194304 (2GiB) LinuxA
     471# 3: 4259840:4194304 (2GiB) LinuxB
     472# 4: 19103744:4194304 (2GiB) userdata
     473wget -q https://raw.githubusercontent.com/Gateworks/bsp-newport/sdk-10.1.1.0-newport/ptgen
     474/bin/bash ptgen \
     475        -p 0x01:2048:30720 \
     476        -p 0x83:65536:4194304 \
     477        -p 0x83:4259840:4194304 \
     478        -p 0x83:19103744:4194304 \
     479        > $BUILDROOT/output/images/mbr.bin
     480}}}
     481 * In U-Boot we will update the partition table:
     482{{{#!bash
     483tftpboot ${loadaddr} mbr.bin && mmc dev 0 && mmc write ${loadaddr} 0 1 # mbr is at 0 and 1 sector long
     484}}}
     485  - Note that if you ever update the entire boot firmware it will over-write this partition table so you will want to take care to not overwrite that portion
     486 * In U-Boot we will install the original rootfs to the first Linux partition offset (LinuxA)
     487{{{#!bash
     488tftpboot ${loadaddr} rootfs.ext4.gz && gzwrite mmc 0 ${loadaddr} ${filesize} 0x100000 0x2000000 # rootfsA is at 0x2000000 (64MiB) and we use a 1MiB buffer
     489}}}
     490 * In U-Boot we will alter the env to use the '''mmcbootpart''' env variable that our update.sh manipulates after a successful update:
     491{{{#!bash
     492setenv mmcbootpart 2
     493setenv bootcmd "setenv bootargs 'console=${console} root=/dev/mmcblk0p${mmcbootpart} rootwait rw; load mmc 0:${mmcbootpart} ${kernel_addr_r} boot/Image' && booti ${kernel_addr_r} - ${fdtcontroladdr}"
     494saveenv
     495}}}
     496  - Note the single quotes around the bootargs value as we do not want U-Boot to expand the args until runtime
     497
     498After you boot to buildroot you can fetch and install the SWUpdate image with:
     499{{{#!bash
     500# bring up networking
     501udhcpc -i eth0
     502# fetch image
     503cd /tmp
     504wget http://myserver/my-software.swu
     505swupdate -i mysoftware.swu
     506}}}
     507
     508Note that if you require support for SWUpdate to complete an install that isn't already there (for example you want to add the capability to update GSC firmware via the gsc_update utility) you will either need to a) add a static linked version of that tool to your image or b) do a 2-stage update where you add the required tools first, then use them in a future update