diff --git a/Dockerfile b/Dockerfile index 43a8272..8368dcc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,10 @@ -FROM debian:buster AS uboot +FROM debian:buster AS build_base RUN apt-get update && \ apt-get install -y build-essential git wget bison flex gcc-arm-linux-gnueabi device-tree-compiler bc +FROM build_base AS uboot + RUN mkdir /uboot_build/ && \ mkdir /uboot/ @@ -43,6 +45,12 @@ RUN make CROSS_COMPILE=arm-linux-gnueabi- distclean && \ make CROSS_COMPILE=arm-linux-gnueabi- -j8 u-boot.bin && \ cp u-boot.bin /uboot/u-boot_rpi4.bin +FROM build_base AS uboot_tool + +ADD ./resources/uboot.c /uboot.c + +RUN arm-linux-gnueabi-gcc -Wall -static -static-libgcc -o /uboot_tool /uboot.c + FROM alpine:3.10 @@ -70,5 +78,6 @@ RUN cd /genext2fs && \ ADD ./resources /resources COPY --from=uboot /uboot/ /uboot/ +COPY --from=uboot_tool /uboot_tool /uboot_tool WORKDIR /work diff --git a/resources/boot.cmd b/resources/boot.cmd index d847b0d..eae7524 100644 --- a/resources/boot.cmd +++ b/resources/boot.cmd @@ -1,46 +1,106 @@ +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # static config -setenv boot_partition_a 2 -setenv boot_partition_b 3 -setenv boot_limit 2 +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +setenv boot_partition_a 0x02 +setenv boot_partition_b 0x03 +setenv boot_limit 0x02 setenv boot_partition_base "/dev/mmcblk0p" +setenv addr_version 0x10000 +setenv addr_boot_counter 0x10001 +setenv addr_boot_partition 0x10002 -# set default values if env not set -if printenv boot_count; then -else - setenv boot_count 1 +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# load persistence values +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# clear memory +mw.b 0x10000 0 0x404 + +# load uboot file +fatload mmc 0:1 0x10000 uboot.dat 0x400 + +# check CRC +crc32 0x10000 0x3FC 0x10400 +if itest *0x103FC -ne *0x10400; then + echo "invalid CRC -> fallback to default values" + + # default values + mw.b ${addr_version} 0x01 + mw.b ${addr_boot_counter} 0x00 + mw.b ${addr_boot_partition} ${boot_partition_a} fi -if printenv boot_partition; then - # check if valid partition a or b - if test ${boot_partition} -ne ${boot_partition_a} && test ${boot_partition} -ne ${boot_partition_b}; then - setenv boot_partition ${boot_partition_a} - fi -else - setenv boot_partition ${boot_partition_a} +# ensure boot partition is valid +if itest.b *${addr_boot_partition} -ne ${boot_partition_a} && test.b *${addr_boot_partition} -ne ${boot_partition_b}; then + mw.b ${addr_boot_partition} ${boot_partition_a} fi +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# fallback boot +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +echo "Check fallback boot" # switch boot partition if boot count exceed limit -if test ${boot_count} -ge ${boot_limit}; then +if itest.b *${addr_boot_counter} -ge ${boot_limit}; then echo "!!! Boot limit exceed !!!" - if test ${boot_partition} -eq ${boot_partition_a}; then - setenv boot_partition ${boot_partition_b} + if itest *${addr_boot_partition} -eq ${boot_partition_a}; then + mv.b ${addr_boot_partition} ${boot_partition_b} else - setenv boot_partition ${boot_partition_a} + mv.b ${addr_boot_partition} ${boot_partition_a} fi - setenv boot_count 0 + mw.b ${addr_boot_counter} 0 + setexpr.b boot_partition *${addr_boot_partition} echo "Switch active partition to ${boot_partition_base}${boot_partition}" +else + # increase boot_count + setexpr.b tmp *${addr_boot_counter} + 1 + mw.b ${addr_boot_counter} ${tmp} + + setexpr.b boot_partition *${addr_boot_partition} fi -# increase boot_count -setexpr boot_count ${boot_count} + 1 -# store settings -saveenv +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# store persistence values +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# overwrite version +mw.b 0x10000 0x01 + +# calculate crc +crc32 0x10000 0x3FC 0x103FC + +# save to uboot file +fatwrite mmc 0:1 0x10000 uboot.dat 0x400 + + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# select kernel +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +echo "select kernel" +setenv boot_kernel "/boot/uImage" + +# only if new pi a new kernel is required +setexpr board_new_pi ${board_revision} \& 0x800000 +if test ${board_new_pi} > 0; then + echo "new board" + # get cpu id from revision + setexpr board_cpu ${board_revision} \& 0xF000 + + # at the moment CPU except the oldest need the new kernel + if test ${board_cpu} > 0x0000; then + setenv boot_kernel "/boot/uImage2" + fi +else + echo "old board" +fi +echo "Load kernel ${boot_kernel}" + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# boot +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # load bootargs from pi boot loader fdt addr ${fdt_addr} && fdt get value bootargs /chosen bootargs @@ -48,7 +108,7 @@ fdt addr ${fdt_addr} && fdt get value bootargs /chosen bootargs setexpr bootargs sub " root=[^ ]+" " root=${boot_partition_base}${boot_partition}" "${bootargs}" # load kernel and boot -ext4load mmc 0:${boot_partition} ${kernel_addr_r} /boot/uImage +ext4load mmc 0:${boot_partition} ${kernel_addr_r} ${boot_kernel} bootm ${kernel_addr_r} - ${fdt_addr} -reset \ No newline at end of file +reset diff --git a/resources/build.sh b/resources/build.sh index ac4c1da..505a0ee 100755 --- a/resources/build.sh +++ b/resources/build.sh @@ -12,8 +12,8 @@ set -e : ${DEFAULT_ROOT_PASSWORD:="alpine"} : ${SIZE_BOOT:="100M"} -: ${SIZE_ROOT_FS:="150M"} -: ${SIZE_ROOT_PART:="250M"} +: ${SIZE_ROOT_FS:="200M"} +: ${SIZE_ROOT_PART:="500M"} : ${SIZE_DATA:="20M"} : ${IMG_NAME:="alpine-${ALPINE_BRANCH}-sdcard"} @@ -22,7 +22,7 @@ set -e # static config # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # RES_PATH=/resources/ -BASE_PACKAGES="alpine-base tzdata parted ifupdown e2fsprogs-extra util-linux coreutils linux-rpi2 uboot-tools openntpd" +BASE_PACKAGES="alpine-base tzdata parted ifupdown e2fsprogs-extra util-linux coreutils linux-rpi linux-rpi2" WORK_PATH="/work" OUTPUT_PATH="/output" @@ -139,20 +139,12 @@ mkdir -p ${ROOTFS_PATH}/dev/shm mkdir -p ${ROOTFS_PATH}/var/lock # time -chroot_exec rc-update add openntpd default -cat >${ROOTFS_PATH}/etc/conf.d/openntpd <${ROOTFS_PATH}/etc/ntpd.conf <${ROOTFS_PATH}/etc/fw_env.config <${ROOTFS_PATH}/etc/local.d/99-uboot.start <> Move persistent data to /data" @@ -248,7 +243,8 @@ ln -fs /data/etc/shadow ${ROOTFS_PATH}/etc/shadow echo ">> Prepare kernel for uboot" # build uImage -mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n "Linux kernel" -d ${ROOTFS_PATH}/boot/vmlinuz-rpi2 ${ROOTFS_PATH}/boot/uImage +mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n "Linux kernel" -d ${ROOTFS_PATH}/boot/vmlinuz-rpi ${ROOTFS_PATH}/boot/uImage +mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n "Linux kernel" -d ${ROOTFS_PATH}/boot/vmlinuz-rpi2 ${ROOTFS_PATH}/boot/uImage2 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # diff --git a/resources/scripts/ab_flash b/resources/scripts/ab_flash index 034210c..def73a3 100755 --- a/resources/scripts/ab_flash +++ b/resources/scripts/ab_flash @@ -19,10 +19,8 @@ current_idx=$(rdev | sed 's#/dev/mmcblk0p\([^ ]*\).*#\1#') if [ $current_idx -eq 2 ]; then echo "Start update for partition B" - flash_idx=3 else echo "Start update for partition A" - flash_idx=2 fi flash_device="/dev/mmcblk0p${flash_idx}" @@ -33,7 +31,7 @@ gunzip -c ${image_file} | dd of=${flash_device} status=progress # switch active partition mount -o remount,rw /uboot -fw_setenv boot_partition ${flash_idx} +/sbin/uboot_tool part_switch sync mount -o remount,ro /uboot diff --git a/resources/uboot.c b/resources/uboot.c new file mode 100644 index 0000000..d58e8d5 --- /dev/null +++ b/resources/uboot.c @@ -0,0 +1,125 @@ +#include +#include +#include + +char* uboot_file = "/uboot/uboot.dat"; + + +void printHelp() { + printf("Usage: uboot_tool [COMMAND]\n"); + printf("\n"); + printf("Commands:\n"); + printf(" part_current - show current partition\n"); + printf(" part_switch - switch active partition\n"); + printf(" reset_counter - reset boot counter\n"); + printf(" version - show version of file\n"); +} + +uint32_t crc32(uint8_t* data, size_t length, uint32_t seed) { + uint32_t crc = ~seed; + while (length--) { + crc ^= (*data++); + for (unsigned int j = 0; j < 8; j++) { + if (crc & 1) { + crc = (crc >> 1) ^ 0xedb88320L; + } else { + crc = crc >> 1; + } + } + } + return ~crc; +} + +int main(int argc, char* argv[]) { + // show help if no command given + if (argc < 2) { + printHelp(); + return 1; + } + char* cmd = argv[1]; + + // read uboot file + FILE* file = fopen(uboot_file, "rb"); + if (file == NULL) { + printf("Failed to open uboot file: %s\n", uboot_file); + return 2; + } + uint8_t data[1024]; + size_t err = fread(data, 1, sizeof(data), file); + if (err == 0) { + printf("Failed to read uboot file: %s\n", uboot_file); + return 2; + } + fclose(file); + + // get crc from file + uint32_t crc = (data[1023] << 24) + + (data[1022] << 16) + + (data[1021] << 8) + + data[1020]; + + // check if CRC is valid + if (crc != crc32(data, 0x3FC, 0)) { + fprintf(stderr, "Invalid CRC -> fallback to default\n"); + + memset(data, 0, sizeof(data)); + + // file version + data[0] = 1; + + // boot counter + data[1] = 0; + + // boot partition + data[2] = 2; // A=2, B=3 + } + + // handle commands + uint8_t save = 0; + if (strcmp(cmd, "version") == 0) { + printf("0x%02x\n", data[0]); + + } else if (strcmp(cmd, "part_current") == 0) { + printf("%d\n", data[2]); + + } else if (strcmp(cmd, "part_switch") == 0) { + if (data[2] == 2) { + data[2] = 3; + } else { + data[2] = 2; + } + save = 1; + + } else if (strcmp(cmd, "reset_counter") == 0) { + data[1] = 0; + save = 1; + + } else { + printf("Unknown command\n"); + return 10; + } + + if (save == 1) { + // calculate new CRC + crc = crc32(data, 0x3FC, 0); + data[1023] = (uint8_t)((crc & 0xFF000000U)>>24); + data[1022] = (uint8_t)((crc & 0x00FF0000U)>>16); + data[1021] = (uint8_t)((crc & 0x0000FF00U)>>8); + data[1020] = (uint8_t)((crc & 0x000000FFU)); + + // write uboot file + file = fopen(uboot_file, "wb"); + if (file == NULL) { + printf("Failed to open uboot file: %s\n", uboot_file); + return 4; + } + size_t err = fwrite(data, 1, sizeof(data), file); + if (err == 0) { + printf("Failed to write uboot file: %s\n", uboot_file); + return 4; + } + fclose(file); + } + + return 0; +}