-
-
Save odyssey4me/bb2424b23d7a42b07d1fb949f2012613 to your computer and use it in GitHub Desktop.
Script to flash CHIP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# This script programs the CHIP's NAND flash using sunxi-tools' `fel` utiltiy, | |
# and U-Boot itself. The following tools must be present on the system: | |
# | |
# - dd (coreutils) | |
# - lsusb (usbutils) | |
# - fel (sunxi-tools) | |
# - mkimage (android-tools) | |
# | |
# The end result is the following flash layout: | |
# | |
# ======== ======== ============ ==================================== | |
# mtdpart size MB name description | |
# -------- -------- ------------ ------------------------------------ | |
# 0 4 spl Master SPL binary | |
# 1 4 spl-backup Backup SPL binary | |
# 3 4 uboot U-Boot binary | |
# 4 4 env U-Boot environment | |
# 5 8 linux Linux kernel zImage w/DTB | |
# 6 64 root Root filesystem ubi volume | |
# 7 64 root-backup Backup root filesystem ubi volume | |
# 8 32 overlay Root filesytem overlay ubi volume | |
# 9 600 cache Download | |
# 10 - data Application data | |
# ======== ======== ============ ==================================== | |
# | |
# Of the partitions in the table, 0 through 7 are flashed by this tool. The | |
# others are assumed to be created in the userspace during boot. | |
# | |
# The flashing works roughly like this: | |
# | |
# CHIP is put into FEL mode by jumping the FEL pin (3rd on U14L) to ground | |
# (first or last on U14L) during power-on. This allows the user to execute | |
# arbitrary bare-metal code on the Allwinner CPU. The `fel` tool is used to | |
# execute the SPL generated by the build (sunxi-spl.bin) and is then used to | |
# transfer the prepared files to DRAM on the board. One of the files that are | |
# transferred to the board's memory is a specially crafted U-Boot script that | |
# performs the transfer of the payload from memory to NAND flash. After all | |
# payloads are transferred to DRAM, the U-Boot binary in the memory is | |
# executed, which in turns runs the prepared U-Boot script. | |
# | |
# This file is part of rxOS. | |
# rxOS is free sofware licensed under the | |
# GNU GPL version 3 or any later version. | |
# | |
# (c) 2016 Outernet Inc | |
# Some rights reserved. | |
set -e | |
# Set-up | |
SCRIPTDIR="$(dirname "$0")" | |
. "$SCRIPTDIR/helpers.sh" | |
# Relevant paths | |
RXOS_DIR="$(cd "$SCRIPTDIR/../../"; pwd)" | |
HOST_DIR="$RXOS_DIR/out/host" | |
BINARIES_DIR="$RXOS_DIR/out/images" | |
TMPDIR= | |
# Execution parameters | |
TMPDIR_TEMPLATE="/tmp/chip-flash-XXXXXXX" | |
NAND_SIZE=0x100000000 # 4GB | |
CHIP_DEVID="0525:a4a7" | |
PAGE_SIZE=16384 | |
PAGE_SIZE_HEX=0x4000 | |
OOB_SIZE=1664 | |
# Source files | |
SPL="$BINARIES_DIR/sunxi-spl.bin" | |
UBOOT="$BINARIES_DIR/u-boot-dtb.bin" | |
UBOOT_ENV="$BINARIES_DIR/uboot-env.bin" | |
LINUX="$BINARIES_DIR/zImage.sun5i-r8-chip" | |
ROOTFS="$BINARIES_DIR/rootfs.ubifs.lzo" | |
# Memory locations | |
SPL_ADDR=0x43000000 | |
UBOOT_SCRIPT_ADDR=0x43100000 | |
UBOOT_ADDR=0x4a000000 | |
UBOOT_ENV_ADDR=0x4b000000 | |
LINUX_ADDR=0x4c000000 | |
ROOTFS_ADDR=0x4d000000 | |
# Offsets | |
SPL_OFF=0x0 # 0 +0 | |
SPL_BACKUP_OFF=0x40000 # 4M +4M | |
UBOOT_OFF=0x80000 # 8M +4M | |
UBOOT_ENV_OFF=0xC0000 # 12M +4M | |
LINUX_OFF=0x1000000 # 16M +4M | |
ROOTFS_OFF=0x1800000 # 24M +8M | |
ROOTFS_BACKUP_OFF=0x5800000 # 88M +64M | |
# Set path so Buildroot host utils can be reused | |
PATH="$HOST_DIR/bin":$PATH | |
# Abort with an error message | |
abort() { | |
local msg="$*" | |
echo "ERROR: $msg" | |
exit 1 | |
} | |
# Print usage | |
usage() { | |
echo "Usage: $0 [-htkD]" | |
echo | |
echo "Options:" | |
echo " -h Show this message and exit" | |
echo " -t Test mode: do not boot into the flashed system " | |
echo " (remain in U-boot)" | |
echo " -k Keep temporary directory" | |
echo " -D Dry run (do not perform any flashing, just echo" | |
echo " what the script would do)" | |
echo | |
echo "This program is part of rxOS." | |
echo "rxOS is free software licensed under the" | |
echo "GNU GPL version 3 or any later version." | |
echo | |
echo "(c) 2016 Outernet Inc" | |
echo "Some rights reserved." | |
echo | |
} | |
# Echo a command if in DRY_MODE, otherwise run it | |
# | |
# The command passed to this function must be a single string. It is executed | |
# using the `eval` command. | |
do_or_dry() { | |
local command="$1" | |
if [ "$DRY_RUN" == y ]; then | |
command="${command//\|/\\|}" | |
command="${command//\"/\\\"}" | |
eval "echo DRY: ${command}" | |
else | |
eval "$command" | |
fi | |
} | |
# Check whether a command exists | |
has_command() { | |
local command="$1" | |
which "$command" > /dev/null 2>&1 | |
} | |
# Check whether a device with specific device ID exists | |
has_dev() { | |
local devid="$1" | |
lsusb | grep -q "$devid" > /dev/null 2>&1 | |
} | |
# Check that the specified path exists and abort if it does not. | |
check_file() { | |
local path="$1" | |
[ -f "$path" ] || abort "File not found: '$path' | |
Is the build finished?" | |
} | |
# Keep executing a specified command until it succeeds or times out | |
# | |
# Arguments: | |
# | |
# timeout: total pauses | |
# pause: pause duration in seconds | |
# message: message shown before the command executes | |
# command: command that checks status | |
# | |
# The command must be quoted. | |
with_timeout() { | |
local timeout="$1" | |
local pause="$2" | |
local msg="$3" | |
local cmd="$4" | |
echo -n "${msg}..." | |
for i in {1..$timeout}; do | |
$cmd > /dev/null 2>&1 && echo "OK" && return 0 | |
sleep "$pause" | |
echo -n "." | |
done | |
echo "TIMEOUT" | |
return 1 | |
} | |
# Wait for CHIP in FEL mode to connected | |
wait_for_fel() { | |
with_timeout 60 1 "Waiting for CHIP in FEL mode" "fel ver" | |
} | |
# Wait for CHIP to reconnect after being flashed | |
wait_for_boot() { | |
with_timeout 30 6 "Flashing CHIP" "has_device $CHIP_DEVID" | |
} | |
# Print a number in hex format | |
hex() { | |
local num="$1" | |
printf "0x%08x" "$num" | |
} | |
# Return the size of a file in bytes | |
filesize() { | |
local path="$1" | |
stat --printf="%s" "$path" | |
} | |
# Return the size of a file in hex | |
hexsize() { | |
local path="$1" | |
hex "$(filesize "$path")" | |
} | |
# Return the size of a file in pages | |
pagesize() { | |
local path="$1" | |
local fsize | |
fsize="$(filesize "$path")" | |
hex "$((fsize / PAGE_SIZE))" | |
} | |
# Return the size of a padded SPL file with EEC in hex | |
splsize() { | |
local path="$1" | |
local fsize | |
fsize="$(filesize "$path")" | |
hex "$((fsize / PAGE_SIZE + OOB_SIZE))" | |
} | |
# Align a file to page boundary | |
# | |
# Arguments: | |
# | |
# in: input file path | |
# out: output file path | |
page_align() { | |
local in="$1" | |
local out="$2" | |
dd if="$in" of="$out" bs=$PAGE_SIZE conv=sync status=none | |
} | |
# Pad a file to specified size | |
# | |
# Arguments: | |
# | |
# size: target size (in hex notiation) | |
# path: path of the file to pad | |
# | |
# This function modifies the original file by appending the padding. Padding is | |
# a stream of random bytes sources from /dev/urandom. | |
# | |
# It is the caller's responsibility to ensure that the target size is larger | |
# than the current size. | |
pad_to() { | |
local size="$1" | |
local path="$2" | |
local source_size | |
local source_size_hex | |
local dpages | |
source_size="$(filesize "$path")" | |
source_size_hex="$(hexsize "$path")" | |
dpages="$(( (size - source_size_hex) / PAGE_SIZE_HEX ))" | |
dd if=/dev/urandom of="$path" seek="$source_size" bs=$PAGE_SIZE \ | |
count="$dpages" status=none | |
} | |
# Create padded SPL with EEC (error correction code) | |
# | |
# Arguments: | |
# | |
# in: path to the source SPL binary | |
# out: output path | |
# | |
# This is a thin wrapper around `spl-image-builder` too provided by NTC. The | |
# arguments are as follows: | |
# | |
# -d disable scrambler | |
# -r repeat count | |
# -u usable page size | |
# -o OOB size | |
# -p page size | |
# -c ECC step size | |
# -s ECC strength | |
add_ecc() { | |
local in="$1" | |
local out="$2" | |
spl-image-builder -d -r 3 -u 4096 -o "$OOB_SIZE" -o "$PAGE_SIZE" -c 1024 \ | |
-s 64 "$in" "$out" | |
} | |
############################################################################### | |
# SHOW STARTS HERE | |
############################################################################### | |
TEST_MODE=n | |
KEEP_TMPDIR=n | |
DRY_RUN=n | |
# Parse the command line options | |
while getopts "htkD" opt; do | |
case $opt in | |
h) | |
usage | |
exit 0 | |
;; | |
t) | |
TEST_MODE=y | |
;; | |
k) | |
KEEP_TMPDIR=y | |
;; | |
D) | |
DRY_RUN=y | |
;; | |
\?) | |
echo "Invalid option: -$OPTARG" >&2 | |
echo | |
usage | |
exit 1 | |
;; | |
esac | |
done | |
# Check prereqisites | |
has_command fel || abort "Missing command 'fel' | |
Please install https://github.com/NextThingCo/sunxi-tools" | |
has_command spl-image-builder || abort "Missing command 'spl-image-builder' | |
Please install from https://github.com/NextThingCo/CHIP-tools @210f269" | |
has_command mkimage || abort "Missing command 'mkimage' | |
Please install android-tools" | |
has_command dd || abort "Missing command 'dd' | |
Please install coreutils" | |
has_command lsusb || abort "Missing command 'lsusb' | |
Please install usbutils" | |
# Check that sources exist | |
check_file "$SPL" | |
check_file "$UBOOT" | |
check_file "$UBOOT_ENV" | |
check_file "$LINUX" | |
check_file "$ROOTFS" | |
# Create and set tempdir | |
TMPDIR="$(mktemp -d "$TMPDIR_TEMPLATE")" | |
############################################################################### | |
# Prepare files | |
############################################################################### | |
msg "Preparing the payloads" | |
submsg "Preparing the SPL binary" | |
add_ecc "$SPL" "$TMPDIR/spl-with-ecc.bin" | |
SPL_SIZE=$(splsize "$TMPDIR/spl-with-ecc.bin") | |
submsg "Preparing the U-Boot binary" | |
page_align "$UBOOT" "$TMPDIR/uboot.bin" | |
UBOOT_SIZE=0xC0000 | |
pad_to "$UBOOT_SIZE" "$TMPDIR/uboot.bin" | |
submsg "Preparing the U-Boot env file" | |
UBOOT_ENV_SIZE=0x40000 | |
submsg "Preparing the kernel image" | |
page_align "$LINUX" "$TMPDIR/zImage" | |
LINUX_SIZE="$(hexsize "$TMPDIR/zImage")" | |
submsg "Preparing the rootfs image" | |
ROOTFS_SIZE="$(hexsize "$ROOTFS")" | |
############################################################################### | |
# Create script | |
############################################################################### | |
msg "Creating U-Boot script" | |
if [ "$TEST_MODE" == y ]; then | |
EXIT_MSG="FINISHED_FLASHING" | |
EXIT_CMD="whle true; do; sleep 10; done;" | |
else | |
EXIT_MSG="BOOTING" | |
EXIT_CMD="boot" | |
fi | |
submsg "Writing script source" | |
cat <<EOF > "$TMPDIR/uboot.cmds" | |
nand erase 0x0 $NAND_SIZE | |
sunxi_nand config spl | |
nand write.raw ${SPL_ADDR} ${SPL_OFF} ${SPL_SIZE} | |
nand write.raw ${SPL_ADDR} ${SPL_BACKUP_OFF} ${SPL_SIZE} | |
sunxi_nand config default | |
nand write ${UBOOT_ADDR} ${UBOOT_OFF} ${UBOOT_SIZE} | |
nand write ${UBOOT_ENV_ADDR} ${UBOOT_ENV_OFF} ${UBOOT_ENV_SIZE} | |
nand write ${LINUX_ADDR} ${LINUX_OFF} ${LINUX_SIZE} | |
nand slc-mode on | |
nand write.trimfs ${ROOTFS_ADDR} ${ROOTFS_OFF} ${ROOTFS_SIZE} | |
nand write.trimfs ${ROOTFS_ADDR} ${ROOTFS_BACKUP_OFF} ${ROOTFS_SIZE} | |
setenv bootargs earlyprintk | |
setenv bootcmd source \${scriptaddr}; nand slc-mode on; mtdparts; nand read \$kernel_addr_r linux; bootm \$kernel_addr_r | |
saveenv | |
mw \${scriptaddr} 0x0 | |
echo | |
echo =================={{{ $EXIT_MSG }}}================== | |
echo | |
$EXIT_CMD | |
EOF | |
submsg "Writing script image" | |
mkimage -A arm -T script -C none -n "flash CHIP" -d "$TMPDIR/uboot.cmds" \ | |
"$TMPDIR/uboot.scr" > /dev/null | |
############################################################################### | |
# Uploading | |
############################################################################### | |
msg "Uploading payloads" | |
# Wait for chip in FEL mode to become available | |
wait_for_fel || abort "Unable to find CHIP in FEL mode" | |
submsg "Executing SPL" | |
do_or_dry 'fel spl "$SPL"' | |
submsg "Uploading SPL" | |
do_or_dry 'fel write "$SPL_ADDR" "$TMPDIR/spl-with-ecc.bin"' | |
submsg "Uploading U-Boot" | |
do_or_dry 'fel write "$UBOOT_ADDR" "$TMPDIR/uboot.bin"' | |
submsg "Uploading U-Boot env" | |
do_or_dry 'fel write "$UBOOT_ENV_ADDR" "$UBOOT_ENV"' | |
submsg "Uploading Linux kernel" | |
do_or_dry 'fel write "$LINUX_ADDR" "$TMPDIR/zImage"' | |
submsg "Uploading rootfs image" | |
do_or_dry 'fel write "$ROOTFS_ADDR" "$ROOTFS"' | |
############################################################################### | |
# Executing flash | |
############################################################################### | |
msg "Executing flash" | |
do_or_dry 'fel exe "$UBOOT_ADDR"' | |
# Finish up | |
msg "Cleaning up" | |
[ "$KEEP_TMPDIR" == n ] && rm -rf "$TMPDIR" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment