├── LICENSE ├── README.md └── rpi-update /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Liam McLoughlin 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rpi-update 2 | 3 | A tool to get the latest bleeding-edge firmware and kernel for your Raspberry Pi. 4 | 5 | # Notes 6 | 7 | This is only intended for use with Raspberry Pi OS. If you are using a different 8 | distribution then check with the maintainers if using rpi-update is safe. 9 | 10 | If the distribution ships a custom kernel (e.g. BerryBoot), then it almost certainly is not 11 | safe. Also differences in the usage of /boot and /opt/vc directories will 12 | likely make it unsafe. 13 | 14 | Even on Raspberry Pi OS you should only use this with a good reason. 15 | 16 | This gets you the latest bleeding edge kernel/firmware. 17 | There is always the possibility of regressions. 18 | 19 | Bug fixes and improvements will eventually make their way into new Raspberry Pi OS 20 | releases and apt-get when they are considered sufficiently well tested. 21 | 22 | A good reason for using this would be if you like to help with the testing effort, 23 | and are happy to risk breakages and submit bug reports. These testers are welcome. 24 | 25 | Also if you are suffering from a bug in current firmware (perhaps as one of 26 | the reporters of the bug on github or forum) and a fix has been pushed out for 27 | testing, then using rpi-update is the right way to get the fix until it makes 28 | its way into new Raspberry Pi OS images and apt-get. 29 | 30 | Backing up before updating is always advisable. 31 | 32 | ## Installing 33 | 34 | ### Installing under Raspberry Pi OS 35 | 36 | To install the tool, run the following command: 37 | 38 | sudo apt-get install rpi-update 39 | 40 | ### Installing under other OSes 41 | 42 | To install the tool, run the following command: 43 | 44 | sudo curl -L --output /usr/bin/rpi-update https://raw.githubusercontent.com/raspberrypi/rpi-update/master/rpi-update && sudo chmod +x /usr/bin/rpi-update 45 | 46 | ## Updating 47 | 48 | Then, to update your firmware, just run the following command: 49 | 50 | sudo rpi-update 51 | 52 | ## Activating 53 | 54 | After the firmware has been sucessfully updated, you'll need to reboot to load 55 | the new firmware. 56 | 57 | ## Options 58 | 59 | If you'd like to set a different GPU/ARM memory split, then define `gpu_mem` in 60 | `/boot/firmware/config.txt`, or in older OSes `/boot/config.txt`. 61 | 62 | To upgrade/downgrade to a specific firmware revision, specify its Git hash 63 | (from the https://github.com/raspberrypi/rpi-firmware repository) as follows: 64 | 65 | sudo rpi-update fab7796df0cf29f9563b507a59ce5b17d93e0390 66 | 67 | You can also specify a git branch in raspberrypi/rpi-firmware repo. 68 | 69 | sudo rpi-update next 70 | 71 | ## Using github artifacts from automated builds 72 | 73 | You can also update the kernel to an automated github build from raspberrypi/linux. 74 | These builds persist for 90 days, and won't be available after that time has elapsed. 75 | 76 | sudo rpi-update pulls/5335 # update to most recent build from pull request 5335 77 | sudo rpi-update ledoff # update to a build PR'd from local branch named ledoff 78 | sudo rpi-update 14a52e4d # update to a build with hash 14a52e4d 79 | sudo rpi-update rpi-6.2.y # update to a latest build from branch rpi-6.2.y 80 | 81 | If you only care about one build architecture you can specify the build architecture. 82 | Options are: bcmrpi bcm2709 bcm2711 bcm2711_arm64 bcm2835 arm64 (last two are with upstream kernel config) 83 | 84 | sudo rpi-update rpi-6.2.y:bcm2711 # update only bcm2711 kernel to latest build from branch rpi-6.2.y 85 | 86 | ### Expert options 87 | 88 | There are a number of options for experts you might like to use. These are all 89 | environment variables you must set if you wish to use them. 90 | 91 | #### `UPDATE_SELF` 92 | 93 | By default, `rpi-update` will attempt to update itself each time it is run. 94 | You can disable this behavior by: 95 | 96 | sudo UPDATE_SELF=0 rpi-update 97 | 98 | #### `SKIP_KERNEL` 99 | 100 | sudo SKIP_KERNEL=1 rpi-update 101 | 102 | Will update everything **except** the `kernel.img` files and the kernel modules. 103 | Use with caution, some firmware updates might depend on a kernel update. 104 | 105 | #### `SKIP_BOOTLOADER` 106 | Will update everything except the bootloader EEPROM. 107 | 108 | To revert previous updates to the local set of EEPROM binaries run:- 109 | ``` 110 | sudo rm -rf /lib/firmware/raspberrypi/bootloader-2711 111 | sudo rm -rf /lib/firmware/raspberrypi/bootloader-2712 112 | sudo apt reinstall rpi-eeprom 113 | ``` 114 | 115 | #### `SKIP_BACKUP` 116 | 117 | sudo SKIP_BACKUP=1 rpi-update 118 | 119 | Avoids making backup of /boot and /lib/modules on first run. 120 | 121 | #### `SKIP_REPODELETE` 122 | 123 | sudo SKIP_REPODELETE=1 rpi-update 124 | 125 | By default the downloaded files (/root/.rpi-firmware) are deleted at end of update. 126 | Use this option to keep the files. 127 | 128 | #### `SKIP_VCLIBS` 129 | 130 | sudo SKIP_VCLIBS=1 rpi-update 131 | 132 | Will update everything **except** the VideoCore libraries. 133 | Use this option to keep the existing VideoCore libraries if you do not want your 134 | local versions overwritten. 135 | 136 | #### `ROOT_PATH` and `BOOT_PATH` 137 | 138 | sudo ROOT_PATH=/media/root BOOT_PATH=/media/boot rpi-update 139 | 140 | Allows you to perform an "offline" update, ie update firmware on an SD card you 141 | are not currently booted from. Useful for installing firmware/kernel to a 142 | non-RPI customised image. Be careful, you must specify both options or neither. 143 | Specifying only one will not work. 144 | 145 | #### `FW_SUBDIR` 146 | 147 | sudo FW_SUBDIR=safe rpi-update 148 | 149 | Allows the firmware to be installed to a subdirectory of /boot. This feature is 150 | intended to support the `os_prefix` setting that can be used in `config.txt`. 151 | By default, FW_SUBDIR is initialised to the value of `os_prefix` in effect when 152 | the device was booted, so as to overwrite the "running" firmware. To explicitly 153 | install with no subdirectory (to install into /boot), use `FW_SUBDIR=/`. 154 | 155 | #### `PRUNE_MODULES` 156 | 157 | Allows you to delete unused module directories when doing an update. Set it equal to a non-zero value and it will remove all modules except the latest installed: 158 | 159 | sudo PRUNE_MODULES=1 rpi-update 160 | 161 | will remove previously installed module files. Use this option to free disk space used by older module updates. 162 | 163 | #### `JUST_CHECK` 164 | 165 | To just get a list of commits contained in rpi-update since you last updated, run: 166 | 167 | sudo JUST_CHECK=1 rpi-update 168 | 169 | This won't update your firmware 170 | 171 | #### `GITHUB_API_TOKEN` 172 | 173 | By default, `rpi-update` will not use a custom GitHub API token. If you run into rate limiting issues, you can supply an API token on the command line: 174 | 175 | sudo GITHUB_API_TOKEN= rpi-update 176 | 177 | #### `RPI_REBOOT` 178 | 179 | To reboot after successfully update, run: 180 | 181 | sudo RPI_REBOOT=1 rpi-update 182 | 183 | You can use it to automate updates. 184 | 185 | ## Troubleshooting 186 | 187 | There are two possible problems related to SSL certificates that may prevent 188 | this tool from working. 189 | 190 | - The time may be set incorrectly on your Raspberry Pi, which you can fix 191 | by setting the time using NTP. 192 | 193 | sudo apt-get install ntpdate 194 | sudo ntpdate -u ntp.ubuntu.com 195 | 196 | - The other possible issue is that you might not have the `ca-certificates` 197 | package installed, and so GitHub's SSL certificate isn't trusted. If you are 198 | on Debian, you can resolve this by typing: 199 | 200 | sudo apt-get install ca-certificates 201 | 202 | Pi-hole and similar DNS based may stop this tool from working. 203 | Make sure github.com domains are not blocked. (e.g. codeload.github.com) 204 | -------------------------------------------------------------------------------- /rpi-update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o nounset 4 | set -o errexit 5 | 6 | for i in $*; do 7 | if [[ $i == -* ]]; then 8 | echo "rpi-update does not accept command line dash parameters." 9 | echo "See: https://github.com/raspberrypi/rpi-update/blob/master/README.md" 10 | exit 1 11 | fi 12 | done 13 | 14 | # REPO_URI variable is here for backwards-compatibility 15 | REPO_URI=${REPO_URI:-"https://github.com/raspberrypi/rpi-firmware"} 16 | FIRMWARE_REPO_URI=${FIRMWARE_REPO_URI:-$REPO_URI} 17 | FIRMWARE_REPO_API_URI=${FIRMWARE_REPO_URI/github.com/api.github.com\/repos} 18 | FIRMWARE_REPO_CONTENT_URI=${FIRMWARE_REPO_URI/github.com/raw.githubusercontent.com} 19 | 20 | BOOTLOADER_REPO_URI=${BOOTLOADER_REPO_URI:-"https://github.com/raspberrypi/rpi-eeprom"} 21 | BOOTLOADER_REPO_API_URI=${BOOTLOADER_REPO_URI/github.com/api.github.com\/repos} 22 | BOOTLOADER_REPO_CONTENT_URI=${BOOTLOADER_REPO_URI/github.com/raw.githubusercontent.com} 23 | 24 | LINUX_REPO_URI=${LINUX_REPO_URI:-"https://github.com/raspberrypi/linux"} 25 | LINUX_REPO_API_URI=${LINUX_REPO_URI/github.com/api.github.com\/repos} 26 | 27 | UPDATE_SELF=${UPDATE_SELF:-1} 28 | UPDATE_REPO_URI=${UPDATE_REPO_URI:-"https://github.com/raspberrypi/rpi-update"} 29 | UPDATE_REPO_CONTENT_URI=${UPDATE_REPO_URI/github.com/raw.githubusercontent.com} 30 | UPDATE_URI="${UPDATE_REPO_CONTENT_URI}/master/rpi-update" 31 | 32 | if [[ "${BOOT_PATH:-"unset"}" == "unset" && "${ROOT_PATH:-"unset"}" != "unset" ]] || 33 | [[ "${BOOT_PATH:-"unset"}" != "unset" && "${ROOT_PATH:-"unset"}" == "unset" ]]; then 34 | echo " *** You need to specify both ROOT_PATH and BOOT_PATH, or neither" 35 | exit 1 36 | fi 37 | 38 | if [[ "${BOOT_PATH:-"unset"}" == "unset" ]]; then 39 | NOOBS_CHECK=${NOOBS_CHECK:-1} 40 | else 41 | NOOBS_CHECK=${NOOBS_CHECK:-0} 42 | fi 43 | 44 | ROOT_PATH=${ROOT_PATH:-"/"} 45 | if command -v vcgencmd > /dev/null; then 46 | CUR_FW_SUBDIR="/$(echo =$(vcgencmd get_config os_prefix) | cut -d'=' -f3)" 47 | else 48 | CUR_FW_SUBDIR="/" 49 | fi 50 | FW_SUBDIR=${FW_SUBDIR:-${CUR_FW_SUBDIR}} 51 | if [[ "${FW_SUBDIR}" != "" ]]; then 52 | if [[ "${FW_SUBDIR::1}" != "/" ]]; then 53 | FW_SUBDIR="/$FW_SUBDIR" 54 | fi 55 | if [[ "${FW_SUBDIR: -1}" == "/" ]]; then 56 | FW_SUBDIR=${FW_SUBDIR: : -1} 57 | fi 58 | fi 59 | if mountpoint -q /boot/firmware ; then 60 | BOOT_PATH=${BOOT_PATH:-"/boot/firmware"} 61 | else 62 | BOOT_PATH=${BOOT_PATH:-"/boot"} 63 | fi 64 | WORK_PATH=${WORK_PATH:-"${ROOT_PATH}/root"} 65 | SKIP_KERNEL=${SKIP_KERNEL:-} 66 | SKIP_BOOTLOADER=${SKIP_BOOTLOADER:-0} 67 | SKIP_FIRMWARE=${SKIP_FIRMWARE:-0} 68 | SKIP_SDK=${SKIP_SDK:-0} 69 | SKIP_VCLIBS=${SKIP_VCLIBS:-0} 70 | SKIP_REPODELETE=${SKIP_REPODELETE:-0} 71 | SKIP_BACKUP=${SKIP_BACKUP:-0} 72 | SKIP_DOWNLOAD=${SKIP_DOWNLOAD:-0} 73 | SKIP_WARNING=${SKIP_WARNING:-0} 74 | SKIP_CHECK_PARTITION=${SKIP_CHECK_PARTITION:-0} 75 | WANT_SYMVERS=${WANT_SYMVERS:-0} 76 | PRUNE_MODULES=${PRUNE_MODULES:-0} 77 | RPI_UPDATE_UNSUPPORTED=${RPI_UPDATE_UNSUPPORTED:-0} 78 | JUST_CHECK=${JUST_CHECK:-0} 79 | RPI_REBOOT=${RPI_REBOOT:-0} 80 | CURL_OPTIONS=${CURL_OPTIONS:-""} 81 | GITHUB_API_TOKEN=${GITHUB_API_TOKEN:-""} 82 | # REDIRECTOR variable is here for backwards-compatibility 83 | REDIRECTOR=${REDIRECTOR:-"https://builds.raspberrypi.com/github/linux"} 84 | REDIRECTOR_URI=${REDIRECTOR_URI:-$REDIRECTOR} 85 | 86 | FW_REPO="${REPO_URI}.git" 87 | FW_REPOLOCAL=${FW_REPOLOCAL:-"${WORK_PATH}/.rpi-firmware"} 88 | FW_PATH="${BOOT_PATH}${FW_SUBDIR}" 89 | FW_MODPATH="${ROOT_PATH}/lib/modules" 90 | FW_REV_IN=${1:-""} 91 | FW_REVFILE="${FW_PATH}/.firmware_revision" 92 | SELFUPDATE_SCRIPT="${WORK_PATH}/.updateScript.sh" 93 | BOOTLOADER_REV_IN=${2:-""} 94 | BOOTLOADER_REVFILE="${FW_PATH}/.bootloader_revision" 95 | 96 | [ "${RPI_UPDATE_UNSUPPORTED}" -ne 0 ] && echo -e "You appear to be trying to update firmware on an incompatible distribution. To force update, run the following:\nsudo -E RPI_UPDATE_UNSUPPORTED=0 rpi-update" && exit 1 97 | 98 | if [[ "$SKIP_KERNEL" == "" ]]; then 99 | SKIP_KERNEL=0 100 | if command -v vcgencmd > /dev/null; then 101 | KERNEL=$(vcgencmd get_config str | grep -E "^kernel=" | cut -d= -f2) 102 | case $KERNEL in 103 | "" | kernel8_rt.img | kernel8.img | kernel_2712.img) ;; 104 | *) echo -e "You appear to be using a custom kernel file (kernel=$KERNEL in config.txt).\nSkipping installation of new kernel, as bundled dtb files may be incompatible with your kernel." && SKIP_KERNEL=1 105 | sleep 1 106 | esac 107 | fi 108 | fi 109 | 110 | # Always follow redirects 111 | CURL_OPTIONS="${CURL_OPTIONS} -L" 112 | 113 | # api.github.com requires a User-Agent header 114 | CURL_OPTIONS_API="${CURL_OPTIONS_API:-"-A curl"}" 115 | 116 | # Support for custom GitHub Auth Tokens 117 | if [[ -n "${GITHUB_API_TOKEN}" ]]; then 118 | echo " *** Using GitHub token for all requests." 119 | CURL_OPTIONS_API="${CURL_OPTIONS_API} --header \"Authorization: token ${GITHUB_API_TOKEN}\"" 120 | fi 121 | 122 | GITHUB_API_LIMITED=$(eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "https://api.github.com/rate_limit" | tr -d "," | awk 'BEGIN {reset=0;} { if ($1 == "\"limit\":") limit=$2; else if ($1 == "\"remaining\":") remaining=$2; else if ($1 == "\"reset\":" && limit>0 && remaining==0) reset=$2;} END { print reset }') 123 | if [ ${GITHUB_API_LIMITED} -gt 0 ]; then 124 | echo " *** Github API is currently rate limited - please try again after $(date --date @${GITHUB_API_LIMITED})" 125 | exit 1 126 | fi 127 | 128 | 129 | function update_self() { 130 | echo " *** Performing self-update" 131 | local _tempFileName="$0.tmp" 132 | 133 | if ! eval curl -fs ${CURL_OPTIONS} --output "${_tempFileName}" "${UPDATE_URI}"; then 134 | echo " !!! Failed to download update for rpi-update!" 135 | echo " !!! Make sure you are connected to the internet, have ca-certificates installed and that the time is set correctly" 136 | exit 1 137 | fi 138 | 139 | if [[ "$(head -1 ${_tempFileName})" != '#!/bin/bash' ]]; then 140 | echo " !!! Failed to download update for rpi-update!" 141 | echo " !!! Contents of file is not as expected - github may be down" 142 | exit 1 143 | fi 144 | 145 | local OCTAL_MODE=$(stat -c '%a' "$0") 146 | if ! chmod ${OCTAL_MODE} "${_tempFileName}" ; then 147 | echo " !!! Failed: Error while trying to set mode on ${_tempFileName}" 148 | exit 1 149 | fi 150 | 151 | cat > "${SELFUPDATE_SCRIPT}" << EOF 152 | if mv "${_tempFileName}" "$0"; then 153 | rm -- "\$0" 154 | exec env UPDATE_SELF=0 /bin/bash "$0" "${FW_REV_IN}" "${BOOTLOADER_REV_IN}" 155 | else 156 | echo " !!! Failed!" 157 | fi 158 | EOF 159 | 160 | echo " *** Relaunching after update" 161 | exec /bin/bash "${SELFUPDATE_SCRIPT}" 162 | } 163 | 164 | function update_modules { 165 | if [[ ${SKIP_KERNEL} -eq 0 ]]; then 166 | echo " *** Updating kernel modules" 167 | find "${FW_REPOLOCAL}/modules" -mindepth 1 -maxdepth 1 -type d | while read DIR; do 168 | BASEDIR=$(basename "${DIR}") 169 | rm -rf "${FW_MODPATH}/${BASEDIR}/kernel" 170 | done 171 | 172 | if [[ ${PRUNE_MODULES} -ne 0 ]]; then 173 | find "${FW_MODPATH}" -mindepth 1 -maxdepth 1 -type d | while read DIR; do 174 | COUNT=$(find "${DIR}" -type f ! \( -name '*.ko' -o -name '*.ko.xz' -o -name 'modules.*' \) | wc -l); 175 | if [[ ${COUNT} -eq 0 ]]; then 176 | echo "Pruning ${DIR}" 177 | rm -rf "${DIR}" 178 | else 179 | echo "Keeping ${DIR}" 180 | fi 181 | done 182 | fi 183 | 184 | find "${FW_REPOLOCAL}/modules" -mindepth 1 -maxdepth 1 -type d | while read DIR; do 185 | BASEDIR="$(basename "${DIR}")" 186 | # get the v7l from 5.15.78-v7l+ and null from 5.15.78+ 187 | VERSION=$(echo $BASEDIR | cut -sd "-" -f2) 188 | if [[ ${WANT_32BIT} -ne 1 ]]; then 189 | if [[ "${VERSION}" == "" ]] || [[ "${VERSION}" == "v7+" ]] || [[ "${VERSION}" == "v7l+" ]]; then 190 | continue; 191 | fi 192 | fi 193 | if [[ ${WANT_64BIT} -ne 1 ]]; then 194 | if [[ "${VERSION}" == "v8+" ]]; then 195 | continue; 196 | fi 197 | fi 198 | if [[ ${WANT_64BIT_RT} -ne 1 ]]; then 199 | if [[ "${VERSION}" == "v8-rt+" ]]; then 200 | continue; 201 | fi 202 | fi 203 | if [[ ${WANT_PI4} -ne 1 ]]; then 204 | if [[ "${VERSION}" == "v7l+" ]]; then 205 | continue; 206 | fi 207 | fi 208 | if [[ ${WANT_PI5} -ne 1 ]]; then 209 | if [[ "${VERSION}" == "v8_16k+" ]]; then 210 | continue; 211 | fi 212 | fi 213 | cp -R "${DIR}" "${FW_MODPATH}/" 214 | echo " *** depmod ${BASEDIR}" 215 | depmod -b "${ROOT_PATH}" -a "${BASEDIR}" 216 | done 217 | else 218 | echo " *** As requested, not updating kernel modules" 219 | fi 220 | } 221 | 222 | function update_vc_libs { 223 | if [[ ${SKIP_VCLIBS} -eq 0 ]]; then 224 | echo " *** Updating VideoCore libraries" 225 | else 226 | echo " *** As requested, not updating VideoCore libraries" 227 | return 228 | fi 229 | 230 | if [[ -e ${ROOT_PATH}/bin/sh ]]; then 231 | local ELFOUTPUT=$(readelf -a "${ROOT_PATH}/bin/sh"; readelf -h "${ROOT_PATH}/bin/sh") 232 | else 233 | local ELFOUTPUT="VFP_args" 234 | fi 235 | if [[ "${ELFOUTPUT}" != "${ELFOUTPUT/VFP_args/}" || \ 236 | "${ELFOUTPUT}" != "${ELFOUTPUT/hard-float/}" ]]; then 237 | if [ -d "${FW_REPOLOCAL}/vc/hardfp/" ]; then 238 | echo " *** Using HardFP libraries" 239 | cp -R "${FW_REPOLOCAL}/vc/hardfp/"* "${ROOT_PATH}/" 240 | fi 241 | else 242 | if [ -d "${FW_REPOLOCAL}/vc/softfp/" ]; then 243 | echo " *** Using SoftFP libraries" 244 | cp -R "${FW_REPOLOCAL}/vc/softfp/"* "${ROOT_PATH}/" 245 | fi 246 | fi 247 | } 248 | 249 | function update_sdk { 250 | if [[ ${SKIP_SDK} -eq 0 ]]; then 251 | if [ -d "${FW_REPOLOCAL}/vc/sdk/" ]; then 252 | echo " *** Updating SDK" 253 | cp -R "${FW_REPOLOCAL}/vc/sdk/"* "${ROOT_PATH}/" 254 | fi 255 | else 256 | echo " *** As requested, not updating SDK" 257 | fi 258 | } 259 | 260 | function download_bootloader_tools { 261 | for tool in rpi-eeprom-update rpi-eeprom-config rpi-eeprom-digest; do 262 | temp="$(mktemp)" 263 | if ! eval curl -fs ${CURL_OPTIONS} "${BOOTLOADER_REPO_CONTENT_URI}/${BOOTLOADER_REV}/${tool}" --output "${temp}"; then 264 | echo " !!! Failed to download ${tool}" 265 | rm -f "${temp}" 266 | exit 1 267 | fi 268 | mv "${temp}" "/usr/bin/${tool}" 269 | chmod a+rx "/usr/bin/${tool}" 270 | done 271 | } 272 | 273 | function download_bootloader_images { 274 | bcm_chip=$1 275 | latest_eeprom=$(eval curl ${CURL_OPTIONS_API} -fs ${CURL_OPTIONS} ${BOOTLOADER_REPO_API_URI}/git/trees/${BOOTLOADER_REV}?recursive=1 | grep "firmware-${bcm_chip}/latest/pieeprom" | sed 's/.*\(pieeprom.*\)".*/\1/' | sort -r | head -n1) 276 | if [[ -n "${latest_eeprom}" ]]; then 277 | fw_path="/lib/firmware/raspberrypi/bootloader-${bcm_chip}/latest" 278 | if [[ ! -d "${fw_path}" ]]; then 279 | echo "Path ${fw_path} not found. Please install the rpi-eeprom package first" 280 | exit 1 281 | fi 282 | if [[ "${BOOTLOADER_REV_IN}" != "master" ]]; then 283 | echo "Non default bootloader revision specified (${BOOTLOADER_REV_IN}) deleting local bootloader binaries in ${fw_path}" 284 | rm -f "${fw_path}/recovery.bin" 285 | rm -f "${fw_path}"/pieeprom*.bin 286 | fi 287 | if [[ ! -f "${fw_path}/${latest_eeprom}" ]]; then 288 | eeprom_temp="$(mktemp)" 289 | if ! eval curl -fs ${CURL_OPTIONS} "${BOOTLOADER_REPO_CONTENT_URI}/${BOOTLOADER_REV}/firmware-${bcm_chip}/latest/${latest_eeprom}" --output "${eeprom_temp}"; then 290 | echo " !!! Failed to download firmware-${bcm_chip}/${latest_eeprom}" 291 | rm -rf "${eeprom_temp}" 292 | exit 1 293 | fi 294 | mv "${eeprom_temp}" "${fw_path}/${latest_eeprom}" 295 | chmod a+r "${fw_path}/${latest_eeprom}" 296 | fi 297 | 298 | # Always download the latest recovery.bin if bootloader_rev has changed. 299 | recovery_temp="$(mktemp)" 300 | if ! eval curl -fs ${CURL_OPTIONS} "${BOOTLOADER_REPO_CONTENT_URI}/${BOOTLOADER_REV}/firmware-${bcm_chip}/latest/recovery.bin" --output "${recovery_temp}"; then 301 | echo " !!! Failed to download ${bcm_chip}/recovery.bin" 302 | rm -rf "${recovery_temp}" 303 | exit 1 304 | fi 305 | mv "${recovery_temp}" "${fw_path}/recovery.bin" 306 | chmod a+r "${fw_path}/recovery.bin" 307 | fi 308 | } 309 | 310 | function download_bootloader { 311 | if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then 312 | echo "Downloading bootloader tools" 313 | download_bootloader_tools 314 | 315 | echo "Downloading bootloader images" 316 | if grep -q "bcm2711" /proc/device-tree/compatible; then 317 | download_bootloader_images 2711 318 | fi 319 | if grep -q "bcm2712" /proc/device-tree/compatible; then 320 | download_bootloader_images 2712 321 | fi 322 | fi 323 | } 324 | 325 | function update_bootloader { 326 | if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then 327 | if grep -q "bcm2712" /proc/device-tree/compatible; then 328 | # Prefer flashrom on BCM2712. rpi-eeprom-update will failover to recovery.bin 329 | # if flashrom is not installed. 330 | export RPI_EEPROM_USE_FLASHROM=${RPI_EEPROM_USE_FLASHROM:-1} 331 | fi 332 | sed /etc/default/rpi-eeprom-update -i -e "s/^FIRMWARE_RELEASE_STATUS.*/FIRMWARE_RELEASE_STATUS=\"latest\"/" 333 | if [[ "${BOOTLOADER_REV_IN}" != "master" ]]; then 334 | # Use latest according to rpi-eeprom git hash 335 | echo "Using latest bootloader from rpi-eeprom ${BOOTLOADER_REV_IN}" 336 | config_temp="$(mktemp)" 337 | if ! rpi-eeprom-config > "${config_temp}"; then 338 | echo "Failed to read current bootloader config" 339 | exit 1 340 | fi 341 | if ! rpi-eeprom-config -a "${config_temp}"; then 342 | echo "Failed to update bootloader - rpi-eeprom-rev ${BOOTLOADER_REV_IN}" 343 | exit 1 344 | fi 345 | rm -f "${config_temp}" 346 | else 347 | # Update if newer 348 | rpi-eeprom-update -a 349 | fi 350 | fi 351 | } 352 | 353 | function show_notice { 354 | local NOTICE_URI=${FIRMWARE_REPO_CONTENT_URI}/${FW_REV}/NOTICE.md 355 | local FULL_NOTICE=$(eval curl -fs ${CURL_OPTIONS} "${NOTICE_URI}") 356 | if [ -z "${FULL_NOTICE}" ]; then 357 | return 358 | fi 359 | local NOTICE_HASH_HEAD=$(echo "${FULL_NOTICE}" | head -1) 360 | if [ "$(echo "${NOTICE_HASH_HEAD}" | awk -F: '{print $1}')" == "HASH" ]; then 361 | local NOTICE_HASH_EXISTS=true 362 | local NOTICE_HASH=$(echo "${NOTICE_HASH_HEAD}" | awk '{print $2}') 363 | else 364 | local NOTICE_HASH_EXISTS=false 365 | fi 366 | if ${NOTICE_HASH_EXISTS}; then 367 | local NOTICE=$(echo "${FULL_NOTICE}" | tail -n+2) 368 | local NEW_HASH=${FW_REV} 369 | local LOCAL_lt_NOTICE=$(compare_hashes "${FIRMWARE_REPO_API_URI}" "${LOCAL_HASH}" lt "${NOTICE_HASH}") 370 | local NEW_ge_NOTICE=$(compare_hashes "${FIRMWARE_REPO_API_URI}" "${NEW_HASH}" ge "${NOTICE_HASH}") 371 | if ! ${LOCAL_lt_NOTICE} && ! ${NEW_ge_NOTICE}; then 372 | return 373 | fi 374 | else 375 | local NOTICE=${FULL_NOTICE} 376 | fi 377 | echo "${NOTICE}" 378 | if ! echo "${NOTICE}" | grep -q WARNING; then 379 | return 380 | fi 381 | if [[ ${SKIP_WARNING} -ne 0 ]]; then 382 | return 383 | fi 384 | read -p "Would you like to proceed? (y/N)" -n 1 -r -s 385 | echo "" 386 | if ! [[ $REPLY =~ ^[Yy]$ ]]; then 387 | exit 1; 388 | fi 389 | } 390 | 391 | function check_partition { 392 | mbs=$1 393 | if [[ ${SKIP_CHECK_PARTITION} -ne 0 ]]; then 394 | return 395 | fi 396 | local PARTSIZE=0 397 | if command -v df > /dev/null 2>&1 ; then 398 | local M=$(df -P ${BOOT_PATH} | awk 'END{print $1}') 399 | if [[ $M == /dev/* ]]; then 400 | if command -v lsblk > /dev/null 2>&1 ; then 401 | PARTSIZE=$(lsblk -bno SIZE ${M}) 402 | fi 403 | fi 404 | fi 405 | if [ $PARTSIZE -ne 0 ] && [ $PARTSIZE -lt $(( mbs*1024*1024 )) ]; then 406 | echo "Partition size $(( $PARTSIZE >> 20 ))M may not be sufficient for all firmware files" 407 | echo "This could result in a system that will not boot." 408 | echo "${mbs}M FAT partition is recommended. Ensure you have a backup if continuing." 409 | if [[ ${SKIP_WARNING} -ne 0 ]]; then 410 | return 411 | fi 412 | read -p "Would you like to proceed? (y/N)" -n 1 -r -s 413 | echo "" 414 | if ! [[ $REPLY =~ ^[Yy]$ ]]; then 415 | exit 1; 416 | fi 417 | fi 418 | } 419 | 420 | function check_initramfs { 421 | local INITRAMFS="" 422 | if command -v vcgencmd > /dev/null; then 423 | INITRAMFS="$(echo =$(vcgencmd get_config ramfsfile) | cut -d'=' -f3)" 424 | fi 425 | if [ "$INITRAMFS" == "" ]; then 426 | return 427 | fi 428 | if [[ ${SKIP_WARNING} -ne 0 ]]; then 429 | return 430 | fi 431 | echo "Updating a system with initramfs configured is not supported by rpi-update" 432 | echo "This could result in a system that will not boot." 433 | read -p "Would you like to proceed? (y/N)" -n 1 -r -s 434 | echo "" 435 | if ! [[ $REPLY =~ ^[Yy]$ ]]; then 436 | exit 1; 437 | fi 438 | } 439 | 440 | 441 | function update_firmware { 442 | if [[ ${SKIP_FIRMWARE} -eq 0 ]]; then 443 | echo " *** Updating firmware" 444 | rm -rf "${FW_PATH}/"start*.elf 445 | rm -rf "${FW_PATH}/"fixup*.dat 446 | rm -rf "${FW_PATH}/"bootcode.bin 447 | if [[ ${WANT_PI4} -eq 1 ]]; then 448 | cp "${FW_REPOLOCAL}/"start*.elf "${FW_PATH}/" 449 | cp "${FW_REPOLOCAL}/"fixup*.dat "${FW_PATH}/" 450 | else 451 | cp "${FW_REPOLOCAL}/"start{,[^4]*}.elf "${FW_PATH}/" 452 | cp "${FW_REPOLOCAL}/"fixup{,[^4]*}.dat "${FW_PATH}/" 453 | fi 454 | cp "${FW_REPOLOCAL}/"*.bin "${FW_PATH}/" 455 | fi 456 | if [[ ${SKIP_KERNEL} -eq 0 ]]; then 457 | if [[ ${WANT_32BIT} -eq 1 ]]; then 458 | [[ -e "${FW_REPOLOCAL}/"kernel.img ]] && cp "${FW_REPOLOCAL}/"kernel.img "${FW_PATH}/" 459 | [[ -e "${FW_REPOLOCAL}/"kernel7.img ]] && cp "${FW_REPOLOCAL}/"kernel7.img "${FW_PATH}/" 460 | if [[ ${WANT_PI4} -eq 1 ]]; then 461 | [[ -e "${FW_REPOLOCAL}/"kernel7l.img ]] && cp "${FW_REPOLOCAL}/"kernel7l.img "${FW_PATH}/" 462 | fi 463 | fi 464 | if [[ ${WANT_64BIT} -eq 1 ]]; then 465 | [[ -e "${FW_REPOLOCAL}/"kernel8.img ]] && cp "${FW_REPOLOCAL}/"kernel8.img "${FW_PATH}/" 466 | fi 467 | if [[ ${WANT_64BIT_RT} -eq 1 ]]; then 468 | [[ -e "${FW_REPOLOCAL}/"kernel8_rt.img ]] && cp "${FW_REPOLOCAL}/"kernel8_rt.img "${FW_PATH}/" 469 | fi 470 | if [[ ${WANT_PI5} -eq 1 ]]; then 471 | [[ -e "${FW_REPOLOCAL}/"kernel_2712.img ]] && cp "${FW_REPOLOCAL}/"kernel_2712.img "${FW_PATH}/" 472 | [[ -e "${FW_REPOLOCAL}/"kernel2712.img ]] && cp "${FW_REPOLOCAL}/"kernel2712.img "${FW_PATH}/"kernel_2712.img 473 | fi 474 | if [[ -n $(shopt -s nullglob; echo "${FW_REPOLOCAL}/"*.dtb*) ]]; then 475 | cp "${FW_REPOLOCAL}/"*.dtb* "${FW_PATH}/" 476 | fi 477 | if [[ -n $(shopt -s nullglob; echo "${FW_REPOLOCAL}/overlays/"*.dtb*) ]]; then 478 | mkdir -p "${FW_PATH}/overlays" 479 | cp "${FW_REPOLOCAL}/overlays/"*.dtb* "${FW_PATH}/overlays/" 480 | if [[ -f "${FW_REPOLOCAL}/overlays/README" ]]; then 481 | cp "${FW_REPOLOCAL}/overlays/README" "${FW_PATH}/overlays/" 482 | fi 483 | fi 484 | else 485 | echo " *** As requested, not updating kernel" 486 | fi 487 | if [[ ${WANT_SYMVERS} -ne 0 ]]; then 488 | if [[ -f "${FW_REPOLOCAL}/Module.symvers" ]]; then 489 | cp "${FW_REPOLOCAL}/Module.symvers" "${FW_PATH}/" 490 | fi 491 | if [[ -f "${FW_REPOLOCAL}/Module7.symvers" ]]; then 492 | cp "${FW_REPOLOCAL}/Module7.symvers" "${FW_PATH}/" 493 | fi 494 | if [[ -f "${FW_REPOLOCAL}/git_hash" ]]; then 495 | cp "${FW_REPOLOCAL}/git_hash" "${FW_PATH}/" 496 | fi 497 | fi 498 | } 499 | 500 | function finalise { 501 | if [[ -f "${FW_PATH}/arm192_start.elf" ]]; then 502 | echo " *** Setting 192M ARM split" 503 | cp "${FW_PATH}/arm192_start.elf" "${FW_PATH}/start.elf" 504 | fi 505 | if [[ -e ${ROOT_PATH}/etc ]]; then 506 | echo " *** Running ldconfig" 507 | ldconfig -r "${ROOT_PATH}" 508 | fi 509 | echo " *** Storing current firmware revision" 510 | echo "${FW_REV}" > "${FW_REVFILE}" 511 | echo "${BOOTLOADER_REV}" > "${BOOTLOADER_REVFILE}" 512 | } 513 | 514 | function do_backup { 515 | if [[ ${SKIP_BACKUP} -eq 0 ]]; then 516 | echo " *** Backing up files (this will take a few minutes)" 517 | local OLD_FW_PATH="${BOOT_PATH}.bak" 518 | if [[ -d "${OLD_FW_PATH}" ]]; then 519 | echo " *** Remove old firmware backup" 520 | rm -rf "${OLD_FW_PATH}" 521 | fi 522 | echo " *** Backing up firmware" 523 | cp -a "${FW_PATH}" "${OLD_FW_PATH}" 524 | if [[ ${SKIP_KERNEL} -eq 0 ]]; then 525 | OLD_FW_MODPATH=${FW_MODPATH}.bak 526 | if [[ -d "${OLD_FW_MODPATH}" ]]; then 527 | echo " *** Remove old modules backup" 528 | rm -rf "${OLD_FW_MODPATH}" 529 | fi 530 | echo " *** Backing up modules $(uname -r)" 531 | local CURRENT_FW_MODPATH=${FW_MODPATH}/$(uname -r) 532 | if [[ -d "${CURRENT_FW_MODPATH}" ]]; then 533 | mkdir -p "${OLD_FW_MODPATH}" && cp -a "${CURRENT_FW_MODPATH}" "${OLD_FW_MODPATH}" 534 | fi 535 | fi 536 | fi 537 | } 538 | 539 | function do_update { 540 | if [ -f ${FW_PATH}/kernel.img ] || [ -f ${FW_PATH}/kernel7.img ]; then 541 | WANT_32BIT=${WANT_32BIT:-1} 542 | fi 543 | if [ -f ${FW_PATH}/kernel7l.img ]; then 544 | WANT_32BIT=${WANT_32BIT:-1} 545 | fi 546 | if [ -f ${FW_PATH}/kernel8.img ]; then 547 | WANT_64BIT=${WANT_64BIT:-1} 548 | fi 549 | if [ -f ${FW_PATH}/kernel8_rt.img ]; then 550 | WANT_64BIT_RT=${WANT_64BIT_RT:-1} 551 | fi 552 | if [ -f ${FW_PATH}/start4.elf ] || [ -f ${BOOT_PATH}/start4.elf ]; then 553 | WANT_PI4=${WANT_PI4:-1} 554 | fi 555 | if [ -f ${FW_PATH}/kernel_2712.img ]; then 556 | WANT_PI5=${WANT_PI5:-1} 557 | fi 558 | WANT_32BIT=${WANT_32BIT:-0} 559 | WANT_64BIT=${WANT_64BIT:-0} 560 | WANT_64BIT_RT=${WANT_64BIT_RT:-0} 561 | WANT_PI4=${WANT_PI4:-0} 562 | WANT_PI5=${WANT_PI5:-0} 563 | echo "WANT_32BIT:${WANT_32BIT} WANT_64BIT:${WANT_64BIT} WANT_64BIT_RT:${WANT_64BIT_RT} WANT_PI4:${WANT_PI4} WANT_PI5:${WANT_PI5}" 564 | if [[ ${WANT_PI5} -eq 1 ]]; then 565 | check_partition 512 566 | elif [[ ${WANT_PI4} -eq 1 ]]; then 567 | check_partition 256 568 | fi 569 | check_initramfs 570 | show_notice 571 | download_bootloader 572 | download_rev 573 | if [[ -f "${FW_REPOLOCAL}/pre-install" ]]; then 574 | echo " *** Running pre-install script" 575 | source "${FW_REPOLOCAL}/pre-install" 576 | fi 577 | update_bootloader 578 | update_firmware 579 | update_modules 580 | update_vc_libs 581 | update_sdk 582 | finalise 583 | if [[ -f "${FW_REPOLOCAL}/post-install" ]]; then 584 | echo " *** Running post-install script" 585 | source "${FW_REPOLOCAL}/post-install" 586 | fi 587 | remove_rev 588 | echo " *** Syncing changes to disk" 589 | sync 590 | echo " *** If no errors appeared, your firmware was successfully updated to ${FW_REV}" 591 | if [[ "${ROOT_PATH}" == "/" ]]; then 592 | if [[ ${RPI_REBOOT} -ne 0 ]]; then 593 | echo " *** Rebooting to activate the new firmware" 594 | reboot 595 | else 596 | echo " *** A reboot is needed to activate the new firmware" 597 | fi 598 | fi 599 | } 600 | 601 | function download_rev { 602 | if [[ "${ARTIFACT}" != "" ]]; then 603 | if [[ -f ${FW_REV_IN} ]]; then 604 | GET="cat" 605 | else 606 | GET="curl ${CURL_OPTIONS}" 607 | fi 608 | echo " *** Downloading specific artifact revision (this will take a few minutes)" 609 | rm -rf "${FW_REPOLOCAL}" 610 | mkdir -p "${FW_REPOLOCAL}" 611 | for build in ${BUILD}; do 612 | if [[ ${FW_REV_IN} != http* ]] && [[ ! -f ${FW_REV_IN} ]]; then 613 | A="${REDIRECTOR_URI}/${ARTIFACT}/${build}" 614 | else 615 | A="${ARTIFACT}" 616 | fi 617 | echo "${GET} ${A} | zcat | tar xf - -C ${FW_REPOLOCAL} --strip-components=2" 618 | if ! eval ${GET} "${A}" | zcat | tar xf - -C "${FW_REPOLOCAL}" --strip-components=2; then 619 | if [[ ${GET} = curl* ]]; then 620 | echo Invalid artifact specified. Response: $( ${GET} "${A}" -o /dev/null -w "%{http_code}" ). 621 | fi 622 | exit 1 623 | fi 624 | done 625 | elif [[ ${SKIP_DOWNLOAD} -eq 0 ]]; then 626 | local FW_TARBALL_URI=${FIRMWARE_REPO_URI}/tarball/${FW_REV} 627 | if ! eval curl -fs ${CURL_OPTIONS} --output /dev/null --head "${FW_TARBALL_URI}"; then 628 | echo "Invalid git hash specified" 629 | exit 1 630 | fi 631 | echo " *** Downloading specific firmware revision (this will take a few minutes)" 632 | rm -rf "${FW_REPOLOCAL}" 633 | mkdir -p "${FW_REPOLOCAL}" 634 | eval curl ${CURL_OPTIONS} "${FW_TARBALL_URI}" | tar xzf - -C "${FW_REPOLOCAL}" --strip-components=1 635 | fi 636 | } 637 | 638 | function remove_rev { 639 | echo " *** Deleting downloaded files" 640 | if [[ ${SKIP_REPODELETE} -eq 0 ]]; then 641 | rm -rf "${FW_REPOLOCAL}" 642 | fi 643 | } 644 | 645 | function noobs_fix { 646 | echo " !!! ${BOOT_PATH} appears to contain NOOBS files" 647 | echo " This may occur if fstab contains incorrect entries." 648 | echo " rpi-update will attempt to correct fstab." 649 | read -p "Would you like to proceed? (y/N)" -n 1 -r -s 650 | echo 651 | if ! [[ $REPLY =~ ^[Yy]$ ]]; then 652 | exit 1; 653 | fi 654 | 655 | if ! grep -qE "/dev/mmcblk0p1\s+/boot" "${ROOT_PATH}/etc/fstab"; then 656 | echo "Unexpected fstab entry" 657 | exit 1 658 | fi 659 | 660 | local ROOTNUM=$(cat "/proc/cmdline" | sed -n 's|.*root=/dev/mmcblk0p\([0-9]*\).*|\1|p') 661 | if [ ! "${ROOTNUM}" ];then 662 | echo "Could not determine root partition." 663 | exit 1 664 | fi 665 | local BOOT_DEV="/dev/mmcblk0p$((ROOTNUM-1))" 666 | local ROOT_DEV="/dev/mmcblk0p${ROOTNUM}" 667 | sed "${ROOT_PATH}/etc/fstab" -e "s|^.*[^#].* / |${ROOT_DEV} / |;s|^.*[^#].* /boot |${BOOT_DEV} /boot |" 668 | read -p "Does this look correct? (y/N)" -n 1 -r -s 669 | echo 670 | if ! [[ $REPLY =~ ^[Yy]$ ]]; then 671 | exit 1; 672 | fi 673 | sed "${ROOT_PATH}/etc/fstab" -i -e "s|^.*[^#].* / |${ROOT_DEV} / |;s|^.*[^#].* /boot |${BOOT_DEV} /boot |" 674 | 675 | umount "${BOOT_PATH}" 676 | if [ $? -ne 0 ]; then 677 | echo "Failed to umount ${BOOT_PATH}. Remount manually and try again." 678 | exit 1 679 | else 680 | mount "/boot" 681 | fi 682 | 683 | } 684 | 685 | function get_hash_date { 686 | local COMMITS_API_URI=${1}/commits/$2 687 | eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${COMMITS_API_URI}" | grep "date" | head -1 | awk -F\" '{print $4}' 688 | } 689 | 690 | function compare_hashes { 691 | local DATE1=$(get_hash_date "${1}" "$2") 692 | local DATE2=$(get_hash_date "${1}" "$4") 693 | if [ $(date -d "${DATE1}" +%s) -$3 $(date -d "${DATE2}" +%s) ]; then 694 | echo true 695 | else 696 | echo false 697 | fi 698 | } 699 | 700 | function get_long_hash { 701 | # ask github for long version hash 702 | local COMMITS_API_URI=${1}/commits/$2 703 | eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${COMMITS_API_URI}" | awk 'BEGIN {hash=""} { if (hash == "" && $1 == "\"sha\":") {hash=substr($2, 2, 40);} } END {print hash}' 704 | } 705 | 706 | function print_diffs { 707 | local DIFF_API_URI="$1" 708 | SEPARATOR="======================================================" 709 | eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${DIFF_API_URI}" | awk -v SEPARATOR="${SEPARATOR}" -F\" ' { if ($2 == "commits") {commits=1} if (commits && $2 == "message") {print SEPARATOR "\nCommit: " $4} }' | sed 's/\\n\\n/\nCommit:\ /g' 710 | } 711 | 712 | 713 | if [[ ${EUID} -ne 0 ]]; then 714 | echo " !!! This tool must be run as root" 715 | exit 1 716 | fi 717 | 718 | echo " *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom" 719 | 720 | if [[ ! -d ${WORK_PATH} ]]; then 721 | echo " !!! ${WORK_PATH} doesn't exist - creating" 722 | mkdir -p "${WORK_PATH}" 723 | fi 724 | 725 | if [[ ${UPDATE_SELF} -ne 0 ]]; then 726 | update_self 727 | else 728 | rm -f "${SELFUPDATE_SCRIPT}" 729 | fi 730 | 731 | if [ "${BRANCH:-"unset"}" != "unset" ]; then 732 | echo 'Using the BRANCH variable is deprecated. Just use "rpi-update "'. 733 | exit 734 | fi 735 | 736 | if [[ ! -d "${FW_PATH}" ]]; then 737 | echo " !!! ${FW_PATH} doesn't exist - creating" 738 | mkdir -p "${FW_PATH}" 739 | fi 740 | 741 | if [[ ${SKIP_KERNEL} -eq 0 ]] && [[ ! -d "${FW_MODPATH}" ]]; then 742 | echo " !!! ${FW_MODPATH} doesn't exist - creating" 743 | mkdir -p "${FW_MODPATH}" 744 | fi 745 | 746 | if [[ ${NOOBS_CHECK} -eq 1 ]] && [[ -f "${BOOT_PATH}/recovery.elf" ]]; then 747 | noobs_fix 748 | fi 749 | 750 | command -v readelf >/dev/null 2>&1 || { 751 | echo " !!! This tool requires you have readelf installed, please install it first" 752 | echo " In Debian, try: sudo apt-get install binutils" 753 | echo " In Arch, try: pacman -S binutils" 754 | exit 1 755 | } 756 | 757 | FW_REV_IN=${FW_REV_IN:-master} 758 | BOOTLOADER_REV_IN=${BOOTLOADER_REV_IN:-master} 759 | 760 | ARTIFACT="" 761 | BUILD="" 762 | FW_REV="" 763 | if [[ ${FW_REV_IN} != http* ]] && [[ ! -f ${FW_REV_IN} ]]; then 764 | FW_REV=$(get_long_hash "${FIRMWARE_REPO_API_URI}" "${FW_REV_IN}") 765 | fi 766 | 767 | echo FW_REV:$FW_REV 768 | 769 | BOOTLOADER_REV="" 770 | BOOTLOADER_LOCAL_HASH="" 771 | if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then 772 | if [[ ${BOOTLOADER_REV_IN} != http* ]] && [[ ! -f ${BOOTLOADER_REV_IN} ]]; then 773 | BOOTLOADER_REV=$(get_long_hash "${BOOTLOADER_REPO_API_URI}" "${BOOTLOADER_REV_IN}") 774 | fi 775 | echo BOOTLOADER_REV:$BOOTLOADER_REV 776 | fi 777 | 778 | if [[ "${FW_REV}" == "" ]]; then 779 | if [[ ${FW_REV_IN} != http* ]] && [[ ! -f ${FW_REV_IN} ]]; then 780 | IFS=':' read ARTIFACT BUILD <<<${FW_REV_IN} 781 | if [[ "${BUILD}" == "" ]]; then 782 | BUILD="bcmrpi bcm2709 bcm2711 bcm2711_rt bcm2712" 783 | fi 784 | if [[ "${ARTIFACT}" == pulls/* ]]; then 785 | PULL=${ARTIFACT##*/} 786 | ARTIFACT=$(eval curl ${CURL_OPTIONS_API} -s "${LINUX_REPO_API_URI}/pulls/${PULL}" | awk '/"sha":/ {gsub(/"/, "", $2); gsub(/,/, "", $2); print $2; exit}') 787 | else 788 | ARTIFACT=$(eval curl ${CURL_OPTIONS_API} -s "${LINUX_REPO_API_URI}/actions/artifacts?per_page=100" | grep -A1 "\"head_branch\": \"${FW_REV_IN}\"" | awk '/"head_sha":/ {gsub(/"/, "", $2); gsub(/,/, "", $2); print $2; exit}') 789 | fi 790 | else 791 | ARTIFACT=${FW_REV_IN} 792 | BUILD=dummy 793 | fi 794 | FW_REV=${ARTIFACT} 795 | SKIP_FIRMWARE=1 796 | SKIP_SDK=1 797 | SKIP_VCLIBS=1 798 | fi 799 | 800 | if [[ "${FW_REV}" == "" ]] && [[ "$FW_REPOLOCAL" == "${WORK_PATH}/.rpi-firmware" ]]; then 801 | echo " *** Invalid hash given" 802 | exit 1 803 | fi 804 | 805 | if [ ! -d "/lib/firmware/raspberrypi/bootloader-2711/latest" ]; then 806 | if [[ "${SKIP_BOOTLOADER}" != 1 ]]; then 807 | # The chip specific firmware directory structure is required for rpi-eeprom updates 808 | # RPi OS Bookworm or newer required. 809 | SKIP_BOOTLOADER=1 810 | echo "rpi-eeprom firmware package appears to be too old. Skipping bootloader updates" 811 | fi 812 | fi 813 | 814 | if [[ ! -f "${FW_REVFILE}" ]]; then 815 | LOCAL_HASH=0 816 | echo " *** We're running for the first time" 817 | if [[ ${JUST_CHECK} -ne 0 ]]; then 818 | echo " *** Firmware update required. No local hash to compare to." 819 | exit 2 820 | fi 821 | do_backup 822 | else 823 | if [[ "${ARTIFACT}" != "" ]]; then 824 | LOCAL_HASH=$(cat "${FW_REVFILE}") 825 | if [[ "${SKIP_BOOTLOADER}" -eq 0 ]]; then 826 | BOOTLOADER_LOCAL_HASH=$(cat "${BOOTLOADER_REVFILE}") 827 | fi 828 | else 829 | LOCAL_HASH=$(get_long_hash ${FIRMWARE_REPO_API_URI} "$(cat "${FW_REVFILE}")") 830 | if [[ "${SKIP_BOOTLOADER}" -eq 0 ]]; then 831 | if [[ ! -f "${BOOTLOADER_REVFILE}" ]]; then 832 | BOOTLOADER_LOCAL_HASH=0 833 | else 834 | BOOTLOADER_LOCAL_HASH=$(get_long_hash "${BOOTLOADER_REPO_API_URI}" "$(cat "${BOOTLOADER_REVFILE}")") 835 | fi 836 | fi 837 | fi 838 | 839 | if [[ "${LOCAL_HASH}" == "${FW_REV}" && "${BOOTLOADER_LOCAL_HASH}" == "${BOOTLOADER_REV}" ]] ; then 840 | echo " *** Your firmware is already up to date (delete ${FW_REVFILE} and ${BOOTLOADER_REVFILE} to force an update anyway)" 841 | exit 0 842 | else 843 | if [[ "${LOCAL_HASH}" == "${FW_REV}" ]]; then 844 | # Skip other components if only the bootloader has changed 845 | SKIP_FIRMWARE=1 846 | SKIP_KERNEL=1 847 | SKIP_VCLIBS=1 848 | SKIP_SDK=1 849 | SKIP_DOWNLOAD=1 850 | ARTIFACT="" 851 | elif [[ "${BOOTLOADER_LOCAL_HASH}" == "${BOOTLOADER_REV}" ]] ; then 852 | SKIP_BOOTLOADER=1 853 | fi 854 | fi 855 | 856 | if [[ ${JUST_CHECK} -ne 0 ]]; then 857 | if $(compare_hashes "${FIRMWARE_REPO_API_URI}" "${LOCAL_HASH}" lt "${FW_REV}"); then 858 | echo " *** Firmware update required. New commits available:" 859 | DIFF_URI=${FIRMWARE_REPO_API_URI}/compare/${LOCAL_HASH}...${FW_REV} 860 | print_diffs "${DIFF_URI}" 861 | elif $(compare_hashes "${FIRMWARE_REPO_API_URI}" "${LOCAL_HASH}" gt "${FW_REV}"); then 862 | echo " *** Firmware downgrade requested. Commits to drop:" 863 | DIFF_URI=${FIRMWARE_REPO_API_URI}/compare/${FW_REV}...${LOCAL_HASH} 864 | print_diffs "${DIFF_URI}" 865 | fi 866 | 867 | if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then 868 | if $(compare_hashes "${BOOTLOADER_REPO_API_URI}" "${BOOTLOADER_LOCAL_HASH}" lt "${BOOTLOADER_REV}"); then 869 | echo " *** Bootloader update required. New commits available:" 870 | DIFF_URI=${BOOTLOADER_REPO_API_URI}/compare/${BOOTLOADER_LOCAL_HASH}...${BOOTLOADER_REV} 871 | print_diffs "${DIFF_URI}" 872 | elif $(compare_hashes "${BOOTLOADER_REPO_API_URI}" "${BOOTLOADER_LOCAL_HASH}" gt "${BOOTLOADER_REV}"); then 873 | echo " *** Bootloader downgrade requested. Commits to drop:" 874 | DIFF_URI=${BOOTLOADER_REPO_API_URI}/compare/${BOOTLOADER_REV}...${BOOTLOADER_LOCAL_HASH} 875 | print_diffs "${DIFF_URI}" 876 | fi 877 | fi 878 | exit 2 879 | fi 880 | fi 881 | 882 | do_update 883 | --------------------------------------------------------------------------------