Skip to content

Commit 7ac1154

Browse files
committed
harden pieeprom-flashrom with clean up
Signed-off-by: Yann CARDAILLAC <yann.cardaillac@balena.io>
1 parent 86a00ea commit 7ac1154

2 files changed

Lines changed: 93 additions & 28 deletions

File tree

layers/meta-balena-raspberrypi/recipes-bsp/rpi-eeprom/files/pieeprom-flashrom.sh

Lines changed: 92 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,18 @@ set -o errexit
1010
# shellcheck disable=SC1091
1111
. /usr/libexec/os-helpers-logging
1212

13-
NEW_IMG="${1:-pieeprom.bin}"
13+
NEW_IMG="${1:-pieeprom.upd}"
1414
CURR_IMG=pieeprom-current.bin.tmp
1515
CURR_IMG_PATH=/tmp
1616
NEW_IMG_PATH=/mnt/boot
1717
SPI_SPEED=16000
18+
SPI_DEVICE=""
19+
VCHIQ_UNBOUND=0
20+
SPI_WAS_UNBOUND=0
21+
SPI_IS_BOUND=0
22+
AUDIO_WAS_DISABLED=0
23+
SPI_OVERLAY_WAS_ENABLED=0
24+
MAILBOX_WAS_DISABLED=0
1825

1926
# Unbind a device from a driver
2027
# Usage: device=$(driver_unbind <driver_path> <device_pattern>)
@@ -86,19 +93,98 @@ vchiq_unbind() {
8693
driver_unbind "${VCHIQ_DRIVER_PATH}" "*.mailbox"
8794
}
8895

96+
cleanup() {
97+
exit_code=$?
98+
cleanup_failed=0
99+
100+
# Cleanup must be best-effort and should not fail the script.
101+
set +o errexit
102+
103+
rm -f "${CURR_IMG_PATH}/${CURR_IMG}"
104+
105+
if [ "${SPI_IS_BOUND}" = "1" ] && [ -n "${SPI_DEVICE}" ]; then
106+
if ! echo "${SPI_DEVICE}" > "${SPI_DRIVER_PATH}/unbind" 2>/dev/null; then
107+
warn "Failed to unbind ${SPI_DEVICE} during cleanup"
108+
else
109+
SPI_IS_BOUND=0
110+
fi
111+
fi
112+
113+
if [ "${SPI_OVERLAY_WAS_ENABLED}" = "1" ]; then
114+
/usr/bin/dtparam -d /mnt/boot/overlays/ -R spi-gpio40-45 || \
115+
{
116+
warn "Failed to remove spi-gpio40-45 overlay during cleanup"
117+
cleanup_failed=1
118+
}
119+
fi
120+
121+
if [ "${AUDIO_WAS_DISABLED}" = "1" ]; then
122+
/usr/bin/dtparam -d /mnt/boot/overlays/ audio=on || \
123+
{
124+
warn "Failed to restore audio=on during cleanup"
125+
cleanup_failed=1
126+
}
127+
fi
128+
129+
if [ "${MAILBOX_WAS_DISABLED}" = "1" ]; then
130+
/usr/bin/vcmailbox 0x00030056 4 4 1 > /dev/null || \
131+
{
132+
warn "Failed to restore mailbox state during cleanup"
133+
cleanup_failed=1
134+
}
135+
fi
136+
137+
if [ "${SPI_WAS_UNBOUND}" = "1" ] && [ "${SPI_IS_BOUND}" = "0" ] && [ -n "${SPI_DEVICE}" ]; then
138+
if ! spi_bind "${SPI_DEVICE}"; then
139+
warn "Failed to restore SPI driver during cleanup"
140+
cleanup_failed=1
141+
fi
142+
fi
143+
144+
# VCHIQ cannot be restored at runtime due to firmware limitations.
145+
# Even with mailbox/audio restored, VideoCore services remain unavailable until reboot.
146+
# https://github.com/raspberrypi/rpi-eeprom/issues/801#issuecomment-3859373151
147+
if [ "${VCHIQ_UNBOUND}" = "1" ]; then
148+
warn "VCHIQ was unbound during EEPROM update and cannot be restored at runtime."
149+
warn "Audio, camera and other VideoCore services will not work until the next reboot."
150+
fi
151+
152+
if [ "${exit_code}" -eq 0 ] && [ "${cleanup_failed}" -eq 1 ]; then
153+
warn "EEPROM update was successful, but cleanup failed. Exiting."
154+
exit 2
155+
fi
156+
157+
exit "${exit_code}"
158+
}
159+
160+
trap cleanup EXIT
161+
89162
SPI_DEVICE=$(spi_unbind)
90163
if [ -z "${SPI_DEVICE}" ]; then
91164
fail "SPI device not found or failed to unbind, cannot proceed with EEPROM update"
92165
fi
166+
SPI_WAS_UNBOUND=1
167+
168+
if /usr/bin/vcmailbox 0x00030056 4 4 0 > /dev/null; then
169+
MAILBOX_WAS_DISABLED=1
170+
else
171+
warn "Failed to disable mailbox before EEPROM update; continuing"
172+
fi
173+
if /usr/bin/dtparam -d /mnt/boot/overlays/ audio=off; then
174+
AUDIO_WAS_DISABLED=1
175+
else
176+
fail "Failed to disable audio before EEPROM update"
177+
fi
93178

