feat: Menu comes back after each run, BIOS dry run, version 0.8.0

- After a run the menu returns; [m] back to the menu or [r] restart now when a restart is needed; q quits.
- A staged BIOS update greys the item out until the restart.
- WIZARD_BIOS_DRY_RUN=1: whole BIOS flow without the device check, never flashes.
- VERSION 0.8.0; CHANGELOG: BIOS work moved to 0.8.0; README: BIOS update step by step.
This commit is contained in:
theupriser committed 2026-09-24 10:40:16 +02:00
1 parent 68981821a3
commit 2e6d20a3f0
5 files changed
+182 -72

No files matched your search

+6 -1
View File
@@ -143,7 +143,12 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
Keep both confirmations (y/N, then typing `UPDATE`) and the warnings; the Keep both confirmations (y/N, then typing `UPDATE`) and the warnings; the
firmware comes from the newest `holo-X.Y` repo (`.files` db names the firmware comes from the newest `holo-X.Y` repo (`.files` db names the
`.cab`, `.db` gives the SHA-256), and fwupd itself refuses non-Fremont `.cab`, `.db` gives the SHA-256), and fwupd itself refuses non-Fremont
hardware. It can only be tested up to fwupd's refusal in the VM. hardware. In the VM, test it with `WIZARD_BIOS_DRY_RUN=1` (skips only the
device check, never flashes) and a faked version (dev-env
`BIOS_VERSION=F7F0107 ./run.sh --fremont`).
- The entry point loops: menu, run, "back to the menu" (or `[m]`/`[r]` when a
restart is needed), until `q`; the restart question is asked once at the
end. Scripted input that runs out ends the loop like `q`.
- `Relogin=true` means a gamescope that fails to start is relaunched in a - `Relogin=true` means a gamescope that fails to start is relaunched in a
tight loop; keep that in mind when changing session handling. tight loop; keep that in mind when changing session handling.
+29 -15
View File
@@ -5,6 +5,35 @@ All notable changes, per version and per commit. Versions follow
`setup-gamescope-boot.sh`. Versions before 0.7.0 were numbered afterwards, `setup-gamescope-boot.sh`. Versions before 0.7.0 were numbered afterwards,
one per merged pull request. one per merged pull request.
## 0.8.0 - 2026-09-24
An opt-in BIOS update for the Steam Machine, and a menu that comes back after
every run. Merged together with 0.7.0, so v0.8.0 is the release that has both.
- `2f9b2a5` **feat: Opt-in BIOS update for the Steam Machine**
- New menu item (Steam Machine only, never ticked by default) showing the
current BIOS version and the newest from Valve's `fremont-hw-support`.
- Two large warnings and two confirmations (y/N, then typing `UPDATE`),
checksum-verified download, installed with fwupd; the wizard then offers
the restart that writes it, with a warning to keep the power on.
- `40c9ee6` **fix: BIOS update only when newer, device check first, aligned warnings**
- The item is greyed out and can't be ticked unless Valve has a newer BIOS.
- Before any warning: SHA-256 of Valve's package, then fwupd confirms the
firmware fits this machine's hardware; otherwise it stops.
- Warning box drawn with a solid red frame whose edges line up, and the
menu's "Now" column aligned.
- `b70c9d6` **fix: shellcheck in the bundle, and the docs for the BIOS checks**
- A variable name in `lib/bios.sh` clashed with `lib/state.sh` in the bundle
(CI's shellcheck would fail); README, AGENTS.md and this changelog updated.
- **feat: Menu comes back after each run, BIOS dry run, version 0.8.0**
- After a run the menu returns with the new state; quit with `q`. When
something needs a restart, choose between back to the menu (`m`) and
restart now (`r`); quitting asks once more.
- A staged BIOS update greys the item out until the restart.
- `WIZARD_BIOS_DRY_RUN=1` walks through the whole BIOS update (download,
checksum, both warnings) but only prints the install and never flashes.
- README: the menu loop and the BIOS update step by step.
## 0.7.0 - 2026-09-24 ## 0.7.0 - 2026-09-24
The SteamOS theme comes from CachyOS's `cachyos-vapor` package, applied with The SteamOS theme comes from CachyOS's `cachyos-vapor` package, applied with
@@ -56,21 +85,6 @@ Machine LED driver works on every installed kernel and survives kernel updates.
- When a new version is released, the `latest` tag and release move to it - When a new version is released, the `latest` tag and release move to it
(bundle replaced), so the older `.../releases/download/latest/...` URL (bundle replaced), so the older `.../releases/download/latest/...` URL
also always gives the newest version. also always gives the newest version.
- `2f9b2a5` **feat: Opt-in BIOS update for the Steam Machine**
- New menu item (Steam Machine only, never ticked by default) showing the
current BIOS version and the newest from Valve's `fremont-hw-support`.
- Two large warnings and two confirmations (y/N, then typing `UPDATE`),
checksum-verified download, installed with fwupd; the wizard then offers
the restart that writes it, with a warning to keep the power on.
- `40c9ee6` **fix: BIOS update only when newer, device check first, aligned warnings**
- The item is greyed out and can't be ticked unless Valve has a newer BIOS.
- Before any warning: SHA-256 of Valve's package, then fwupd confirms the
firmware fits this machine's hardware; otherwise it stops.
- Warning box drawn with a solid red frame whose edges line up, and the
menu's "Now" column aligned.
- **fix: shellcheck in the bundle, and the docs for the BIOS checks**
- A variable name in `lib/bios.sh` clashed with `lib/state.sh` in the bundle
(CI's shellcheck would fail); README, AGENTS.md and this changelog updated.
## 0.6.2 - 2026-09-23 ## 0.6.2 - 2026-09-23
+39 -13
View File
@@ -27,6 +27,9 @@ Everything you turn off is put back the way it was.
5. **Steam Machine support** - only shown on a Valve Steam Machine: the 5. **Steam Machine support** - only shown on a Valve Steam Machine: the
driver for the front LED bar, and the hardware settings in Steam (fan, driver for the front LED bar, and the hardware settings in Steam (fan,
TV control over HDMI-CEC). TV control over HDMI-CEC).
6. **Update BIOS** - only on a Steam Machine, opt-in and at your own risk:
installs the newest Steam Machine BIOS from Valve (see
[BIOS updates](#bios-updates-steam-machine)).
## Requirements ## Requirements
@@ -74,6 +77,10 @@ it's loaded right now, so a kernel update is easy to check. The wizard then
shows what it will change, asks your password once, and at the end offers shows what it will change, asks your password once, and at the end offers
to restart (needed for changes to how the PC starts). to restart (needed for changes to how the PC starts).
After each run the menu comes back with the new state, so you can change more
in one go; quit with **q**. When something needs a restart, you choose
between going back to the menu and restarting now; quitting asks once more.
Run it again whenever you like - to change your choices, to turn things off Run it again whenever you like - to change your choices, to turn things off
again, or after a CachyOS update (press `a` in the menu to re-apply again, or after a CachyOS update (press `a` in the menu to re-apply
everything that's on). everything that's on).
@@ -283,22 +290,41 @@ cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log
journalctl --user -b | grep -i led journalctl --user -b | grep -i led
``` ```
**BIOS updates** (opt-in, never ticked by default). On a Steam Machine the menu ### BIOS updates (Steam Machine)
has an **Update BIOS** item that shows the current BIOS version and the newest
one Valve ships (`F7F0108.cab` in its `fremont-hw-support` package, looked up The **Update BIOS** item is only shown on a Steam Machine and is never ticked
on Valve's SteamOS mirror). It can only be ticked when Valve has a newer BIOS by default. It shows the BIOS version you have now and the newest one Valve
than the one installed; otherwise it's greyed out. Before asking anything it ships (the `.cab` file in its `fremont-hw-support` package, looked up on
downloads the package and checks it: the SHA-256 from Valve's repository Valve's SteamOS mirror):
proves it's Valve's file, and fwupd confirms the firmware is for this very
machine (it compares the firmware's hardware IDs with the device). Only then ```
it shows a large warning and asks for confirmation, shows the warning again [ ] Update BIOS (at your own risk): now F7F0107, newest F7F0108 (opt-in, runs once)
and continues when you type `UPDATE`; the BIOS is written during the next restart. ```
It can only be ticked when Valve has a newer BIOS than yours; when you're up
to date, when the newest version can't be looked up (offline), or when an
update is already waiting for a restart, it's greyed out.
When you run it, the wizard:
1. downloads Valve's package and checks its **SHA-256** against Valve's
repository, so it's exactly Valve's file;
2. asks **fwupd** whether the firmware is for this very machine (fwupd compares
the firmware's hardware IDs with the device) and stops if it isn't;
3. shows a large red **warning** with the current and the new version, and asks
whether you understand the risks (default: no);
4. shows the warning **again** and only continues when you type `UPDATE`;
5. hands the firmware to fwupd, which writes it during the **next restart**:
choose "restart now" or restart later yourself.
**At your own risk:** a failed or interrupted BIOS update can leave the machine **At your own risk:** a failed or interrupted BIOS update can leave the machine
unable to start. Keep it on mains power, and never turn off the power, unplug unable to start. Keep it on mains power, and never turn off the power, unplug
it or press the power button while it updates, including during the restart it or press the power button while it updates, including during the restart;
afterwards; the screen can stay black for several minutes. fwupd refuses the the screen can stay black for several minutes.
file on anything that isn't a Steam Machine.
To walk through it without flashing anything, run the wizard with
`WIZARD_BIOS_DRY_RUN=1`: it downloads and checks the package and shows both
warnings, skips fwupd's device check, and only prints the install command.
### Manual session control ### Manual session control
+23 -6
View File
@@ -6,6 +6,10 @@
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own. # Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
BIOS_REPO_PREFIX=holo BIOS_REPO_PREFIX=holo
# WIZARD_BIOS_DRY_RUN=1 walks through the whole BIOS update (download,
# checksum, both warnings) but never flashes: fwupd's device check is
# skipped and the install is only printed. For testing, e.g. in a VM.
BIOS_DRY_RUN="${WIZARD_BIOS_DRY_RUN:-}"
bios_available() { detect_valve_fremont; } bios_available() { detect_valve_fremont; }
@@ -45,7 +49,7 @@ bios_lookup_newest() {
bios_selectable() { bios_selectable() {
# Only when Valve has a newer BIOS than the one installed; the menu # Only when Valve has a newer BIOS than the one installed; the menu
# greys the item out otherwise (up to date, or newest unknown/offline). # greys the item out otherwise (up to date, or newest unknown/offline).
[[ -n "${BIOS_NEWEST:-}" && "$BIOS_NEWEST" != "$(bios_current)" ]] [[ -z "${BIOS_NEEDS_RESTART:-}" && -n "${BIOS_NEWEST:-}" && "$BIOS_NEWEST" != "$(bios_current)" ]]
} }
bios_label() { bios_label() {
@@ -53,6 +57,7 @@ bios_label() {
local newest="newest unknown (offline?)" local newest="newest unknown (offline?)"
[[ -n "${BIOS_NEWEST:-}" ]] && newest="newest $BIOS_NEWEST" [[ -n "${BIOS_NEWEST:-}" ]] && newest="newest $BIOS_NEWEST"
[[ "${BIOS_NEWEST:-}" == "$(bios_current)" ]] && newest="up to date" [[ "${BIOS_NEWEST:-}" == "$(bios_current)" ]] && newest="up to date"
[[ -n "${BIOS_NEEDS_RESTART:-}" ]] && newest="$BIOS_NEWEST staged, restart to install"
echo "Update BIOS (at your own risk): now $(bios_current), $newest" echo "Update BIOS (at your own risk): now $(bios_current), $newest"
} }
@@ -114,8 +119,9 @@ bios_enable() {
err "Couldn't find the newest Steam Machine BIOS on Valve's mirror ($VALVE_MIRROR)." err "Couldn't find the newest Steam Machine BIOS on Valve's mirror ($VALVE_MIRROR)."
return 1 return 1
fi fi
local current tmp local current tmp compatible
current="$(bios_current)" current="$(bios_current)"
[[ -n "$BIOS_DRY_RUN" ]] && warn "DRY RUN (WIZARD_BIOS_DRY_RUN): nothing will be flashed."
if [[ "$current" == "$BIOS_NEWEST" ]]; then if [[ "$current" == "$BIOS_NEWEST" ]]; then
ok "The BIOS is already the newest version ($current); nothing to do." ok "The BIOS is already the newest version ($current); nothing to do."
return 0 return 0
@@ -136,19 +142,24 @@ bios_enable() {
return 1 return 1
fi fi
ok "Checksum OK: this is Valve's $BIOS_PKG." ok "Checksum OK: this is Valve's $BIOS_PKG."
if ! bios_fits_device "$tmp/$BIOS_CAB"; then local yes="$c_green$c_bold" b="$c_bold" n="$c_reset"
if [[ -n "$BIOS_DRY_RUN" ]]; then
warn "Dry run: skipping fwupd's check that the firmware fits this machine."
compatible="${c_yellow}${b}not checked${n} (dry run)"
elif bios_fits_device "$tmp/$BIOS_CAB"; then
ok "fwupd confirms BIOS $BIOS_NEWEST is firmware for this machine."
compatible="${yes}yes${n} (checked by fwupd)"
else
err "fwupd says BIOS $BIOS_NEWEST is not for this machine's hardware; not installing it." err "fwupd says BIOS $BIOS_NEWEST is not for this machine's hardware; not installing it."
rm -rf "$tmp" rm -rf "$tmp"
return 1 return 1
fi fi
ok "fwupd confirms BIOS $BIOS_NEWEST is firmware for this machine."
local yes="$c_green$c_bold" b="$c_bold" n="$c_reset"
bios_disclaimer "WARNING: BIOS UPDATE - ENTIRELY AT YOUR OWN RISK" \ bios_disclaimer "WARNING: BIOS UPDATE - ENTIRELY AT YOUR OWN RISK" \
"Current BIOS: ${b}$current${n}" \ "Current BIOS: ${b}$current${n}" \
"New BIOS: ${b}$BIOS_NEWEST${n}" \ "New BIOS: ${b}$BIOS_NEWEST${n}" \
"Checksum: ${yes}OK${n} (Valve's package)" \ "Checksum: ${yes}OK${n} (Valve's package)" \
"Compatible: ${yes}yes${n} (checked by fwupd)" "Compatible: $compatible"
if ! ask_yn "Do you understand the risks and want to continue?" n; then if ! ask_yn "Do you understand the risks and want to continue?" n; then
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0 info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
fi fi
@@ -161,6 +172,12 @@ bios_enable() {
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0 info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
fi fi
if [[ -n "$BIOS_DRY_RUN" ]]; then
ok "Dry run: would now run: sudo fwupdmgr install -y --no-reboot-check $BIOS_CAB"
ok "Dry run finished; nothing was flashed and no restart is needed."
rm -rf "$tmp"
return 0
fi
info "Handing BIOS $BIOS_NEWEST to fwupd. Do NOT turn off the power from now on." info "Handing BIOS $BIOS_NEWEST to fwupd. Do NOT turn off the power from now on."
# -y: we already asked twice; --no-reboot-check: the wizard's own # -y: we already asked twice; --no-reboot-check: the wizard's own
# restart question comes at the end. # restart question comes at the end.
+85 -37
View File
@@ -15,7 +15,7 @@
set -uo pipefail set -uo pipefail
# Release version, see CHANGELOG.md. # Release version, see CHANGELOG.md.
VERSION=0.7.0 VERSION=0.8.0
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -39,41 +39,91 @@ fi
# user running the script. # user running the script.
TARGET_USER="$(id -un)" TARGET_USER="$(id -un)"
detect_components restart_needed() { [[ -n "${BIOS_NEEDS_RESTART:-}" || "$RESTART_FOR_LOGIN" == true ]]; }
run_menu || { info "Nothing changed."; exit 0; }
plan_changes
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then restart_now() {
ok "Everything is already the way you want it." if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
warn "The BIOS update is written during this restart. Keep the power on and don't"
warn "touch the machine until it has fully started again, even if the screen stays black."
fi
info "Restarting..."
sudo reboot
exit 0 exit 0
fi }
echo after_run() {
echo -e "${c_bold}This will:${c_reset}" # After a run: back to the menu, or restart right away when something
for c in "${TO_DISABLE[@]}"; do echo " - turn off: ${LABEL[$c]}"; done # that just ran needs it. Returns 1 when input has ended (scripted runs).
for c in "${TO_ENABLE[@]}"; do local reply
if is_action "$c"; then echo " - run: ${LABEL[$c]%%:*} (checks, then asks twice more)" if ! restart_needed; then
elif [[ "${CURRENT[$c]}" == 1 ]]; then echo " - re-apply: ${LABEL[$c]}"; else echo " - turn on: ${LABEL[$c]}"; fi read -rp "Press Enter to go back to the menu... " _ || return 1
return 0
fi
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
warn "The BIOS update is installed at the next restart."
else
info "The login changes take effect after a restart."
fi
while true; do
read -rp "$(echo -e "${c_bold}[m]${c_reset} back to the menu ${c_bold}[r]${c_reset} restart now: ")" reply || return 1
case "$reply" in
m|M|"") return 0 ;;
r|R) restart_now ;;
*) warn "Type m or r." ;;
esac
done
}
# Menu loop: after each run the menu comes back with the new state, until
# the user quits; the restart question comes then, once, for everything.
RESTART_FOR_LOGIN=false
SUDO_KEEPALIVE=false
while true; do
detect_components
run_menu || break
plan_changes
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
ok "Everything is already the way you want it."
read -rp "Press Enter to go back to the menu... " _ || break
continue
fi
echo
echo -e "${c_bold}This will:${c_reset}"
for c in "${TO_DISABLE[@]}"; do echo " - turn off: ${LABEL[$c]}"; done
for c in "${TO_ENABLE[@]}"; do
if is_action "$c"; then echo " - run: ${LABEL[$c]%%:*} (checks, then asks twice more)"
elif [[ "${CURRENT[$c]}" == 1 ]]; then echo " - re-apply: ${LABEL[$c]}"; else echo " - turn on: ${LABEL[$c]}"; fi
done
ask_yn "Go ahead?" y || { info "Nothing changed."; continue; }
# Ask for the sudo password once and keep it fresh, instead of prompting
# at random points during the run.
sudo -n true 2>/dev/null || sudo -v || exit 1
if [[ "$SUDO_KEEPALIVE" == false ]]; then
SUDO_KEEPALIVE=true
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
fi
apply_changes
# Login manager changes only take effect after a restart.
[[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" gaming "* || " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" single "* ]] &&
RESTART_FOR_LOGIN=true
echo
detect_components
echo -e "${c_bold}Done. Current state:${c_reset}"
for c in "${COMPONENTS[@]}"; do
component_available "$c" && ! is_action "$c" || continue
if [[ "${CURRENT[$c]}" == 1 ]]; then echo -e " ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " off ${LABEL[$c]}"; fi
done
if [[ ${#FAILED[@]} -gt 0 ]]; then
warn "These had problems (see above): ${FAILED[*]}"
fi
echo
after_run || break
done done
ask_yn "Go ahead?" y || { info "Nothing changed."; exit 0; }
# Ask for the sudo password once and keep it fresh, instead of prompting at
# random points during the run.
sudo -n true 2>/dev/null || sudo -v || exit 1
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
apply_changes
echo
detect_components
echo -e "${c_bold}Done. Current state:${c_reset}"
for c in "${COMPONENTS[@]}"; do
component_available "$c" && ! is_action "$c" || continue
if [[ "${CURRENT[$c]}" == 1 ]]; then echo -e " ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " off ${LABEL[$c]}"; fi
done
if [[ ${#FAILED[@]} -gt 0 ]]; then
warn "These had problems (see above): ${FAILED[*]}"
fi
echo echo
# A staged BIOS update is written during the restart. # A staged BIOS update is written during the restart.
@@ -85,14 +135,12 @@ if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
else else
info "The BIOS update installs at your next restart." info "The BIOS update installs at your next restart."
fi fi
exit 0 elif [[ "$RESTART_FOR_LOGIN" == true ]]; then
fi
# Login manager changes only take effect after a restart.
if [[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" gaming "* || " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" single "* ]]; then
if ask_yn "Restart now so the changes take effect?" n; then if ask_yn "Restart now so the changes take effect?" n; then
sudo reboot sudo reboot
else else
info "Restart whenever you're ready." info "Restart whenever you're ready."
fi fi
else
info "Bye."
fi fi