# Firmware configuration file for the GRiSP 2 require-fwup-version="1.0.0" # # Firmware metadata # # All of these can be overriden using environment variables of the same name. # # Run 'fwup -m' to query values in a .fw file. # Use 'fw_printenv' to query values on the target. # # These are used by Nerves libraries to introspect. define(NERVES_FW_PRODUCT, "Nerves Firmware") define(NERVES_FW_DESCRIPTION, "") define(NERVES_FW_VERSION, "${NERVES_SDK_VERSION}") define(NERVES_FW_PLATFORM, "grisp2") define(NERVES_FW_ARCHITECTURE, "arm") define(NERVES_FW_AUTHOR, "The Nerves Team") define(NERVES_FW_DEVPATH, "/dev/rootdisk0") define(NERVES_FW_APPLICATION_PART0_DEVPATH, "/dev/rootdisk0p3") # Linux part number is 1-based define(NERVES_FW_APPLICATION_PART0_FSTYPE, "f2fs") define(NERVES_FW_APPLICATION_PART0_TARGET, "/root") define(NERVES_PROVISIONING, "${NERVES_SYSTEM}/images/fwup_include/provisioning.conf") # Default paths if not specified via the commandline define(ROOTFS, "${NERVES_SYSTEM}/images/rootfs.squashfs") # This configuration file will create an image that has an MBR and the # following layout in GRiSPv2's ~4 GB eMMC: # # +----------------------------+ # | MBR | # +----------------------------+ # | Barebox (#1-1791) | # +----------------------------+ # | Barebox env (#1792-2047) | # +----------------------------+ # | U-Boot environment | # +----------------------------+ # | p1: RootFS A (squashfs) | # +----------------------------+ # | p2: RootFS B (squashfs) | # +----------------------------+ # | p3: Application (f2fs) | # +----------------------------+ # # The Barebox, and RootFS locations match the GRiSPv2 eMMC layout # See https://github.com/grisp/grisp_demo/blob/sylane/make-image/make_image.sh # # Nerves currently keeps its boot state in the U-Boot environment block that # immediately preceeds the rootfs partitions. The application data paration # immediately follow the partitions. This area is currently unspecified for the # GRiSP2. # Nerves state define(UBOOT_ENV_OFFSET, 7936) define(UBOOT_ENV_COUNT, 256) # 128 KB # Match the GRiSPv2 eMMC layout # See https://github.com/grisp/grisp_demo/blob/sylane/make-image/make_image.sh define(ROOTFS_A_PART_OFFSET, 8192) define(ROOTFS_A_PART_COUNT, 524288) define(ROOTFS_B_PART_OFFSET, 532480) define(ROOTFS_B_PART_COUNT, ${ROOTFS_A_PART_COUNT}) # 2.5G Application partition define-eval(APP_PART_OFFSET, "${ROOTFS_B_PART_OFFSET} + ${ROOTFS_B_PART_COUNT}") define(APP_PART_COUNT, 5242880) # Firmware archive metadata meta-product = ${NERVES_FW_PRODUCT} meta-description = ${NERVES_FW_DESCRIPTION} meta-version = ${NERVES_FW_VERSION} meta-platform = ${NERVES_FW_PLATFORM} meta-architecture = ${NERVES_FW_ARCHITECTURE} meta-author = ${NERVES_FW_AUTHOR} meta-vcs-identifier = ${NERVES_FW_VCS_IDENTIFIER} meta-misc = ${NERVES_FW_MISC} file-resource barebox { host-path = "${NERVES_SYSTEM}/images/barebox-phytec-phycore-imx6ul-emmc-512mb.img" } file-resource uboot-env.bin { host-path = "${NERVES_SYSTEM}/images/uboot-env.bin" } file-resource rootfs.img { host-path = ${ROOTFS} # Error out if the rootfs size exceeds the partition size assert-size-lte = ${ROOTFS_A_PART_COUNT} } mbr mbr { partition 0 { block-offset = ${ROOTFS_A_PART_OFFSET} block-count = ${ROOTFS_A_PART_COUNT} type = 0x83 # Linux } partition 1 { block-offset = ${ROOTFS_B_PART_OFFSET} block-count = ${ROOTFS_B_PART_COUNT} type = 0x83 # Linux } partition 2 { block-offset = ${APP_PART_OFFSET} block-count = ${APP_PART_COUNT} type = 0x83 # Linux expand = true } } # Location where installed firmware information is stored. uboot-environment uboot-env { block-offset = ${UBOOT_ENV_OFFSET} block-count = ${UBOOT_ENV_COUNT} } # This firmware task writes everything to the destination media. # This should only be run at the factory to initialize a board! task complete { # Only match if not mounted require-unmounted-destination = true on-init { } on-resource barebox { # The Barebox image starts at the beginning of the eMMC, but doesn't # have the desired MBR. raw_write(0) mbr_write(mbr) } on-resource uboot-env.bin { # Boot to the A partition first and don't fail back. # If this fails, we bricked the board with no recovery. raw_write(${UBOOT_ENV_OFFSET}) # Include provisioning instructions include("${NERVES_PROVISIONING}") # Add in the generic Nerves metadata variables. uboot_setenv(uboot-env, "nerves_fw_active", "a") uboot_setenv(uboot-env, "nerves_fw_devpath", ${NERVES_FW_DEVPATH}) uboot_setenv(uboot-env, "a.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH}) uboot_setenv(uboot-env, "a.nerves_fw_application_part0_fstype", ${NERVES_FW_APPLICATION_PART0_FSTYPE}) uboot_setenv(uboot-env, "a.nerves_fw_application_part0_target", ${NERVES_FW_APPLICATION_PART0_TARGET}) uboot_setenv(uboot-env, "a.nerves_fw_product", ${NERVES_FW_PRODUCT}) uboot_setenv(uboot-env, "a.nerves_fw_description", ${NERVES_FW_DESCRIPTION}) uboot_setenv(uboot-env, "a.nerves_fw_version", ${NERVES_FW_VERSION}) uboot_setenv(uboot-env, "a.nerves_fw_platform", ${NERVES_FW_PLATFORM}) uboot_setenv(uboot-env, "a.nerves_fw_architecture", ${NERVES_FW_ARCHITECTURE}) uboot_setenv(uboot-env, "a.nerves_fw_author", ${NERVES_FW_AUTHOR}) uboot_setenv(uboot-env, "a.nerves_fw_vcs_identifier", ${NERVES_FW_VCS_IDENTIFIER}) uboot_setenv(uboot-env, "a.nerves_fw_misc", ${NERVES_FW_MISC}) uboot_setenv(uboot-env, "a.nerves_fw_uuid", "\${FWUP_META_UUID}") } on-resource rootfs.img { # write to the first rootfs partition raw_write(${ROOTFS_A_PART_OFFSET}) } on-finish { } } task upgrade.a { # This task upgrades the A partition require-uboot-variable(uboot-env, "nerves_fw_active", "b") # Require that the running version of firmware has been validated. # If it has not, then failing back is not guaranteed to work. require-uboot-variable(uboot-env, "nerves_fw_validated", "1") # Verify the expected platform/architecture require-uboot-variable(uboot-env, "b.nerves_fw_platform", "${NERVES_FW_PLATFORM}") require-uboot-variable(uboot-env, "b.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}") on-init { info("Upgrading partition A") # Clear some firmware information just in case this update gets # interrupted midway. If this partition was bootable, it's not going to # be soon. uboot_unsetenv(uboot-env, "a.nerves_fw_version") uboot_unsetenv(uboot-env, "a.nerves_fw_platform") uboot_unsetenv(uboot-env, "a.nerves_fw_architecture") uboot_unsetenv(uboot-env, "a.nerves_fw_uuid") # Indicate that the entire partition can be cleared trim(${ROOTFS_A_PART_OFFSET}, ${ROOTFS_A_PART_COUNT}) } # Write the new firmware, but don't commit them. That way if the user # aborts midway, we still are using the original firmware. on-resource rootfs.img { delta-source-raw-offset=${ROOTFS_B_PART_OFFSET} delta-source-raw-count=${ROOTFS_B_PART_COUNT} raw_write(${ROOTFS_A_PART_OFFSET}) } on-finish { # Update firmware metadata uboot_setenv(uboot-env, "a.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH}) uboot_setenv(uboot-env, "a.nerves_fw_application_part0_fstype", ${NERVES_FW_APPLICATION_PART0_FSTYPE}) uboot_setenv(uboot-env, "a.nerves_fw_application_part0_target", ${NERVES_FW_APPLICATION_PART0_TARGET}) uboot_setenv(uboot-env, "a.nerves_fw_product", ${NERVES_FW_PRODUCT}) uboot_setenv(uboot-env, "a.nerves_fw_description", ${NERVES_FW_DESCRIPTION}) uboot_setenv(uboot-env, "a.nerves_fw_version", ${NERVES_FW_VERSION}) uboot_setenv(uboot-env, "a.nerves_fw_platform", ${NERVES_FW_PLATFORM}) uboot_setenv(uboot-env, "a.nerves_fw_architecture", ${NERVES_FW_ARCHITECTURE}) uboot_setenv(uboot-env, "a.nerves_fw_author", ${NERVES_FW_AUTHOR}) uboot_setenv(uboot-env, "a.nerves_fw_vcs_identifier", ${NERVES_FW_VCS_IDENTIFIER}) uboot_setenv(uboot-env, "a.nerves_fw_misc", ${NERVES_FW_MISC}) uboot_setenv(uboot-env, "a.nerves_fw_uuid", "\${FWUP_META_UUID}") # Reset the validation status and boot to A # next time. uboot_setenv(uboot-env, "nerves_fw_active", "a") uboot_setenv(uboot-env, "nerves_fw_validated", "0") uboot_setenv(uboot-env, "nerves_fw_booted", "0") } on-error { } } task upgrade.b { # This task upgrades the B partition require-uboot-variable(uboot-env, "nerves_fw_active", "a") require-uboot-variable(uboot-env, "nerves_fw_validated", "1") # Verify the expected platform/architecture require-uboot-variable(uboot-env, "a.nerves_fw_platform", "${NERVES_FW_PLATFORM}") require-uboot-variable(uboot-env, "a.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}") on-init { info("Upgrading partition B") # Clear some firmware information just in case this update gets # interrupted midway. uboot_unsetenv(uboot-env, "b.nerves_fw_version") uboot_unsetenv(uboot-env, "b.nerves_fw_platform") uboot_unsetenv(uboot-env, "b.nerves_fw_architecture") uboot_unsetenv(uboot-env, "b.nerves_fw_uuid") trim(${ROOTFS_B_PART_OFFSET}, ${ROOTFS_B_PART_COUNT}) } on-resource rootfs.img { delta-source-raw-offset=${ROOTFS_A_PART_OFFSET} delta-source-raw-count=${ROOTFS_A_PART_COUNT} raw_write(${ROOTFS_B_PART_OFFSET}) } on-finish { # Update firmware metadata uboot_setenv(uboot-env, "b.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH}) uboot_setenv(uboot-env, "b.nerves_fw_application_part0_fstype", ${NERVES_FW_APPLICATION_PART0_FSTYPE}) uboot_setenv(uboot-env, "b.nerves_fw_application_part0_target", ${NERVES_FW_APPLICATION_PART0_TARGET}) uboot_setenv(uboot-env, "b.nerves_fw_product", ${NERVES_FW_PRODUCT}) uboot_setenv(uboot-env, "b.nerves_fw_description", ${NERVES_FW_DESCRIPTION}) uboot_setenv(uboot-env, "b.nerves_fw_version", ${NERVES_FW_VERSION}) uboot_setenv(uboot-env, "b.nerves_fw_platform", ${NERVES_FW_PLATFORM}) uboot_setenv(uboot-env, "b.nerves_fw_architecture", ${NERVES_FW_ARCHITECTURE}) uboot_setenv(uboot-env, "b.nerves_fw_author", ${NERVES_FW_AUTHOR}) uboot_setenv(uboot-env, "b.nerves_fw_vcs_identifier", ${NERVES_FW_VCS_IDENTIFIER}) uboot_setenv(uboot-env, "b.nerves_fw_misc", ${NERVES_FW_MISC}) uboot_setenv(uboot-env, "b.nerves_fw_uuid", "\${FWUP_META_UUID}") # Reset the validation status and boot to B next time. uboot_setenv(uboot-env, "nerves_fw_active", "b") uboot_setenv(uboot-env, "nerves_fw_validated", "0") uboot_setenv(uboot-env, "nerves_fw_booted", "0") } on-error { } } task upgrade.unvalidated { require-uboot-variable(uboot-env, "nerves_fw_validated", "0") on-init { error("Please validate the running firmware before upgrading it again.") } } task upgrade.unexpected { require-uboot-variable(uboot-env, "a.nerves_fw_platform", "${NERVES_FW_PLATFORM}") require-uboot-variable(uboot-env, "a.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}") on-init { error("Please check the media being upgraded. It doesn't look like either the A or B partitions are active.") } } task upgrade.wrongplatform { on-init { error("Expecting platform=${NERVES_FW_PLATFORM} and architecture=${NERVES_FW_ARCHITECTURE}") } }