Skip to content

Commit

Permalink
Added RAM split detection, added offline mode, added option to skip k…
Browse files Browse the repository at this point in the history
…ernel update (thanks AndrewS!)
  • Loading branch information
Hexxeh committed May 26, 2012
1 parent 5f6ab29 commit e9c85cd
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 71 deletions.
30 changes: 29 additions & 1 deletion README.md
Expand Up @@ -21,7 +21,10 @@ To then update your firmware, simply run the following command as root:
rpi-update
</pre>

By default, the 224MB memory split will be used. If you'd like to use the 192MB split, then type:

By default, rpi-update will attempt to determine the split you're currently using, and then use that split. If it cannot determine what split you are using, it will default to 224MB.

If you'd like to explicitly select a split, simply provide the RAM split value after the command as follows:

<pre>
rpi-update 192
Expand All @@ -32,3 +35,28 @@ If you'd like to use the 128MB memory split, then the command is the same as the
After the firmware has been sucessfully updated, you'll need to reboot to load the new firmware.

This tool is experimental, and may screw up your install. If you have problems with it, post an issue to this GitHub repo and I'll see if I can help you.

Expert options
--------------

There are a number of options for experts you might like to use, these are all environment variables you must set if you wish to use them.

### SKIP_KERNEL

#### Usage

SKIP_KERNEL=1 rpi-update

#### Effect

Will update everything EXCEPT the kernel.img files and the kernel modules. Use with caution, some firmware updates might depend a kernel update.

### ROOT_PATH/BOOT_PATH

#### Usage

ROOT_PATH=/media/root BOOT_PATH=/media/boot rpi-update

#### Effect

Allows you to perform an "offline" update, ie update firmware on an SD card you're not currently booted from. Useful for installing firmware/kernel to a non-RPI customised image. Be careful, you must specify both options or neither. Specifying only one will not work.
224 changes: 154 additions & 70 deletions rpi-update
Expand Up @@ -3,94 +3,188 @@
set -o nounset
set -o errexit

UPDATE=${2:-1}
UPDATE_URI="https://raw.github.com/Hexxeh/rpi-update/master/rpi-update"
UPDATE=${UPDATE:-1}
UPDATE_URI="https://github.com/Hexxeh/rpi-update/raw/master/rpi-update"

ROOT_PATH=${ROOT_PATH:-"/"}
BOOT_PATH=${BOOT_PATH:-"/boot"}
SKIP_KERNEL=${SKIP_KERNEL:-0}
FW_REPO="git://github.com/Hexxeh/rpi-firmware.git"
FW_REPOLOCAL="/root/.rpi-firmware"
FW_PATH="/boot"
FW_REPONAME=`basename ${FW_REPOLOCAL}`
FW_RAM=${1:-224}
FW_GPU=$((256-FW_RAM))
FW_REPOLOCAL="${ROOT_PATH}/root/.rpi-firmware"
FW_PATH="${BOOT_PATH}"
FW_MODPATH="${ROOT_PATH}/lib/modules"
FW_RAM=${1:-0}
GITCMD="git --git-dir=\"${FW_REPOLOCAL}/.git\" --work-tree=\"${FW_REPOLOCAL}\""

function detect_split() {
if [[ -f "$FW_PATH/start.elf" && ${FW_RAM} -eq 0 ]]; then
FW_RAM=224
for R in 128 192 224
do
if [[ -f "$FW_PATH/arm${R}_start.elf" ]]
then
if diff "$FW_PATH/arm${R}_start.elf" "$FW_PATH/start.elf" >/dev/null
then
FW_RAM=$R
break
fi
fi
done
fi
FW_GPU=$((256-FW_RAM))
}

function update_self() {
echo "Performing self-update"
echo "Performing self-update"
_tempFileName="$0.tmp"
_payloadName="$0.payload"

if ! wget --quiet --output-document="$_payloadName" $UPDATE_URI ; then

if ! wget --quiet --output-document="${_tempFileName}" "${UPDATE_URI}"; then
echo "Failed to download update for rpi-update!"
echo "Make sure you have ca-certificates installed and that the time is set correctly"
exit 1
fi

_interpreter=$(head --lines=1 "$0")
echo $_interpreter > "$_tempFileName"
tail --lines=+2 "$_payloadName" >> "$_tempFileName"
rm "$_payloadName"

OCTAL_MODE=$(stat -c '%a' $0)
if ! chmod $OCTAL_MODE "$_tempFileName" ; then
echo "Failed: Error while trying to set mode on $_tempFileName."

OCTAL_MODE=$(stat -c '%a' "$0")
if ! chmod ${OCTAL_MODE} "${_tempFileName}" ; then
echo "Failed: Error while trying to set mode on ${_tempFileName}"
exit 1
fi

cat > updateScript.sh << EOF
cat > /tmp/updateScript.sh << EOF
#!/bin/bash
if mv "$_tempFileName" "$0"; then
rm -- \$0
exec /bin/bash $0 ${FW_RAM} 0
if mv "${_tempFileName}" "$0"; then
rm -- "\$0"
exec env UPDATE=0 /bin/bash "$0" "$@"
else
echo "Failed!"
fi
EOF
exec /bin/bash updateScript.sh "$@"

exec /bin/bash /tmp/updateScript.sh
}

