mirror of
https://github.com/raspberrypi/rpi-eeprom.git
synced 2026-01-20 21:13:36 +08:00
Compare commits
63 Commits
v2023.12.0
...
v2024.06.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e430a41e73 | ||
|
|
ab087e5db1 | ||
|
|
80be2d6d14 | ||
|
|
88f96b4f86 | ||
|
|
cf3cadf994 | ||
|
|
61fb89536f | ||
|
|
768f4fbc69 | ||
|
|
2b2c8103ff | ||
|
|
2bfd7cb74e | ||
|
|
9a5a522ee8 | ||
|
|
7a1a01c24f | ||
|
|
f4580cd6f5 | ||
|
|
c0a207f452 | ||
|
|
76b990a894 | ||
|
|
afa5822e03 | ||
|
|
a2fb4ed28d | ||
|
|
ca7a39efe9 | ||
|
|
c94506e598 | ||
|
|
61023cbd32 | ||
|
|
d8abe8c67d | ||
|
|
14f05613b4 | ||
|
|
07bf72a919 | ||
|
|
b745226b41 | ||
|
|
c478689de0 | ||
|
|
8c67b27665 | ||
|
|
18620870d7 | ||
|
|
11c64e3721 | ||
|
|
36e58db5c2 | ||
|
|
b1a715b256 | ||
|
|
0e8ecbcf83 | ||
|
|
d4918d4d4c | ||
|
|
b5c7f1bee6 | ||
|
|
c987375f1d | ||
|
|
99cb0bdaa2 | ||
|
|
a8f2eb75b5 | ||
|
|
606c5d25e5 | ||
|
|
88b33ab030 | ||
|
|
a7f982962b | ||
|
|
9df346bc1c | ||
|
|
68fca2166b | ||
|
|
eca47c5f4c | ||
|
|
097e2d0573 | ||
|
|
4b8e875510 | ||
|
|
21a78a91de | ||
|
|
cc020609fb | ||
|
|
d5f1ab30fa | ||
|
|
8855da9889 | ||
|
|
a5b4f91caf | ||
|
|
7232154170 | ||
|
|
759460850c | ||
|
|
9e0bffb291 | ||
|
|
258d0114c0 | ||
|
|
0cd761bc84 | ||
|
|
72cedfe5ee | ||
|
|
14e934cee3 | ||
|
|
e407fb0030 | ||
|
|
b405ed7465 | ||
|
|
ef0cfffced | ||
|
|
a66e79ba99 | ||
|
|
745eabf90e | ||
|
|
043841636c | ||
|
|
3f325bd482 | ||
|
|
52c5d89d48 |
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
value: |
|
||||
**Is this the right place for my bug report?**
|
||||
|
||||
* This repository contains the Raspberry Pi 4, Pi400 and CM4 bootloader EEPROM images and installation scripts.
|
||||
* This repository contains the Raspberry Pi 5, Raspberry Pi 4, Pi400, CM4 and CM4-S bootloader EEPROM images and installation scripts.
|
||||
* Please report boot issues for the earlier models at the GPU firmware repo [github.com/raspberrypi/firmware](https://github.com/raspberrypi/firmware).
|
||||
* Please report USB issues which occur after the OS has started at the Linux repo [github.com/raspberrypi/linux/](https://github.com/raspberrypi/linux/).
|
||||
* If you simply have a question, then [the Raspberry Pi forums](https://www.raspberrypi.org/forums) are the best place to ask it.
|
||||
@@ -39,10 +39,12 @@ body:
|
||||
description: On which device you are facing the bug?
|
||||
multiple: true
|
||||
options:
|
||||
- Raspberry Pi 5
|
||||
- Raspberry Pi 4 Mod. B
|
||||
- Raspberry Pi 400
|
||||
- Raspberry Pi CM4
|
||||
- Raspberry Pi CM4 Lite
|
||||
- Raspberry Pi CM4-S
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
@@ -52,7 +54,7 @@ body:
|
||||
attributes:
|
||||
label: Bootloader configuration.
|
||||
description: |
|
||||
Copy and paste the results of `vcgencmd bootloader_config` or describe the failing configuration.
|
||||
Copy and paste the results of `rpi-eeprom-config` or describe the failing configuration.
|
||||
|
||||
* `rpi-eeprom-update` saves a backup of the previous bootloader configuration to `/var/lib/raspberrypi/bootloader/backup` before it schedules the update.
|
||||
* `rpi-eeprom-config pieeprom.upd` can be used to read the contents of an EEPROM image.
|
||||
|
||||
22
LICENSE
22
LICENSE
@@ -93,3 +93,25 @@ License: uIP
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
License: MIT
|
||||
QR Code generator library (C)
|
||||
|
||||
Copyright (c) Project Nayuki. (MIT License)
|
||||
https://www.nayuki.io/page/qr-code-generator-library
|
||||
|
||||
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:
|
||||
- The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
- 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.
|
||||
|
||||
@@ -9,7 +9,7 @@ To reset the bootloader back to factory defaults use [Raspberry Pi Imager](https
|
||||
|
||||
# Bootloader documentation
|
||||
* [Config.txt boot options](https://www.raspberrypi.com/documentation/computers/config_txt.html#boot-options)
|
||||
* [Bootloader EEPROM](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-4-boot-eeprom)
|
||||
* [Bootloader configuration](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-4-bootloader-configuration)
|
||||
* [Bootloader EEPROM](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-boot-eeprom)
|
||||
* [Bootloader configuration](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-bootloader-configuration)
|
||||
* [Updating the Compute Module 4 bootloader](https://www.raspberrypi.com/documentation/computers/compute-module.html#cm4bootloader)
|
||||
* [Releases and release notes](releases.md)
|
||||
|
||||
BIN
firmware-2711/default/pieeprom-2024-04-15.bin
Normal file
BIN
firmware-2711/default/pieeprom-2024-04-15.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
firmware-2711/latest/pieeprom-2024-01-18.bin
Normal file
BIN
firmware-2711/latest/pieeprom-2024-01-18.bin
Normal file
Binary file not shown.
BIN
firmware-2711/latest/pieeprom-2024-01-22.bin
Normal file
BIN
firmware-2711/latest/pieeprom-2024-01-22.bin
Normal file
Binary file not shown.
BIN
firmware-2711/latest/pieeprom-2024-04-15.bin
Normal file
BIN
firmware-2711/latest/pieeprom-2024-04-15.bin
Normal file
Binary file not shown.
BIN
firmware-2711/latest/pieeprom-2024-04-17.bin
Normal file
BIN
firmware-2711/latest/pieeprom-2024-04-17.bin
Normal file
Binary file not shown.
BIN
firmware-2711/latest/pieeprom-2024-05-17.bin
Normal file
BIN
firmware-2711/latest/pieeprom-2024-05-17.bin
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,41 @@
|
||||
# Raspberry Pi4 bootloader EEPROM release notes
|
||||
|
||||
## 2024-05-17 - Ignore bootloader updates for Pi5 on Pi4 - (latest)
|
||||
* Add timestamps to UART log messages.
|
||||
* Add support for [tryboot] conditional the bootloader EEPROM
|
||||
config file.
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/454
|
||||
* Fix MAX_RESTARTS parameter
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/576
|
||||
* Add recovery_reboot option to config.txt for rpiboot which causes
|
||||
the system to reboot after updating the bootloader.
|
||||
* Improve secure-boot OTP provisioning logging.
|
||||
* Fix setting to enable secure-boot mode on Pi4B
|
||||
|
||||
## 2024-04-17 - Build Pi4 firmware from the mainline branch - STABLE
|
||||
* Switch to building the Pi4 firmware from the common Pi4/Pi5
|
||||
mainline release. This doesn't change the Pi4 features
|
||||
but should make it quicker to release bug fixes in common code.
|
||||
* Fix issue that caused the TRYBOOT flag to be lost in secure-boot mode.
|
||||
* dtoverlay: Use %u when converting u32s to strings
|
||||
See: https://github.com/raspberrypi/linux/issues/6039
|
||||
* Improved debug messages for secure-boot.
|
||||
* Generate the bootloader diagnostics qrcode at run time.
|
||||
|
||||
## 2024-04-15 - Fix tryboot mode in secure-boot - DEFAULT
|
||||
* Promote the secure-boot fix to the DEFAULT release.
|
||||
|
||||
## 2024-04-15 - Fix tryboot mode in secure-boot - STABLE
|
||||
* Fix an issue where the tryboot flag was being reset and lost during
|
||||
the secure-boot initialization.
|
||||
|
||||
## 2024-01-22 - Fix issue boot.img end sector check - STABLE
|
||||
* See https://github.com/raspberrypi/rpi-eeprom/issues/521
|
||||
|
||||
## 2024-01-18 - Fix issue with minimal sized FAT partition - STABLE
|
||||
* Fix handling of files that use the last cluster in the partition
|
||||
https://github.com/raspberrypi/rpi-eeprom/issues/521
|
||||
|
||||
## 2023-08-01 - Remove beta release folder
|
||||
* Remove the beta release folder and provide a symlink to stable
|
||||
for backwards compatibility for anyone who has beta in
|
||||
|
||||
BIN
firmware-2712/default/pieeprom-2023-12-14.bin
Normal file
BIN
firmware-2712/default/pieeprom-2023-12-14.bin
Normal file
Binary file not shown.
BIN
firmware-2712/default/pieeprom-2024-01-05.bin
Normal file
BIN
firmware-2712/default/pieeprom-2024-01-05.bin
Normal file
Binary file not shown.
BIN
firmware-2712/default/pieeprom-2024-02-16.bin
Normal file
BIN
firmware-2712/default/pieeprom-2024-02-16.bin
Normal file
Binary file not shown.
BIN
firmware-2712/default/pieeprom-2024-04-17.bin
Normal file
BIN
firmware-2712/default/pieeprom-2024-04-17.bin
Normal file
Binary file not shown.
BIN
firmware-2712/default/pieeprom-2024-04-20.bin
Normal file
BIN
firmware-2712/default/pieeprom-2024-04-20.bin
Normal file
Binary file not shown.
BIN
firmware-2712/default/pieeprom-2024-06-05.bin
Normal file
BIN
firmware-2712/default/pieeprom-2024-06-05.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2023-12-14.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2023-12-14.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-01-05.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-01-05.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-01-15.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-01-15.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-01-22.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-01-22.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-01-24.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-01-24.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-02-05.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-02-05.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-02-08.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-02-08.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-02-14.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-02-14.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-02-16.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-02-16.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-04-05.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-04-05.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-04-17.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-04-17.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-04-18.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-04-18.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-04-20.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-04-20.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-05-13.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-05-13.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-05-17.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-05-17.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-06-04.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-06-04.bin
Normal file
Binary file not shown.
BIN
firmware-2712/latest/pieeprom-2024-06-05.bin
Normal file
BIN
firmware-2712/latest/pieeprom-2024-06-05.bin
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,127 @@
|
||||
# Raspberry Pi5 bootloader EEPROM release notes
|
||||
|
||||
## 2024-06-11: Promote pieeprom-2024-06-05 to the default release (default)
|
||||
|
||||
## 2024-06-05: CM5 bringup changes (latest)
|
||||
* Minor changes to support CM5 bringup and test.
|
||||
|
||||
## 2024-06-04: Fix [pi5] config.txt conditional state (latest)
|
||||
* The [pi5] conditional statement should apply to the entire pi5
|
||||
family i.e. include cm5 as well.
|
||||
* Bump SDIO bus priorities to that a GPU/RAM intensive processes
|
||||
can't unnecessarily stall an I/O processes.
|
||||
* Assorted log message tidyups.
|
||||
|
||||
## 2024-05-17: Ignore bootloader updates for Pi5 on Pi4 - (latest)
|
||||
* Add timestamps to UART log messages
|
||||
|
||||
2024-05-13: Add support for NVMe boot with PCIe switches (latest)
|
||||
* Add preliminary support for booting NVMe devices behind PCIe switches.
|
||||
See: https://github.com/raspberrypi/firmware/issues/1833
|
||||
* Fix MAX_RESTARTS parameter
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/576
|
||||
* arm_dt: Support HAT EEPROM dtparams
|
||||
* Fix reporting of the partition number via DT
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/575
|
||||
* Resolve HID counting bug which caused Network Install to fail on some keyboards
|
||||
See: Fixes https://github.com/raspberrypi/rpi-eeprom/issues/574
|
||||
* Pull PCIE DET_WAKE high by default on CM5
|
||||
|
||||
2024-04-20: Fix SDRAM refesh timing (default) (automatic update)
|
||||
* Fix a possible performance regression on Pi5.
|
||||
|
||||
2024-04-18: Promote the 2024-04-17 release to the default release (default) (automatic update)
|
||||
* Select pieeprom-2024-04-17.bin to be the new default release and bump the
|
||||
automatic update minimum version to this.
|
||||
|
||||
2024-04-18: Update RP1 firmware to extend PCIe L1 entry timeout to 32 us (latest)
|
||||
* Extend PCIe L1 entry timeout to 32us
|
||||
Fix xhci soft reset on link-down
|
||||
Set useful xhci compatibility bits in GUCTL
|
||||
See https://github.com/raspberrypi/firmware/issues/1877
|
||||
|
||||
2024-04-17: Fix TRYBOOT flag in secure-boot mode (latest)
|
||||
* Fix issue that caused the TRYBOOT flag to be lost in secure-boot mode.
|
||||
* dtoverlay: Use %u when converting u32s to strings
|
||||
See: https://github.com/raspberrypi/linux/issues/6039
|
||||
* Improved debug messages for secure-boot.
|
||||
* Generate the bootloader diagnostics qrcode at run time.
|
||||
|
||||
2024-04-05: HAT+ fixes for max-current, custom CA cert for net install and enable over-clocking to > 3GHz (latest)
|
||||
* bootloader: clock_2712: Remove restriction on arm_freq <= 3000
|
||||
See: https://github.com/raspberrypi/firmware/issues/1876
|
||||
* arm_dt: Update max_current to match HAT value
|
||||
* arm_dt: Remove unused legacy parameters (core_freq, arm_freq, uart0_clkrate and cache_line_size)
|
||||
* Add support for custom CA cert for network install
|
||||
You need to specify
|
||||
HTTP_HOST=myhost.com
|
||||
HTTP_PATH=/path/to/files
|
||||
HTTP_CACERT_HASH=<hash>
|
||||
|
||||
where <hash> is a sha256 hash of the der encoded ca certificate.
|
||||
CA cert is added using rpi-eeprom-config.
|
||||
* Optimise Vbat current draw with charging disabled
|
||||
* Display OTP boot status in UART log messages.
|
||||
* Preliminary support for secure-boot OTP provisioning.
|
||||
* Update PCIE DET_WAKE pinmux for D0 products
|
||||
|
||||
2024-02-16: u-boot loading and thermal throttling fixes (latest) (default)
|
||||
* arm_loader: Move non-kernels back to 512KB
|
||||
See: https://github.com/raspberrypi/firmware/issues/1868
|
||||
|
||||
* Limit throttled frequency to OS requested frequency rather than
|
||||
config.txt frequency.
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/518
|
||||
|
||||
2024-02-14: Fix vcgencmd otp_dump and implement C(initial_turbo) (latest)
|
||||
* Fix a regression that caused vcgencmd otp_dump to fail.
|
||||
* Implement C(initial_turbo) on Pi5
|
||||
See: https://github.com/raspberrypi/firmware/issues/1864
|
||||
|
||||
2024-02-08: Adjust SDRAM refresh based on temperature (latest)
|
||||
|
||||
* Adjust the SDRAM refresh interval based on the temperature. This
|
||||
addresses the gap in performance between the 8GB and 4GB variants.
|
||||
See https://github.com/raspberrypi/firmware/issues/1854
|
||||
* Preliminary support for signed boot.
|
||||
|
||||
2024-02-05: Add support for HAT+ POE HATs (latest)
|
||||
* Add support for probing HAT+ POE HATs
|
||||
* Implement DWC3 specific XHCI quirks
|
||||
|
||||
2024-01-24: NVMe boot fix for WD NVMe (latest)
|
||||
* Add a workaround for an issue seen when booting with WD Blue SN550 NVMe SSD
|
||||
|
||||
2024-01-22: Add support for network-install (latest)
|
||||
* Fix issue boot.img end sector check - STABLE
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/521
|
||||
* Fix handling of files that use the last cluster in the partition
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/521
|
||||
* Fix SD card detection
|
||||
See: https://github.com/raspberrypi/rpi-eeprom/issues/523
|
||||
|
||||
2024-01-15: Add support for network-install (latest)
|
||||
* Add support for Network Install
|
||||
* Preliminary D0 firmware support
|
||||
|
||||
2024-01-08: Promote 2024-01-05 to default (automatic update)
|
||||
|
||||
2024-01-05: Fix handling of FAT files without LFNs.
|
||||
* Fix issues with SFN entries sometimes being treated as LFNs
|
||||
see https://github.com/raspberrypi/rpi-eeprom/issues/514
|
||||
* Add a dedicated message for "M.2 HAT" not being found instead of
|
||||
the generic 'unsupported boot order' message when NVMe boot is
|
||||
skipped.
|
||||
|
||||
2023-12-17: Promote 2023-12-14 to default release
|
||||
* Bump to the default release now that the partition number fix is confirmed.
|
||||
|
||||
2023-12-14: Fix boot partition parameter (latest)
|
||||
* Fix an issue where the boot partition parameter in PM_RSTS was cleared
|
||||
before being checked.
|
||||
https://github.com/raspberrypi/firmware/issues/1853
|
||||
* Add a specific fatal error pattern for RP1 not found - 4 long - 3 short
|
||||
|
||||
2023-12-12: Promote 2023-12-06 to default release.
|
||||
|
||||
2023-12-06: Initialise DWC PHY (latest)
|
||||
@@ -40,7 +162,7 @@
|
||||
* Update board-name - "Raspberry Pi 5"
|
||||
|
||||
2023-09-28: vcgencmd pmic_read_adcs fixes (automatic update)
|
||||
|
||||
|
||||
* Fix the LDO names and current scaling codes
|
||||
* Manufacturing test updates
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@ script_dir=$(cd "$(dirname "$0")" && pwd)
|
||||
${script_dir}/make-release critical 2023-01-11 000138c0 "${script_dir}/2711-config" release-2711 rpi-boot-eeprom-recovery 2711
|
||||
|
||||
# Pi5
|
||||
${script_dir}/make-release critical 2023-10-18 "" "${script_dir}/2712-config" release-2712 rpi-boot-eeprom-recovery 2712
|
||||
${script_dir}/make-release critical 2024-06-05 "" "${script_dir}/2712-config" release-2712 rpi-boot-eeprom-recovery 2712
|
||||
|
||||
@@ -90,7 +90,6 @@ rm -rf "${output_dir}"
|
||||
mkdir "${output_dir}"
|
||||
|
||||
# Build the different boot priority flavours
|
||||
gen_release "${config_dir}/boot-conf-default.txt" "${output_dir}/${output_basename}-${tag}.zip"
|
||||
for variant in sd usb network; do
|
||||
gen_release "${config_dir}/boot-conf-${variant}.txt" "${output_dir}/${output_basename}-${tag}-${variant}.zip"
|
||||
done
|
||||
|
||||
@@ -19,6 +19,8 @@ VALID_IMAGE_SIZES = [512 * 1024, 2 * 1024 * 1024]
|
||||
BOOTCONF_TXT = 'bootconf.txt'
|
||||
BOOTCONF_SIG = 'bootconf.sig'
|
||||
PUBKEY_BIN = 'pubkey.bin'
|
||||
CACERT_DER = 'cacert.der'
|
||||
BOOTCODE_BIN = 'bootcode.bin'
|
||||
|
||||
# Each section starts with a magic number followed by a 32 bit offset to the
|
||||
# next section (big-endian).
|
||||
@@ -296,14 +298,22 @@ class BootloaderImage(object):
|
||||
length = -1
|
||||
is_last = False
|
||||
|
||||
next_offset = self._image_size - ERASE_ALIGN_SIZE # Don't create padding inside the bootloader scratch page
|
||||
for i in range(0, len(self._sections)):
|
||||
if filename == BOOTCODE_BIN:
|
||||
next_offset = 0
|
||||
dst_filename = filename
|
||||
i = 0
|
||||
s = self._sections[i]
|
||||
if s.magic == FILE_MAGIC and s.filename == filename:
|
||||
is_last = (i == len(self._sections) - 1)
|
||||
offset = s.offset
|
||||
length = s.length
|
||||
break
|
||||
offset = s.offset
|
||||
length = s.length
|
||||
else:
|
||||
next_offset = self._image_size - ERASE_ALIGN_SIZE # Don't create padding inside the bootloader scratch page
|
||||
for i in range(0, len(self._sections)):
|
||||
s = self._sections[i]
|
||||
if s.magic == FILE_MAGIC and s.filename == filename:
|
||||
is_last = (i == len(self._sections) - 1)
|
||||
offset = s.offset
|
||||
length = s.length
|
||||
break
|
||||
|
||||
# Find the start of the next non padding section
|
||||
i += 1
|
||||
@@ -317,30 +327,43 @@ class BootloaderImage(object):
|
||||
debug('%s offset %d length %d is-last %d next %d' % (filename, ret[0], ret[1], ret[2], ret[3]))
|
||||
return ret
|
||||
|
||||
def update(self, src_bytes, dst_filename):
|
||||
def update(self, src_bytes, dst_filename, bootcode = False):
|
||||
"""
|
||||
Replaces a modifiable file with specified byte array.
|
||||
"""
|
||||
hdr_offset, length, is_last, next_offset = self.find_file(dst_filename)
|
||||
update_len = len(src_bytes) + FILE_HDR_LEN
|
||||
if bootcode:
|
||||
hdr_offset, length, is_last, next_offset = self.find_file(dst_filename)
|
||||
struct.pack_into('>L', self._bytes, hdr_offset + 4, len(src_bytes))
|
||||
struct.pack_into(("%ds" % len(src_bytes)), self._bytes, hdr_offset + 8, src_bytes)
|
||||
pad_start = hdr_offset + len(src_bytes) + 8
|
||||
is_last = False
|
||||
debug("bootcode padded to %d" % next_offset);
|
||||
if next_offset < 128 * 1024:
|
||||
raise Exception("update-bootcode: Can't update image - 128K must be reserved for bootcode")
|
||||
if next_offset < 0:
|
||||
raise Exception("update-bootcode: Failed to find next section")
|
||||
|
||||
if hdr_offset + update_len > self._image_size - ERASE_ALIGN_SIZE:
|
||||
raise Exception('No space available - image past EOF.')
|
||||
else:
|
||||
hdr_offset, length, is_last, next_offset = self.find_file(dst_filename)
|
||||
update_len = len(src_bytes) + FILE_HDR_LEN
|
||||
|
||||
if hdr_offset < 0:
|
||||
raise Exception('Update target %s not found' % dst_filename)
|
||||
if hdr_offset + update_len > self._image_size - ERASE_ALIGN_SIZE:
|
||||
raise Exception('No space available - image past EOF.')
|
||||
|
||||
if hdr_offset + update_len > next_offset:
|
||||
raise Exception('Update %d bytes is larger than section size %d' % (update_len, next_offset - hdr_offset))
|
||||
if hdr_offset < 0:
|
||||
raise Exception('Update target %s not found' % dst_filename)
|
||||
|
||||
new_len = len(src_bytes) + FILENAME_LEN + 4
|
||||
struct.pack_into('>L', self._bytes, hdr_offset + 4, new_len)
|
||||
struct.pack_into(("%ds" % len(src_bytes)), self._bytes,
|
||||
hdr_offset + 4 + FILE_HDR_LEN, src_bytes)
|
||||
if hdr_offset + update_len > next_offset:
|
||||
raise Exception('Update %d bytes is larger than section size %d' % (update_len, next_offset - hdr_offset))
|
||||
|
||||
# If the new file is smaller than the old file then set any old
|
||||
# data which is now unused to all ones (erase value)
|
||||
pad_start = hdr_offset + 4 + FILE_HDR_LEN + len(src_bytes)
|
||||
new_len = len(src_bytes) + FILENAME_LEN + 4
|
||||
struct.pack_into('>L', self._bytes, hdr_offset + 4, new_len)
|
||||
struct.pack_into(("%ds" % len(src_bytes)), self._bytes,
|
||||
hdr_offset + 4 + FILE_HDR_LEN, src_bytes)
|
||||
|
||||
# If the new file is smaller than the old file then set any old
|
||||
# data which is now unused to all ones (erase value)
|
||||
pad_start = hdr_offset + 4 + FILE_HDR_LEN + len(src_bytes)
|
||||
|
||||
# Add padding up to 8-byte boundary
|
||||
while pad_start % 8 != 0:
|
||||
@@ -379,10 +402,11 @@ class BootloaderImage(object):
|
||||
Replaces the contents of dst_filename in the EEPROM with the contents of src_file.
|
||||
"""
|
||||
src_bytes = open(src_filename, 'rb').read()
|
||||
if len(src_bytes) > MAX_FILE_SIZE:
|
||||
bootcode = dst_filename == BOOTCODE_BIN
|
||||
if not bootcode and len(src_bytes) > MAX_FILE_SIZE:
|
||||
raise Exception("src file %s is too large (%d bytes). The maximum size is %d bytes."
|
||||
% (src_filename, len(src_bytes), MAX_FILE_SIZE))
|
||||
self.update(src_bytes, dst_filename)
|
||||
self.update(src_bytes, dst_filename, bootcode)
|
||||
|
||||
def set_timestamp(self, timestamp):
|
||||
"""
|
||||
@@ -408,14 +432,22 @@ class BootloaderImage(object):
|
||||
|
||||
def get_file(self, filename):
|
||||
hdr_offset, length, is_last, next_offset = self.find_file(filename)
|
||||
offset = hdr_offset + 4 + FILE_HDR_LEN
|
||||
file_bytes = self._bytes[offset:offset+length-FILENAME_LEN-4]
|
||||
if filename == BOOTCODE_BIN:
|
||||
offset = hdr_offset + 8
|
||||
file_bytes = self._bytes[offset:offset+length]
|
||||
else:
|
||||
offset = hdr_offset + 4 + FILE_HDR_LEN
|
||||
file_bytes = self._bytes[offset:offset+length-FILENAME_LEN-4]
|
||||
|
||||
return file_bytes
|
||||
|
||||
def extract_files(self):
|
||||
for i in range(0, len(self._sections)):
|
||||
s = self._sections[i]
|
||||
if s.magic == FILE_MAGIC:
|
||||
if s.magic == MAGIC and s.offset == 0:
|
||||
file_bytes = self.get_file(BOOTCODE_BIN)
|
||||
open(BOOTCODE_BIN, 'wb').write(file_bytes)
|
||||
elif s.magic == FILE_MAGIC:
|
||||
file_bytes = self.get_file(s.filename)
|
||||
open(s.filename, 'wb').write(file_bytes)
|
||||
|
||||
@@ -431,6 +463,7 @@ class BootloaderImage(object):
|
||||
sys.stdout.write(config_bytes)
|
||||
|
||||
def main():
|
||||
global DEBUG
|
||||
"""
|
||||
Utility for reading and writing the configuration file in the
|
||||
Raspberry Pi bootloader EEPROM image.
|
||||
@@ -478,7 +511,7 @@ Operating modes:
|
||||
The configuration file will be taken from:
|
||||
* The blconfig reserved memory nvmem device
|
||||
* The cached bootloader configuration 'vcgencmd bootloader_config'
|
||||
* The current pending update - typically /boot/pieeprom.upd
|
||||
* The current pending update - typically /boot/firmware/pieeprom.upd
|
||||
|
||||
sudo -E rpi-eeprom-config --edit [pieeprom.bin]
|
||||
|
||||
@@ -492,8 +525,7 @@ Operating modes:
|
||||
the corresponding RSA public key.
|
||||
|
||||
Requires Python Cryptodomex libraries and OpenSSL. To install on Raspberry Pi OS run:-
|
||||
sudo apt install openssl python-pip
|
||||
sudo python3 -m pip install cryptodomex
|
||||
sudo apt install python3-pycryptodome
|
||||
|
||||
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
|
||||
rpi-eeprom-config --config bootconf.txt --digest bootconf.sig --pubkey public.pem --out pieeprom-signed.bin pieeprom.bin
|
||||
@@ -511,12 +543,16 @@ See 'rpi-eeprom-update -h' for more information about the available EEPROM image
|
||||
parser.add_argument('-c', '--config', help='Name of bootloader configuration file', required=False)
|
||||
parser.add_argument('-e', '--edit', action='store_true', default=False, help='Edit the current EEPROM config')
|
||||
parser.add_argument('-o', '--out', help='Name of output file', required=False)
|
||||
parser.add_argument('-d', '--digest', help='Signed boot only. The name of the .sig file generated by rpi-eeprom-dgst for config.txt ', required=False)
|
||||
parser.add_argument('-d', '--digest', help='Signed boot only. The name of the .sig file generated by rpi-eeprom-digest for config.txt ', required=False)
|
||||
parser.add_argument('-p', '--pubkey', help='Signed boot only. The name of the RSA public key file to store in the EEPROM', required=False)
|
||||
parser.add_argument('-x', '--extract', action='store_true', default=False, help='Extract the modifiable files (boot.conf, pubkey, signature)', required=False)
|
||||
parser.add_argument('-b', '--bootcode', help='Signed boot 2712 only. The name of the customer signed bootcode.bin file to store in the EEPROM', required=False)
|
||||
parser.add_argument('-t', '--timestamp', help='Set the timestamp in the EEPROM image file', required=False)
|
||||
parser.add_argument('--cacertder', help='The name of a CA Certificate DER encoded file to store in the EEPROM', required=False)
|
||||
parser.add_argument('--debug', help='Debug logging for this tool', action='store_true', required=False)
|
||||
parser.add_argument('eeprom', nargs='?', help='Name of EEPROM file to use as input')
|
||||
args = parser.parse_args()
|
||||
DEBUG = args.debug
|
||||
|
||||
if (args.edit or args.apply is not None) and os.getuid() != 0:
|
||||
exit_error("--edit/--apply must be run as root")
|
||||
@@ -537,7 +573,15 @@ See 'rpi-eeprom-update -h' for more information about the available EEPROM image
|
||||
image = BootloaderImage(args.eeprom, args.out)
|
||||
if args.timestamp is not None:
|
||||
image.set_timestamp(args.timestamp)
|
||||
|
||||
if args.bootcode is not None:
|
||||
image.update_file(args.bootcode, BOOTCODE_BIN)
|
||||
|
||||
if args.cacertder is not None:
|
||||
image.update_file(args.cacertder, CACERT_DER)
|
||||
|
||||
if args.config is not None:
|
||||
# The public key, EEPROM config and signature should be set together
|
||||
if not os.path.exists(args.config):
|
||||
exit_error("config file '%s' not found" % args.config)
|
||||
image.update_file(args.config, BOOTCONF_TXT)
|
||||
@@ -545,8 +589,9 @@ See 'rpi-eeprom-update -h' for more information about the available EEPROM image
|
||||
image.update_file(args.digest, BOOTCONF_SIG)
|
||||
if args.pubkey is not None:
|
||||
image.update_key(args.pubkey, PUBKEY_BIN)
|
||||
image.write()
|
||||
elif args.config is None and args.timestamp is not None:
|
||||
|
||||
if args.config is not None or args.timestamp is not None or args.bootcode is not None or args.cacertder is not None:
|
||||
debug("Writing image")
|
||||
image.write()
|
||||
else:
|
||||
image.read()
|
||||
|
||||
@@ -34,18 +34,27 @@ checkDependencies() {
|
||||
if ! command -v xxd > /dev/null; then
|
||||
die "xxd not found. Try installing the xxd package."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
rpi-eeprom-digest [-k RSA_KEY] -i IMAGE -o OUTPUT
|
||||
|
||||
Creates a .sig file containing the sha256 digest of the IMAGE and an optional
|
||||
RSA signature of that hash.
|
||||
Tool to generate .sig files containing the SHA256 digest and optional
|
||||
RSA signature. Typically this tool is used by rpi-eeprom-update to
|
||||
generate a hash to guard against file-system corruption for EEPROM updates
|
||||
OR for signing OS images (boot.img) for secure-boot.
|
||||
|
||||
This tool CANNOT be used directly to sign an bootloader EEPROM image
|
||||
for secure-boot because the signed data is bootloader configuration file
|
||||
rather than the entire flash image.
|
||||
To create signed bootloader images please see
|
||||
https://github.com/raspberrypi/usbboot/tree/master/secure-boot-recovery/README.md
|
||||
|
||||
|
||||
Options:
|
||||
-i The source image.
|
||||
-i The source image e.g. boot.img
|
||||
-o The name of the digest/signature file.
|
||||
-k Optional RSA private key.
|
||||
|
||||
@@ -58,16 +67,20 @@ The bootloader only verifies RSA signatures in signed boot mode
|
||||
|
||||
Examples:
|
||||
|
||||
# Generate RSA signature for the EEPROM config file.
|
||||
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
|
||||
|
||||
# Generate the normal sha256 hash to guard against file-system corruption
|
||||
rpi-eeprom-digest -i pieeprom.bin -o pieeprom.sig
|
||||
rpi-eeprom-digest -i vl805.bin -o vl805.sig
|
||||
|
||||
# Generate a signed OS ramdisk image for secure-boot
|
||||
rpi-eeprom-digest -k private.pem -i boot.img -o boot.sig
|
||||
|
||||
# Generate RSA signature for the EEPROM config file
|
||||
# As used by update-pieeprom.sh in usbboot/secure-boot-recovery
|
||||
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
|
||||
|
||||
# To verify the signature of an existing .sig file using the public key.
|
||||
# N.B The key file must be the PUBLIC key in PEM format.
|
||||
rpi-eeprom-digest -k public.pem -i pieeprom.bin -v pieeprom.sig
|
||||
rpi-eeprom-digest -k public.pem -i boot.bin -v boot.sig
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
|
||||
@@ -110,6 +110,10 @@ die() {
|
||||
exit ${EXIT_FAILED}
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
getBootloaderConfig() {
|
||||
# Prefer extracting bootloader's config from DT.
|
||||
#
|
||||
@@ -192,9 +196,9 @@ applyRecoveryUpdate()
|
||||
getBootloaderCurrentVersion
|
||||
BOOTLOADER_UPDATE_VERSION=$(strings "${BOOTLOADER_UPDATE_IMAGE}" | grep BUILD_TIMESTAMP | sed 's/.*=//g')
|
||||
if [ "${BOOTLOADER_CURRENT_VERSION}" -gt "${BOOTLOADER_UPDATE_VERSION}" ]; then
|
||||
echo " WARNING: Installing an older bootloader version."
|
||||
echo " Update the rpi-eeprom package to fetch the latest bootloader images."
|
||||
echo
|
||||
warn " WARNING: Installing an older bootloader version."
|
||||
warn " Update the rpi-eeprom package to fetch the latest bootloader images."
|
||||
warn
|
||||
fi
|
||||
echo " CURRENT: $(date -u "-d@${BOOTLOADER_CURRENT_VERSION}") (${BOOTLOADER_CURRENT_VERSION})"
|
||||
echo " UPDATE: $(date -u "-d@${BOOTLOADER_UPDATE_VERSION}") (${BOOTLOADER_UPDATE_VERSION})"
|
||||
@@ -254,9 +258,10 @@ applyRecoveryUpdate()
|
||||
# of power loss.
|
||||
if [ "${RPI_EEPROM_USE_FLASHROM}" = 1 ]; then
|
||||
echo
|
||||
echo "UPDATING bootloader."
|
||||
echo "UPDATING bootloader. This could take up to a minute. Please wait"
|
||||
echo
|
||||
echo "*** Do not disconnect the power until the update is complete ***"
|
||||
echo
|
||||
echo "*** WARNING: Do not disconnect the power until the update is complete ***"
|
||||
echo "If a problem occurs then the Raspberry Pi Imager may be used to create"
|
||||
echo "a bootloader rescue SD card image which restores the default bootloader image."
|
||||
echo
|
||||
@@ -310,11 +315,11 @@ applyUpdate() {
|
||||
if [ "${RPI_EEPROM_USE_FLASHROM}" = 1 ]; then
|
||||
flashrom_probe_ok=0
|
||||
if ! [ -e "${SPIDEV}" ]; then
|
||||
echo "WARNING: SPI device ${SPIDEV} not found. Setting RPI_EEPROM_USE_FLASHROM to 0"
|
||||
warn "WARNING: SPI device ${SPIDEV} not found. Setting RPI_EEPROM_USE_FLASHROM to 0"
|
||||
fi
|
||||
|
||||
if ! flashrom -p linux_spi:dev=${SPIDEV},spispeed=16000 > /dev/null 2>&1; then
|
||||
echo "WARNING: Flashrom probe of ${SPIDEV} failed"
|
||||
warn "WARNING: Flashrom probe of ${SPIDEV} failed"
|
||||
else
|
||||
flashrom_probe_ok=1
|
||||
fi
|
||||
@@ -365,7 +370,7 @@ getBootloaderUpdateVersion() {
|
||||
}
|
||||
|
||||
chipNotSupported() {
|
||||
echo "This tool only works with Raspberry Pi4 and Rapberry Pi5"
|
||||
echo "Device does not a have a Raspberry Pi bootloader EEPROM (e.g. Pi 4 or Pi 5). Skipping bootloader update."
|
||||
exit ${EXIT_SUCCESS}
|
||||
}
|
||||
|
||||
@@ -395,15 +400,23 @@ checkDependencies() {
|
||||
elif [ $(((0x$BOARD_INFO >> 12) & 15)) = 4 ]; then
|
||||
BCM_CHIP=2712
|
||||
EEPROM_SIZE=2097152
|
||||
BOOTLOADER_AUTO_UPDATE_MIN_VERSION="${BOOTLOADER_AUTO_UPDATE_MIN_VERSION:-1697650217}"
|
||||
BOOTLOADER_AUTO_UPDATE_MIN_VERSION="${BOOTLOADER_AUTO_UPDATE_MIN_VERSION:-1713610410}"
|
||||
SPIDEV=/dev/spidev10.0
|
||||
# Default is to use flashrom if availableon BCM2712
|
||||
RPI_EEPROM_USE_FLASHROM=${RPI_EEPROM_USE_FLASHROM:-1}
|
||||
else
|
||||
chipNotSupported
|
||||
fi
|
||||
|
||||
# Default to off - in the future Raspberry Pi 5 may default to using flashrom if
|
||||
# flashrom is available.
|
||||
[ -z "${RPI_EEPROM_USE_FLASHROM}" ] && RPI_EEPROM_USE_FLASHROM=0
|
||||
if [ "${AUTO_UPDATE_BOOTLOADER}" = 1 ] || [ -n "${BOOTLOADER_UPDATE_IMAGE}" ]; then
|
||||
[ -z "${RPI_EEPROM_USE_FLASHROM}" ] && RPI_EEPROM_USE_FLASHROM=0
|
||||
if [ "${RPI_EEPROM_USE_FLASHROM}" -eq 1 ] && ! command -v flashrom > /dev/null; then
|
||||
warn "WARNING: flashrom not found. Setting RPI_EEPROM_USE_FLASHROM to 0"
|
||||
RPI_EEPROM_USE_FLASHROM=0
|
||||
fi
|
||||
fi
|
||||
|
||||
FIRMWARE_IMAGE_DIR="${FIRMWARE_ROOT}-${BCM_CHIP}/${FIRMWARE_RELEASE_STATUS}"
|
||||
if ! [ -d "${FIRMWARE_IMAGE_DIR}" ]; then
|
||||
@@ -450,11 +463,15 @@ checkDependencies() {
|
||||
die "lspci not found. Try installing the pciutils package."
|
||||
fi
|
||||
|
||||
if ! command -v strings > /dev/null; then
|
||||
die "strings not found. Try installing the binutils package."
|
||||
fi
|
||||
|
||||
# vcgencmd bootloader_version is deprecated. Use device-tree if available to
|
||||
# reduce the number of dependencies on VCHI.
|
||||
if ! [ -f "${DT_BOOTLOADER_TS}" ]; then
|
||||
if ! command -v vcgencmd > /dev/null; then
|
||||
die "vcgencmd not found. Try installing the libraspberrypi-bin package."
|
||||
die "vcgencmd not found. Try installing the raspi-utils package."
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -473,16 +490,12 @@ checkDependencies() {
|
||||
fi
|
||||
|
||||
if ! command -v sha256sum > /dev/null; then
|
||||
die "sha256sum not found. Try installing the coreutilities package."
|
||||
die "sha256sum not found. Try installing the coreutils package."
|
||||
fi
|
||||
|
||||
if [ "${BCM_CHIP}" = 2711 ] && [ ! -f "${RECOVERY_BIN}" ]; then
|
||||
die "${RECOVERY_BIN} not found."
|
||||
fi
|
||||
|
||||
if ! command -v flashrom > /dev/null; then
|
||||
RPI_EEPROM_USE_FLASHROM=0
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
@@ -704,11 +717,11 @@ findBootFS()
|
||||
|
||||
if [ "${BCM_CHIP}" = 2712 ]; then
|
||||
if ! [ -e "${BOOTFS}/config.txt" ]; then
|
||||
echo "WARNING: BOOTFS: \"${BOOTFS}/config.txt\" not found. Please check boot directory"
|
||||
warn "WARNING: BOOTFS: \"${BOOTFS}/config.txt\" not found. Please check boot directory"
|
||||
fi
|
||||
else
|
||||
if [ "$(find "${BOOTFS}/" -name "*.elf" | wc -l)" = 0 ]; then
|
||||
echo "WARNING: BOOTFS: \"${BOOTFS}\" contains no .elf files. Please check boot directory"
|
||||
warn "WARNING: BOOTFS: \"${BOOTFS}\" contains no .elf files. Please check boot directory"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ FORCE=0
|
||||
READ_KEY=""
|
||||
WRITE_KEY=""
|
||||
OUTPUT_BINARY=0
|
||||
ROW_COUNT=8
|
||||
ROW_OFFSET=0
|
||||
|
||||
die() {
|
||||
echo "$@" >&2
|
||||
@@ -25,10 +27,12 @@ usage() {
|
||||
N.B. OTP bits can never change from 1 to 0.
|
||||
-w Writes the new key to OTP memory.
|
||||
-y Skip the confirmation prompt when writing to OTP.
|
||||
-l Specify key length in words. Defaults to 8 words (32 bytes). Pi 5 supports up to 16 words (64 bytes).
|
||||
-o word Offset into the keystore to use, e.g. 0-7 for Pi 4, 0-15 for Pi 5. Defaults to zero.
|
||||
|
||||
<key> is a 64 digit hex number (256 bit) e.g. to generate a 256 random number run 'openssl rand -hex 32'
|
||||
<key> is usually a 64 digit hex number (256 bit) e.g. to generate a 256 random number run 'openssl rand -hex 32'
|
||||
|
||||
IMPORTANT: Raspberry Pi 4 and earlier revisions do not have a hardware secure key store. These OTP rows are visible
|
||||
IMPORTANT: Raspberry Pi 5 and earlier revisions do not have a hardware secure key store. These OTP rows are visible
|
||||
to any user in the 'video' group via vcmailbox. Therefore this functionality is only suitable for key
|
||||
storage if the OS has already been restricted using the signed boot functionality.
|
||||
|
||||
@@ -46,8 +50,8 @@ check_key_set() {
|
||||
}
|
||||
|
||||
read_key() {
|
||||
out=READ_KEY="$(vcmailbox 0x00030081 40 40 0 8 0 0 0 0 0 0 0 0)" || die "Failed to read the current key from OTP"
|
||||
READ_KEY="$(echo "${out}" | sed 's/0x//g' | awk '{for(i=8;i<16;i++) printf $i; print ""}')"
|
||||
out=READ_KEY="$(vcmailbox 0x00030081 $((8 + ROW_COUNT * 4)) $((8 + ROW_COUNT * 4)) $ROW_OFFSET $ROW_COUNT 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)" || die "Failed to read the current key from OTP"
|
||||
READ_KEY="$(echo "${out}" | sed 's/0x//g' | awk -v last=$((8 + ROW_COUNT)) '{for(i=8;i<last;i++) printf $i; print ""}')"
|
||||
}
|
||||
|
||||
write_key() {
|
||||
@@ -55,19 +59,19 @@ write_key() {
|
||||
# Normalize formatting and check the length
|
||||
key="$(echo "${key}" | tr 'A-Z' 'a-z')"
|
||||
key="$(echo "${key}" | sed 's/[^a-f0-9]//g')"
|
||||
[ "$(echo -n "${key}" | wc -c)" = 64 ] || die "Invalid key parameter"
|
||||
[ "$(echo -n "${key}" | wc -c)" = $((ROW_COUNT * 4 * 2)) ] || die "Invalid key parameter"
|
||||
|
||||
count=0
|
||||
key_params=""
|
||||
while [ ${count} -lt 8 ]; do
|
||||
while [ ${count} -lt $ROW_COUNT ]; do
|
||||
start=$(((count * 8) + 1))
|
||||
end=$((start + 7))
|
||||
key_params="${key_params} 0x$(echo -n "${key}" | cut -c${start}-${end})"
|
||||
count=$((count + 1))
|
||||
end=$((start + 7))
|
||||
key_params="${key_params} 0x$(echo -n "${key}" | cut -c${start}-${end})"
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
if [ "${YES}" = 0 ] && [ -t 0 ]; then
|
||||
echo "Write ${key} to OTP?"
|
||||
echo "Write ${key} of $ROW_COUNT words to OTP starting at word offset $ROW_OFFSET?"
|
||||
echo
|
||||
echo "WARNING: Updates to OTP registers are permanent and cannot be undone."
|
||||
|
||||
@@ -79,13 +83,13 @@ write_key() {
|
||||
fi
|
||||
fi
|
||||
|
||||
vcmailbox 0x38081 40 40 0 8 ${key_params} || die "Failed to write key"
|
||||
vcmailbox 0x38081 $((8 + ROW_COUNT * 4)) $((8 + ROW_COUNT * 4)) $ROW_OFFSET $ROW_COUNT ${key_params} || die "Failed to write key"
|
||||
read_key
|
||||
[ "${READ_KEY}" = "${key}" ] || die "Key readback check failed. ${out}"
|
||||
}
|
||||
|
||||
YES=0
|
||||
while getopts bcfhw:y option; do
|
||||
while getopts bcfhw:yl:o: option; do
|
||||
case "${option}" in
|
||||
b) OUTPUT_BINARY=1
|
||||
;;
|
||||
@@ -102,13 +106,61 @@ while getopts bcfhw:y option; do
|
||||
w) WRITE_KEY="${OPTARG}"
|
||||
;;
|
||||
y) YES=1
|
||||
;;
|
||||
;;
|
||||
l) ROW_COUNT="${OPTARG}"
|
||||
;;
|
||||
o) ROW_OFFSET="${OPTARG}"
|
||||
;;
|
||||
*) echo "Unknown argument \"${option}\""
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -f "/sys/firmware/devicetree/base/system/linux,revision" ]; then
|
||||
BOARD_INFO="$(od -v -An -t x1 /sys/firmware/devicetree/base/system/linux,revision | tr -d ' \n')"
|
||||
elif grep -q Revision /proc/cpuinfo; then
|
||||
BOARD_INFO="$(sed -n '/^Revision/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo)"
|
||||
elif command -v vcgencmd > /dev/null; then
|
||||
BOARD_INFO="$(vcgencmd otp_dump | grep '30:' | sed 's/.*://')"
|
||||
else
|
||||
die "No Raspberry Pi board info found"
|
||||
fi
|
||||
if [ $(((0x$BOARD_INFO >> 23) & 1)) = 0 ]; then
|
||||
die "Chip not supported"
|
||||
fi
|
||||
if [ $(((0x$BOARD_INFO >> 12) & 15)) = 3 ]; then
|
||||
MAX_ROW_COUNT=8
|
||||
elif [ $(((0x$BOARD_INFO >> 12) & 15)) = 4 ]; then
|
||||
MAX_ROW_COUNT=16
|
||||
else
|
||||
die "Chip not supported"
|
||||
fi
|
||||
if [ -z "$ROW_COUNT" ] || [ "$ROW_COUNT" -ne "$ROW_COUNT" ] 2>/dev/null; then
|
||||
die "Key length not a number"
|
||||
fi
|
||||
if [ $ROW_COUNT -lt 1 ]; then
|
||||
die "Length too small"
|
||||
fi
|
||||
if [ $ROW_COUNT -gt $MAX_ROW_COUNT ]; then
|
||||
die "Length too big"
|
||||
fi
|
||||
if [ -z "$ROW_OFFSET" ] || [ "$ROW_OFFSET" -ne "$ROW_OFFSET" ] 2>/dev/null; then
|
||||
die "Offset is not a number"
|
||||
fi
|
||||
if [ $ROW_OFFSET -lt 0 ]; then
|
||||
die "Offset too small"
|
||||
fi
|
||||
if [ ${ROW_OFFSET} -gt $((MAX_ROW_COUNT - ROW_COUNT)) ]; then
|
||||
die "Offset too big"
|
||||
fi
|
||||
if [ -z $(which vcmailbox) ]; then
|
||||
die "vcmailbox command missing"
|
||||
fi
|
||||
if [ -z $(which xxd) ] && [ "$OUTPUT_BINARY" -eq "1" ]; then
|
||||
die "xxd command missing"
|
||||
fi
|
||||
|
||||
if [ -n "${WRITE_KEY}" ]; then
|
||||
if [ "${FORCE}" = 0 ] && check_key_set; then
|
||||
die "Current key is non-zero. Specify -f to write anyway"
|
||||
|
||||
229
tools/rpi-sign-bootcode
Executable file
229
tools/rpi-sign-bootcode
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import struct
|
||||
import sys
|
||||
|
||||
# python3 -m pip install pycryptodomex
|
||||
from Cryptodome.Hash import HMAC, SHA1, SHA256
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.Signature import pkcs1_15
|
||||
|
||||
_CONFIG = {'DEBUG': False}
|
||||
MAX_BIN_SIZE = 110 * 1024
|
||||
|
||||
def debug(msg):
|
||||
"""
|
||||
Outputs the msg string to stdout if DEBUG is enabled (via -d)
|
||||
"""
|
||||
if _CONFIG['DEBUG']:
|
||||
sys.stderr.write(str(msg) + '\n')
|
||||
|
||||
class ImageFile:
|
||||
"""
|
||||
Signed binary image
|
||||
"""
|
||||
def __init__(self, filename, max_size_kb):
|
||||
self._filename = filename
|
||||
self._bytes_written = 0
|
||||
if self._filename is None:
|
||||
self._of = sys.stdout
|
||||
else:
|
||||
self._of = open(self._filename, "wb")
|
||||
self._max_size_kb = max_size_kb
|
||||
self._bytes = bytearray()
|
||||
|
||||
debug("%8s %20s: [%6s] %s" % ('OFFSET', 'TYPE', 'SIZE', 'DESCRIPTION'))
|
||||
debug("")
|
||||
|
||||
def append(self, data):
|
||||
"""
|
||||
Appends a blob of binary data to the image
|
||||
"""
|
||||
self._bytes.extend(data)
|
||||
|
||||
def append_file(self, source_file):
|
||||
"""
|
||||
Appends the binary contents of source_file to the current image. If
|
||||
source_file is None then a base64 encoded blob is read from stdin.
|
||||
"""
|
||||
if source_file is None:
|
||||
b64 = ""
|
||||
for l in sys.stdin.readlines():
|
||||
b64 += l
|
||||
file_bytes = base64.b64decode(b64)
|
||||
else:
|
||||
file_bytes = bytearray(open(source_file, 'rb').read())
|
||||
size = len(file_bytes)
|
||||
debug("%08x %20s: [%6d] %s" % (self.pos(), 'FILE', size, source_file))
|
||||
self.append(file_bytes)
|
||||
|
||||
def append_keynum(self, keynum):
|
||||
"""
|
||||
Appends a given key number as a 32-bit LE integer.
|
||||
"""
|
||||
if (keynum < 0 or keynum > 4) and keynum != 16:
|
||||
raise Exception("Bad key number %d" % keynum)
|
||||
debug("%08x %20s: [%6d] %d" % (self.pos(), "KEYNUM", 4, keynum))
|
||||
self.append(struct.pack('<i', keynum))
|
||||
|
||||
def append_version(self, version):
|
||||
"""
|
||||
Appends a version number, 0-32 to avoid firmware rollback, a Raspberry Pi
|
||||
with OTP bit n set will not execute a firmware without bit n set.
|
||||
"""
|
||||
if version < 0 or version > 32:
|
||||
raise Exception("Bad version number %d must be between 0-32" % version)
|
||||
debug("%08x %20s: [%6d] %d" % (self.pos(), "VERSION", 4, version))
|
||||
self.append(struct.pack('<i', version))
|
||||
|
||||
def append_length(self):
|
||||
"""
|
||||
Appends the current length to the image as a 32-bit LE integer
|
||||
"""
|
||||
length = len(self._bytes)
|
||||
debug("%08x %20s: [%6d] %d" % (self.pos(), "LEN", 4, length))
|
||||
self.append(struct.pack('<i', length))
|
||||
|
||||
def append_public_key(self, pem_file):
|
||||
"""
|
||||
Converts an RSA public key into the format expected by the ROM
|
||||
and appends it to the image.
|
||||
|
||||
If a private key is passed then only the public key part is extracted.
|
||||
"""
|
||||
arr = bytearray()
|
||||
key = RSA.importKey(open(pem_file, 'r').read())
|
||||
|
||||
if key.size_in_bits() != 2048:
|
||||
raise Exception("RSA key size must be 2048")
|
||||
|
||||
# Export N and E in little endian format
|
||||
arr.extend(key.n.to_bytes(256, byteorder='little'))
|
||||
arr.extend(key.e.to_bytes(8, byteorder='little'))
|
||||
debug("%08x %20s: [%6d] %s" % (self.pos(), 'RSA', len(arr), pem_file))
|
||||
self.append(arr)
|
||||
|
||||
def append_rsa_signature(self, digest_alg, private_pem):
|
||||
"""
|
||||
Append a RSA 2048 signature of the SHA256 of the data so far
|
||||
"""
|
||||
key = RSA.importKey(open(private_pem, 'r').read())
|
||||
if key.size_in_bits() != 2048:
|
||||
raise Exception("RSA key size must be 2048")
|
||||
|
||||
if digest_alg == 'sha256':
|
||||
digest = SHA256.new(self._bytes)
|
||||
elif digest_alg == 'sha1':
|
||||
digest = SHA1.new(self._bytes)
|
||||
|
||||
signature = pkcs1_15.new(key).sign(digest)
|
||||
self.append(signature)
|
||||
debug("%08x %20s: [%6d] digest %s signature %s" % (self.pos(), 'RSA2048 - SHA256', len(signature), digest.hexdigest(), signature.hex()))
|
||||
|
||||
def append_digest(self, digest_alg, hmac_keyfile):
|
||||
"""
|
||||
Appends the hash/digest to the image
|
||||
"""
|
||||
if hmac_keyfile is not None:
|
||||
hmac_key = str(open(hmac_keyfile, 'r').read()).strip()
|
||||
expected_keylen = 40
|
||||
if len(hmac_key) != expected_keylen:
|
||||
raise Exception("Bad key length %d expected %d" % (len(hmac_key), expected_keylen))
|
||||
|
||||
if digest_alg == 'hmac-sha256':
|
||||
digest = HMAC.new(base64.b16decode(hmac_key, True), self._bytes, digestmod=SHA256)
|
||||
elif digest_alg == 'hmac-sha1':
|
||||
digest = HMAC.new(base64.b16decode(hmac_key, True), self._bytes, digestmod=SHA1)
|
||||
elif digest_alg == 'sha256':
|
||||
digest = SHA256.new(self._bytes)
|
||||
elif digest_alg == 'sha1':
|
||||
digest = SHA1.new(self._bytes)
|
||||
else:
|
||||
raise Exception("Digest not supported %s" % (digest_alg))
|
||||
|
||||
debug("%08x %20s: [%6d] %s" % (self.pos(), digest_alg, len(digest.digest()), digest.hexdigest()))
|
||||
self.append(digest.digest())
|
||||
|
||||
def pos(self):
|
||||
return len(self._bytes)
|
||||
|
||||
def write(self):
|
||||
if len(self._bytes) > self._max_size_kb:
|
||||
raise Exception("Signed binary size %d is too large. Max size %d" % (len(self._bytes), MAX_BIN_SIZE))
|
||||
debug("Image size %d" % len(self._bytes))
|
||||
if self._filename is None:
|
||||
self._of.buffer.write(base64.b64encode(self._bytes))
|
||||
else:
|
||||
self._of.write(self._bytes)
|
||||
|
||||
def close(self):
|
||||
self._of.close()
|
||||
|
||||
def create_2711_image(output, bootcode, private_key, private_keynum, hmac):
|
||||
"""
|
||||
Create a 2711 C0 secure-boot compatible seconds stage signed binary.
|
||||
"""
|
||||
image = ImageFile(output, MAX_BIN_SIZE)
|
||||
image.append_file(bootcode)
|
||||
image.append_length()
|
||||
image.append_keynum(private_keynum)
|
||||
image.append_rsa_signature('sha1', private_key)
|
||||
image.append_digest('hmac-sha1', hmac)
|
||||
image.write()
|
||||
image.close()
|
||||
|
||||
def create_2712_image(output, bootcode, private_key, private_keynum, private_version):
|
||||
"""
|
||||
Create 2712 signed bootloader. The HMAC is removed and the full public key is appended.
|
||||
"""
|
||||
image = ImageFile(output, MAX_BIN_SIZE)
|
||||
image.append_file(bootcode)
|
||||
image.append_length()
|
||||
image.append_keynum(private_keynum)
|
||||
image.append_version(private_version)
|
||||
image.append_rsa_signature('sha256', private_key)
|
||||
image.append_public_key(private_key)
|
||||
image.write()
|
||||
image.close()
|
||||
|
||||
def main():
|
||||
help_text = """
|
||||
Signs a second stage bootloader image.
|
||||
|
||||
Examples:
|
||||
2711 mode:
|
||||
rpi-sign-bootcode --debug -c 2711 -i bootcode.bin.clr -o bootcode.bin -k 2711_rsa_priv_0.pem -n 0 -m bootcode-production.key
|
||||
|
||||
2712 C1 and D0 mode:
|
||||
* HMAC not included on 2712
|
||||
* RSA public key included - ROM just contains the hashes of the RPi public keys.
|
||||
|
||||
Customer counter-signed signed:
|
||||
* Exactly the same as Raspberry Pi signing but the input is the Raspberry Pi signed bootcode.bin
|
||||
* The key number will probably always be 16 to indicate a customer signing
|
||||
|
||||
rpi-sign-bootcode --debug -c 2712 -i bootcode.bin.sign2 -o bootcode.bin -k customer.pem
|
||||
"""
|
||||
parser = argparse.ArgumentParser(help_text)
|
||||
parser.add_argument('-o', '--output', required=False, help='Output filename . If not specified the signed images is written to stdout in base64 format')
|
||||
parser.add_argument('-c', '--chip', required=True, type=int, help='Chip number')
|
||||
parser.add_argument('-i', '--input', required=False, help='Path of the unsigned bootcode.bin file OR RPi signed bootcode file sign with the customer key. If NULLL the binary is read from stdin in base64 format')
|
||||
parser.add_argument('-m', '--hmac', required=False, help='Path of the HMAC key file')
|
||||
parser.add_argument('-k', '--private-key', dest='private_key', required=True, help='Path of RSA private key (PEM format)')
|
||||
parser.add_argument('-n', '--private-keynum', dest='private_keynum', required=False, default=0, type=int, help='ROM key index for RPi signing stage')
|
||||
parser.add_argument('-d', '--debug', action='store_true')
|
||||
parser.add_argument('-v', '--private-version', dest='private_version', required=True, type=int, help='Version of firmware, stops firmware rollback, only valid 0-31')
|
||||
|
||||
args = parser.parse_args()
|
||||
_CONFIG['DEBUG'] = args.debug
|
||||
if args.chip == 2711:
|
||||
if args.hmac is None:
|
||||
raise Exception("HMAC key requried for 2711")
|
||||
create_2711_image(args.output, args.input, args.private_key, args.private_keynum, args.hmac)
|
||||
elif args.chip == 2712:
|
||||
create_2712_image(args.output, args.input, args.private_key, args.private_keynum, args.private_version)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user