# Firmware configuration file for the PcEngines Alix (Geode)

define(FINALIZE_FW, "/tmp/finalize.fw")

# 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 3 partitions:
#
# +----------------------------+
# | MBR                    |
# +----------------------------+
# | Boot partition (FAT16)     |
# | syslinux.cfg           |
# | bzImage                |
# +----------------------------+
# | p1*: Rootfs A (squashfs)   |
# +----------------------------+
# | p1*: Rootfs B (squashfs)   |
# +----------------------------+
# | p2: Application (FAT32)    |
# +----------------------------+
#
# The p1 partition points to whichever of Rootfs A or B that
# is active.

# The boot partition contains syslinux, 2 Linux kernels,
# and the bootloader configuration. 16 MB should be plenty.
define(BOOT_PART_OFFSET, 63)
define(BOOT_PART_COUNT, 31232)

# Let the rootfs have room to grow up to 128 MiB
define(ROOTFS_A_PART_OFFSET, 32768)
define(ROOTFS_A_PART_COUNT, 262144)
define(ROOTFS_B_PART_OFFSET, 294912)
define(ROOTFS_B_PART_COUNT, 262144)

# Application partition. This partition can occupy all of the
# remaining space. Size it to fit the destination.
define(APP_PART_OFFSET, 557056)
define(APP_PART_COUNT, 2097152)

# Firmware metadata
meta-product = "Nerves Firmware"
meta-description = ""
meta-version = ${NERVES_SDK_VERSION}
meta-platform = "alix"
meta-architecture = "x86"
meta-author = "Frank Hunleth"

# File resources are listed in the order that they are included in the .fw file
# This is important, since this is the order that they're written on a firmware
# update due to the event driven nature of the update system.
file-resource bootpart.bin {
    host-path = "${NERVES_SYSTEM}/images/bootpart.bin"
}
file-resource syslinux.cfg {
    host-path = "${NERVES_SYSTEM}/images/syslinux.cfg"
}
file-resource bzImage {
    host-path = "${NERVES_SYSTEM}/images/bzImage"
}
file-resource rootfs.img {
    host-path = ${ROOTFS}
}

mbr mbr-a {
    bootstrap-code-host-path = "${NERVES_SYSTEM}/images/syslinux/mbr.bin"
    partition 0 {
        block-offset = ${BOOT_PART_OFFSET}
        block-count = ${BOOT_PART_COUNT}
        type = 0x1 # FAT12
        boot = true
    }
    partition 1 {
        block-offset = ${ROOTFS_A_PART_OFFSET}
        block-count = ${ROOTFS_A_PART_COUNT}
        type = 0x83 # Linux
    }
    partition 2 {
        block-offset = ${APP_PART_OFFSET}
        block-count = ${APP_PART_COUNT}
        type = 0xc # FAT32
    }
    # partition 3 is unused
}

mbr mbr-b {
    bootstrap-code-host-path = "${NERVES_SYSTEM}/images/syslinux/mbr.bin"
    partition 0 {
        block-offset = ${BOOT_PART_OFFSET}
        block-count = ${BOOT_PART_COUNT}
        type = 0x1 # FAT12
        boot = true
    }
    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 = 0xc # FAT32
    }
    # partition 3 is unused
}

# This firmware task writes everything to the destination media
task complete {
    # Only match if not mounted
    require-unmounted-destination = true

    # Everything that gets written can be verified on the fly.
    # This speeds things up, since we don't care about detecting
    # errors before data gets written.
    verify-on-the-fly = true

    on-init {
        mbr_write(mbr-a)
    }

    on-resource bootpart.bin { raw_write(${BOOT_PART_OFFSET}) }
    on-resource syslinux.cfg { fat_write(${BOOT_PART_OFFSET}, "syslinux.cfg") }
    on-resource bzImage { fat_write(${BOOT_PART_OFFSET}, "bzImage") }

    on-resource rootfs.img {
        # write to the first rootfs partition
        raw_write(${ROOTFS_A_PART_OFFSET})
    }

    on-finish {
        # Initialize the app partition last so that the boot
        # partition can be written in one go.
        fat_mkfs(${APP_PART_OFFSET}, ${APP_PART_COUNT})
        fat_setlabel(${APP_PART_OFFSET}, "APPDATA")
    }
}

task upgrade.a {
    # This task upgrades the A partition
    require-partition1-offset = ${ROOTFS_B_PART_OFFSET}

    # Since the upgrade won't run until it has been finalized, it's ok
    # to write data as it is read.
    verify-on-the-fly = true

    on-init {
        # Erase any old saved files from previous upgrades
        fat_rm(${BOOT_PART_OFFSET}, "bzImage.pre")
    }

    on-resource zImage {
        fat_write(${BOOT_PART_OFFSET}, "bzImage.new")
    }

    on-resource rootfs.img {
        # write to the first rootfs partition
        raw_write(${ROOTFS_A_PART_OFFSET})
    }

    on-finish {
	# Switch over to boot the new firmware
        mbr_write(mbr-a)
        fat_mv(${BOOT_PART_OFFSET}, "bzImage", "bzImage.pre")
        fat_mv(${BOOT_PART_OFFSET}, "bzImage.new", "bzImage")
    }

    on-error {
        # Clean up in case something goes wrong
        fat_rm(${BOOT_PART_OFFSET}, "bzImage.new")
    }
}

task upgrade.b {
    # This task upgrades the B partition
    require-partition1-offset = ${ROOTFS_A_PART_OFFSET}

    # Since the upgrade won't run until it has been finalized, it's ok
    # to write data as it is read.
    verify-on-the-fly = true

    on-init {
        fat_rm(${BOOT_PART_OFFSET}, "bzImage.pre")
    }

    on-resource zImage { fat_write(${BOOT_PART_OFFSET}, "bzImage.new") }

    on-resource rootfs.img {
        # write to the first rootfs partition
        raw_write(${ROOTFS_B_PART_OFFSET})
    }

    on-finish {
	# Switch over to boot the new firmware
        mbr_write(mbr-b)
        fat_mv(${BOOT_PART_OFFSET}, "bzImage", "bzImage.pre")
        fat_mv(${BOOT_PART_OFFSET}, "bzImage.new", "bzImage")
    }

    on-error {
        # Clean up in case something goes wrong
        fat_rm(${BOOT_PART_OFFSET}, "bzImage.new")
    }
}
