| 926 | === For Venice |
| 927 | |
| 928 | In this example Buildroot branch 2021.08.x was used. |
| 929 | |
| 930 | Here are the relevant files to add to your buildroot directory: |
| 931 | * '''configs/venice_swupdate_defconfig''': Buildroot defconfig (represents the minimal 'changes' made to buildroot default config): |
| 932 | {{{#!bash |
| 933 | cat << EOF > configs/venice_swupdate_defconfig |
| 934 | BR2_aarch64=y |
| 935 | BR2_KERNEL_HEADERS_5_10=y |
| 936 | BR2_ROOTFS_OVERLAY="overlay" |
| 937 | BR2_LINUX_KERNEL=y |
| 938 | BR2_LINUX_KERNEL_CUSTOM_GIT=y |
| 939 | BR2_LINUX_KERNEL_CUSTOM_REPO_URL="https://github.com/Gateworks/linux-venice.git" |
| 940 | BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION="v5.10.18-venice" |
| 941 | BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y |
| 942 | BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="venice_minimal_kernel_defconfig" |
| 943 | BR2_LINUX_KERNEL_INSTALL_TARGET=y |
| 944 | BR2_PACKAGE_UBOOT_TOOLS=y |
| 945 | BR2_PACKAGE_OPENSSL=y |
| 946 | BR2_PACKAGE_LIBCONFIG=y |
| 947 | BR2_PACKAGE_JSON_C=y |
| 948 | BR2_PACKAGE_LIBCURL=y |
| 949 | BR2_PACKAGE_SWUPDATE=y |
| 950 | BR2_PACKAGE_SWUPDATE_CONFIG="swupdate.config" |
| 951 | BR2_TARGET_ROOTFS_EXT2=y |
| 952 | BR2_TARGET_ROOTFS_EXT2_4=y |
| 953 | BR2_TARGET_ROOTFS_EXT2_GZIP=y |
| 954 | EOF |
| 955 | }}} |
| 956 | - Note that SWupdate reuqires ZLIB if we are going to use gzip compression |
| 957 | |
| 958 | * '''Download or create a defconfig:''' |
| 959 | {{{#!bash |
| 960 | wget http://dev.gateworks.com/buildroot/venice/minimal/venice_minimal_kernel_defconfig |
| 961 | }}} |
| 962 | * '''overlay/etc/fw_env.config''': config file for u-boot env tools fw_setenv |
| 963 | {{{#!bash |
| 964 | mkdir overlay |
| 965 | mkdir overlay/etc |
| 966 | cat << EOF > overlay/etc/fw_env.config |
| 967 | # Device offset Env. size |
| 968 | /dev/mmcblk2 0xff0000 0x8000 |
| 969 | /dev/mmcblk2 0xff8000 0x8000 |
| 970 | EOF |
| 971 | }}} |
| 972 | - Note that this file is whitespace sensitive |
| 973 | * '''Create swupdate.config config file to build swupdate executable which drives the update process.''' |
| 974 | {{{#!bash |
| 975 | cat << EOF > swupdate.config |
| 976 | # We do not need MTD or LUA support |
| 977 | # CONFIG_MTD is not set |
| 978 | # CONFIG_LUA is not set |
| 979 | CONFIG_SIGNED_IMAGES=y |
| 980 | CONFIG_ENCRYPTED_IMAGES=y |
| 981 | # Suricatta provides support for fetching updates via a Hawkbit server if desired |
| 982 | CONFIG_SURICATTA=y |
| 983 | CONFIG_SURICATTA_SSL=y |
| 984 | CONFIG_SURICATTA_STATE_CHOICE_BOOTLOADER=y |
| 985 | # We need the raw handler to image to an MMC partition |
| 986 | CONFIG_RAW=y |
| 987 | # We need the shellscript handler for our update.sh shellscript |
| 988 | CONFIG_SHELLSCRIPTHANDLER=y |
| 989 | # We need the bootloader handler to alter the u-boot environment |
| 990 | CONFIG_BOOTLOADERHANDLER=y |
| 991 | EOF |
| 992 | }}} |
| 993 | * Note: The "BR2_PACKAGE_SWUPDATE_CONFIG=" Buildroot config argument could potenially point to an existing file, edit this peramater using menuconfig to point to the file you're creating here. |
| 994 | * '''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 |
| 995 | {{{#!bash |
| 996 | cat << EOF > sw-description |
| 997 | software = |
| 998 | { |
| 999 | version = "0.1.0"; |
| 1000 | description = "Firmware update for XXXXX Project"; |
| 1001 | |
| 1002 | /* images installed to the system */ |
| 1003 | images: ( |
| 1004 | { |
| 1005 | filename = "venice_swupdate.ext2.gz"; |
| 1006 | device = "/dev/update"; |
| 1007 | type = "raw"; |
| 1008 | sha256 = "b443d32b1f2036d731a423f1c9fd6c05731eb107b48b84bc42be95c0c7b31f03"; |
| 1009 | compressed = true; |
| 1010 | } |
| 1011 | ); |
| 1012 | |
| 1013 | scripts: ( |
| 1014 | { |
| 1015 | filename = "update.sh"; |
| 1016 | type = "shellscript"; |
| 1017 | sha256 = "80463da620c42e02f51b360a33a34d0f180992cbd398c0ea6db0a5d838fa3739"; |
| 1018 | } |
| 1019 | ); |
| 1020 | } |
| 1021 | EOF |
| 1022 | }}} |
| 1023 | * Note: You will need to generate your own sha256, use the "sha256sum" command to do this. Check that your filename is accurate. |
| 1024 | |
| 1025 | - '''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. |
| 1026 | {{{#!bash |
| 1027 | #!/bin/sh |
| 1028 | cat << EOF > sw-descrption |
| 1029 | if [ $# -lt 1 ]; then |
| 1030 | exit 0; |
| 1031 | fi |
| 1032 | |
| 1033 | function get_current_root_device |
| 1034 | { |
| 1035 | for i in `cat /proc/cmdline`; do |
| 1036 | if [ ${i:0:5} = "root=" ]; then |
| 1037 | CURRENT_ROOT="${i:5}" |
| 1038 | fi |
| 1039 | done |
| 1040 | } |
| 1041 | |
| 1042 | # ping-pong between /dev/mmcblk2p1 and /dev/mmcblk2p2 |
| 1043 | # (adapt for your partitioning scheme and/or root device type) |
| 1044 | function get_update_part |
| 1045 | { |
| 1046 | CURRENT_PART="${CURRENT_ROOT:-/dev/mmcblk2p1}" |
| 1047 | if [ $CURRENT_PART = "/dev/mmcblk2p1" ]; then |
| 1048 | UPDATE_PART="2"; |
| 1049 | else |
| 1050 | UPDATE_PART="1"; |
| 1051 | fi |
| 1052 | } |
| 1053 | |
| 1054 | function get_update_device |
| 1055 | { |
| 1056 | UPDATE_ROOT=${CURRENT_ROOT%?}${UPDATE_PART} |
| 1057 | } |
| 1058 | |
| 1059 | |
| 1060 | if [ $1 == "preinst" ]; then |
| 1061 | # get the current root device |
| 1062 | get_current_root_device |
| 1063 | |
| 1064 | # get the device to be updated |
| 1065 | get_update_part |
| 1066 | get_update_device |
| 1067 | |
| 1068 | # create a symlink for the update process |
| 1069 | ln -sf $UPDATE_ROOT /dev/update |
| 1070 | fi |
| 1071 | |
| 1072 | if [ $1 == "postinst" ]; then |
| 1073 | # get the current root device |
| 1074 | get_current_root_device |
| 1075 | |
| 1076 | # get the device to be updated |
| 1077 | get_update_part |
| 1078 | get_update_device |
| 1079 | |
| 1080 | # toggle rootpart |
| 1081 | # we do it twice to write to both primary/secondary env |
| 1082 | fw_setenv mmcbootpart $UPDATE_PART |
| 1083 | fw_setenv mmcbootpart $UPDATE_PART |
| 1084 | fi |
| 1085 | EOF |
| 1086 | }}} |
| 1087 | |
| 1088 | * '''With these files created proceed with the build:''' |
| 1089 | {{{#!bash |
| 1090 | # build buildroot rootfs |
| 1091 | make venice_swupdate_defconfig |
| 1092 | make |
| 1093 | # create a private/public key combo for signature verifcation |
| 1094 | openssl genrsa -out swupdate-priv.pem # private |
| 1095 | openssl rsa -in swupdate-priv.pem -out swupdate-public.pem -outform PEM -pubout # public |
| 1096 | # sign the sw-description |
| 1097 | openssl dgst -sha256 -sign swupdate-priv.pem sw-description > sw-description.sig |
| 1098 | # build swupdate image |
| 1099 | cp output/images/rootfs.ext2.gz ./venice_swupdate.ext2.gz |
| 1100 | for i in sw-description sw-description.sig update.sh venice_swupdate.ext2.gz; do |
| 1101 | echo $i; done | cpio -ov -H crc > my-software.swu |
| 1102 | }}} |
| 1103 | * Note that you can skip the inclusion of sw-description.sig and the pub/priv key if you don't care about signatures and have not define CONFIG_SIGNED_IMAGES in your swupdate.config |
| 1104 | * '''create an MBR partition table that defines LinuxA and LinuxB partitions we will ping-pong between.''' |
| 1105 | {{{#!bash |
| 1106 | # 1: 32768:4194304 (2GiB) LinuxA |
| 1107 | # 2: 4227072:4194304 (2GiB) LinuxB |
| 1108 | # 3: 8421376:4194304(2GiB) userdata |
| 1109 | wget -q https://raw.githubusercontent.com/Gateworks/bsp-newport/sdk-10.1.1.0-newport/ptgen |
| 1110 | /bin/bash ptgen \ |
| 1111 | -p 0x83:32768:4194304 \ |
| 1112 | -p 0x83:4227072:4194304 \ |
| 1113 | -p 0x83:8421376:4194304 \ |
| 1114 | > output/images/mbr.bin |
| 1115 | }}} |
| 1116 | * Note: How did we arive at these values? "0x83" is the Linux partition type, "32768" is 16MB (the boot firmware offset) in 512 byte blocks, "4194304" is 2GiB in 512 byte blocks, this will be the length of the partition, "4227072" is the offset plus the length of the partition, this is where the next partion will start. |
| 1117 | * Bonus fact, here's a way to calculate these values on the command line: |
| 1118 | {{{#!bash |
| 1119 | echo $((16*1024*1024)) # 16MB in bytes |
| 1120 | echo $((16*1024*1024/512)) # to 512 byte blocks. |
| 1121 | printf "0x%x\n" $((16*1024*1024)) # to hex |
| 1122 | }}} |
| 1123 | * '''Boot the board, break out in the bootlader, then update the partition table:''' |
| 1124 | {{{#!bash |
| 1125 | tftpboot ${loadaddr} mbr.bin && mmc dev 2 && mmc write ${loadaddr} 0 1 # mbr is at 0 and 1 sector long |
| 1126 | }}} |
| 1127 | * '''While in U-Boot install the Buildroot rootfs to the first Linux partition offset (LinuxA)''' |
| 1128 | {{{#!bash |
| 1129 | tftpboot ${loadaddr} venice_swupdate.ext2.gz && gzwrite mmc 0 ${loadaddr} ${filesize} 0x100000 0x2000000 # rootfsA is at 0x2000000 (32MiB) and we use a 1MiB buffer |
| 1130 | }}} |
| 1131 | * '''In U-Boot set the env to use the ''mmcbootpart'' variable that our update.sh will need in order to toggle the partition after a successful update. Custom bootargs will also be applied in this step.''' |
| 1132 | {{{#!bash |
| 1133 | setenv mmcbootpart 2 |
| 1134 | |
| 1135 | setenv bootcmd 'setenv bootargs console=${console} root=/dev/mmcblk2p${mmcbootpart} rootwait rw; setenv fsload load mmc 2:${mmcbootpart}; setenv dir /boot; run loadfdt && $fsload ${kernel_addr_r} boot/Image && booti ${kernel_addr_r} - ${fdt_addr_r}' |
| 1136 | |
| 1137 | saveenv |
| 1138 | }}} |
| 1139 | - Note the single quotes around the bootargs value as we do not want U-Boot to expand the args until runtime |
| 1140 | |
| 1141 | * '''After you boot to buildroot you can fetch and install the SWUpdate image with:''' |
| 1142 | {{{#!bash |
| 1143 | # bring up networking |
| 1144 | udhcpc -i eth0 |
| 1145 | # fetch image |
| 1146 | cd /tmp |
| 1147 | wget http://myserver/my-software.swu |
| 1148 | wget http://myserver/swupdate-public.pem |
| 1149 | swupdate -i my-software.swu -k swupdate-public.pem |
| 1150 | }}} |
| 1151 | * Note that you can skip the -k param have not enabled signed images via CONFIG_SIGNED_IMAGES in your swupdate.config |
| 1152 | |
| 1153 | '''If you would like these files pre-compiled, download them [http://dev.gateworks.com/fae/swupdate-files.tar.gz Here].''' |
| 1154 | |
| 1155 | |