94-
/usr/bin/vcmailbox 0x00030056 4 4 0 > /dev/null || true
95-
/usr/bin/dtparam -d /mnt/boot/overlays/ audio=off
96-
/usr/bin/dtoverlay -d /mnt/boot/overlays/ spi-gpio40-45
179+
if /usr/bin/dtoverlay -d /mnt/boot/overlays/ spi-gpio40-45; then
180+
SPI_OVERLAY_WAS_ENABLED=1
181+
else
182+
fail "Failed to apply spi-gpio40-45 overlay before EEPROM update"
183+
fi
97184

98185
# Try binding SPI; if it fails (pinctrl conflict with VCHIQ holding GPIO 40-45),
99186
# unbind VCHIQ and retry. VCHIQ cannot be rebound at runtime, so audio/camera
100187
# will be unavailable until reboot.
101-
VCHIQ_UNBOUND=0
102188
if ! spi_bind "$SPI_DEVICE"; then
103189
warn "Unbinding VCHIQ to release GPIO 40-45 (audio/camera will be unavailable until reboot)"
104190
vchiq_unbind
@@ -107,6 +193,7 @@ if ! spi_bind "$SPI_DEVICE"; then
107193
fail "SPI bind failed even after VCHIQ unbind, cannot proceed"
108194
fi
109195
fi
196+
SPI_IS_BOUND=1
110197

111198
/usr/sbin/flashrom -p "linux_spi:dev=/dev/spidev0.0,spispeed=${SPI_SPEED}" --read "${CURR_IMG_PATH}/${CURR_IMG}"
112199

@@ -120,25 +207,3 @@ else
120207
/usr/sbin/flashrom -p "linux_spi:dev=/dev/spidev0.0,spispeed=${SPI_SPEED}" --write "${NEW_IMG_PATH}/${NEW_IMG}"
121208
info "SPI EEPROM fw update successful"
122209
fi
123-
124-
rm "${CURR_IMG_PATH}/${CURR_IMG}"
125-
126-
SPI_DEVICE=$(spi_unbind)
127-
if [ -z "${SPI_DEVICE}" ]; then
128-
fail "SPI device not found during cleanup, cannot restore system state"
129-
fi
130-
131-
/usr/bin/dtparam -d /mnt/boot/overlays/ -R spi-gpio40-45
132-
/usr/bin/dtparam -d /mnt/boot/overlays/ audio=on
133-
/usr/bin/vcmailbox 0x00030056 4 4 1 > /dev/null || true
134-
135-
if ! spi_bind "$SPI_DEVICE"; then
136-
fail "Failed to restore SPI driver during cleanup"
137-
fi
138-
139-
# In an ideal world we would restore the mailbox, but unfortunately this is impossible
140-
# https://github.com/raspberrypi/rpi-eeprom/issues/801#issuecomment-3859373151
141-
if [ "${VCHIQ_UNBOUND}" = "1" ]; then
142-
warn "VCHIQ was unbound during EEPROM update and cannot be restored at runtime."
143-
warn "Audio, camera and other VideoCore services will not work until the next reboot."
144-
fi

layers/meta-balena-raspberrypi/recipes-bsp/rpi-eeprom/files/pieeprom-update.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if type is_secured >/dev/null 2>&1 && is_secured; then
1616
exit 0
1717
fi
1818

19-
NEW_IMG="${1:-pieeprom.bin}"
19+
NEW_IMG="${1:-pieeprom.upd}"
2020
DT_BOOTLOADER_TS="/proc/device-tree/chosen/bootloader/build-timestamp"
2121
# Minimum bootloader version that supports self-update (2022-04-26)
2222
# See https://github.com/raspberrypi/rpi-eeprom/blob/master/rpi-eeprom-update

0 commit comments

Comments
 (0)