function update_modules {
cp -R ${FW_REPOLOCAL}/modules/* /lib/modules/
for D in `find ${FW_REPOLOCAL}/modules -mindepth 1 -maxdepth 1 -type d`; do
depmod -a `basename $D`
done
if [[ ${SKIP_KERNEL} -eq 0 ]]; then
cp -R "${FW_REPOLOCAL}/modules/"* "${FW_MODPATH}/"
find "${FW_REPOLOCAL}/modules" -mindepth 1 -maxdepth 1 -type d | while read DIR; do
depmod -b "${ROOT_PATH}" -a $(basename "${DIR}")
done
fi
}

function update_sdk {
ELFOUTPUT=`readelf -a /bin/bash`
if [ "$ELFOUTPUT" != "${ELFOUTPUT/VFP_args/}" ]; then
if [[ -f /etc/init.d/vcfiled ]]; then
/etc/init.d/vcfiled stop
fi

ELFOUTPUT=$(readelf -a "${ROOT_PATH}/bin/bash")
if [ "${ELFOUTPUT}" != "${ELFOUTPUT/VFP_args/}" ]; then
echo "Using HardFP libraries"
cp -R ${FW_REPOLOCAL}/vc/hardfp/* /
cp -R "${FW_REPOLOCAL}/vc/hardfp/"* "${ROOT_PATH}/"
else
echo "Using SoftFP libraries"
cp -R ${FW_REPOLOCAL}/vc/softfp/* /
cp -R "${FW_REPOLOCAL}/vc/softfp/"* "${ROOT_PATH}/"
fi
cp -R "${FW_REPOLOCAL}/vc/sdk/"* "${ROOT_PATH}/"

if [[ -f /etc/init.d/vcfiled ]]; then
/etc/init.d/vcfiled start
fi
cp -R ${FW_REPOLOCAL}/vc/sdk/* /
}

function set_split {
cp ${FW_REPOLOCAL}/arm${FW_RAM}_start.elf ${FW_PATH}/start.elf
cp "${FW_PATH}/arm${FW_RAM}_start.elf" "${FW_PATH}/start.elf"
}

function update_firmware {
cp ${FW_REPOLOCAL}/*.elf ${FW_PATH}/
cp ${FW_REPOLOCAL}/*.bin ${FW_PATH}/
cp ${FW_REPOLOCAL}/*.img ${FW_PATH}/
cp "${FW_REPOLOCAL}/"*.elf "${FW_PATH}/"
cp "${FW_REPOLOCAL}/"*.bin "${FW_PATH}/"
if [[ ${SKIP_KERNEL} -eq 0 ]]; then
cp "${FW_REPOLOCAL}/"*.img "${FW_PATH}/"
else
echo "Skipping kernel/modules updated as requested"
fi
}

function finalise {
ldconfig
ldconfig -r "${ROOT_PATH}"
eval ${GITCMD} rev-parse master > "${FW_PATH}/.firmware_revision"
sync
}

if [[ $EUID -ne 0 ]]; then
function download_repo {
echo "Setting up firmware (this will take a few minutes)"
mkdir -p "${FW_REPOLOCAL}"
git clone "${FW_REPO}" "${FW_REPOLOCAL}" --depth=1 --quiet
RETVAL=$?
if [[ ${RETVAL} -ne 0 ]]; then
echo "Failed to download new firmware files"
exit 1
fi
}

function update_repo {
echo "Updating firmware (this will take a few minutes)"
eval ${GITCMD} fetch --quiet
RETVAL=$?
if [[ ${RETVAL} -ne 0 ]]; then
echo "Failed to download updated firmware files"
exit 1
fi
eval ${GITCMD} merge origin/master -m "automerge" --quiet
RETVAL=$?
if [[ ${RETVAL} -ne 0 ]]; then
echo "Failed to download updated firmware files"
exit 1
fi
}

function do_backup {
cp -a "${FW_PATH}" "${FW_PATH}.bak"
cp -a "${FW_MODPATH}" "${FW_MODPATH}.bak"
}

function do_update {
update_firmware
update_modules
update_sdk
set_split
finalise
echo "If no errors appeared, your firmware was successfully $1"
if [[ "${ROOT_PATH}" == "/" ]]; then
echo "A reboot is needed to activate the new firmware"
fi
}

if [[ ${EUID} -ne 0 ]]; then
echo "This tool must be run as root"
exit 1
fi

if [[ $UPDATE -ne 0 ]]; then
echo "Raspberry Pi firmware updater by Hexxeh"
if [[ ${UPDATE} -ne 0 ]]; then
echo "Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS"
update_self
fi

if [[ ( "${ROOT_PATH}" == "/" && "${BOOT_PATH}" != "/boot" ) ]] ||
[[ ( "${BOOT_PATH}" == "/boot" && "${ROOT_PATH}" != "/" ) ]]; then
echo "You need to specify both ROOT_PATH and BOOT_PATH, or neither"
exit 1
fi

if [[ ! -d "${FW_PATH}" ]]; then
echo "${FW_PATH} doesn't exist"
exit 1
fi
if [[ ! -f "${FW_PATH}/start.elf" ]]; then
echo "${FW_PATH}/start.elf doesn't exist."
exit 1
fi
if [[ ! -d "${FW_MODPATH}" ]]; then
echo "${FW_MODPATH} doesn't exist"
exit 1
fi

command -v git >/dev/null 2>&1 || {
echo "This tool requires you have Git installed, please install it first"
echo "In Debian, try: sudo apt-get install git-core"
Expand All @@ -105,35 +199,25 @@ command -v readelf >/dev/null 2>&1 || {
exit 1
}

echo "Using memory split of ${FW_RAM}MB/${FW_GPU}MB"

GITCMD="git --git-dir=${FW_REPOLOCAL}/.git --work-tree=${FW_REPOLOCAL}"
detect_split
if [[ ${FW_RAM} -ne 224 ]] && [[ ${FW_RAM} -ne 192 ]] && [[ ${FW_RAM} -ne 128 ]]; then
echo "RAM value must be one of: 224, 192, 128"
exit 1
fi
echo "Using ARM/GPU memory split of ${FW_RAM}MB/${FW_GPU}MB"

mkdir -p ${FW_REPOLOCAL}
if $($GITCMD rev-parse &> /dev/null); then
echo "Updating firmware (this will take a few minutes)"
$GITCMD fetch --quiet
$GITCMD merge origin/master -m "automerge" --quiet
update_firmware
update_modules
update_sdk
set_split
finalise
echo "If no errors appeared, your firmware was successfully updated"
else
echo "We're running for the first time"
echo "Setting up firmware (this will take a few minutes)"
cp -R ${FW_PATH} ${FW_PATH}.bak
git clone ${FW_REPO} ${FW_REPOLOCAL} --depth=1 --quiet
RETVAL=$?
if [[ $RETVAL != 0 ]]; then
echo "Failed to download new firmware files"
else
update_firmware
update_modules
update_sdk
if [[ -f "${FW_REPOLOCAL}/.git/config" ]]; then
update_repo
if [[ -f "${FW_PATH}/.firmware_revision" ]] && [[ $(cat "${FW_PATH}/.firmware_revision") == $(eval ${GITCMD} rev-parse master) ]]; then
echo "Your firmware is already up to date"
set_split
finalise
echo "If no errors appeared, your firmware was successfully setup"
else
do_update "updated"
fi
else
echo "We're running for the first time"
download_repo
do_backup
do_update "setup"
fi

0 comments on commit e9c85cd

Please sign in to comment.