Skip to content

bentemple/steamos-extensions

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SteamOS System Modification Persistence

This repo documents and provides an example set of extensions that utilize the systemd-sysext mechanism. This mechanism can be used to create permanent system modifications that support filesystem overlays and automatically enabled systemd unit files.

This repo is a fork of MiningMarsh/steamos-extension-examples I extended it to combine the unpacked extensions and then use Github actions to pack the extensions as releases instead of having 2 separate repositories. All credit to MiningMarsh for putting this together so elegantly.

I also added a Steamdeck Hibernate After Sleep extension, as that was my first primary use-case for wanting to persist a major change to my steamdeck and ensure I didn't need to do anything between updates to retain the functionality.

Disclaimer

I provide no warranties for this code. Modifying your steamdeck's software could potentially make your device unbootable. Typically this is recoverable from a bootable USB drive, but proceed at your own risk.

Quick Start

Copy any desired extensions into /var/lib/extensions/ along with the steamos-extension-loader.raw extension. Run the following command to enable all the extensions you copied:

systemctl enable --now systemd-sysext.service
systemctl enable --now steamos-extension-loader-installer.service

Reboot your steamdeck, the extensions should now be installed.

Extension Summary

Required:

steamos-extension-loader - Persists the extensions between system updates and installs new extensions

Optional extensions:

Boot:

  • steamos-extension-hibernate-after-sleep - Auto-hibernates after configurable suspend duration (default 60min) with swap/GRUB/Bluetooth fixes
  • steamos-extension-retain-boot - Forces SteamOS as next boot entry after each reboot (dual-boot helper)

Utilities:

  • steamos-extension-clean-games - Auto-removes untracked game directories and orphaned shader caches from Steam install paths
  • steamos-extension-compat-tools - Auto-installs/updates emulators Boxtron, Luxtorpeda, Roberta, and Proton GE to latest versions
  • steamos-extension-update-decky-loader - Auto-updates Decky Loader stable channel (restarts Steam client on update)
  • steamos-extension-update-btrfs - Auto-updates steamos-btrfs on schedule (SteamOS only, not HoloISO)
  • steamos-extension-update-flatpak - Scheduled repair/update of all flatpaks with dependency cleanup

Performance Tweaks:

  • steamos-extension-performance-tuning - Applies performance tweaks and AC/battery-aware CPU governor/NVMe tuning via udev rules
  • steamos-extension-thermal-tdp - Dynamic TDP management: bursts to 20W then throttles to 15W based on temperature (Steam Deck only)
  • steamos-extension-preload - Pre-caches frequently-loaded files to minimize latency
  • steamos-extension-prelockd - Prevents executable memory pages from swapping to reduce latency
  • steamos-extension-nohang - Minimizes system latency during low-memory conditions via nohang daemon
  • steamos-extension-irqbalance - Balances CPU interrupts across cores while minimizing active cores for power efficiency
  • steamos-extension-disable-mitigations - Adds mitigations=off kernel parameter for potential performance at security cost

Other:

  • steamos-extension-zram - Configures zram swap + ext4 filesystem for caching frequently-written directories in RAM - Mostly a toy, likely don't use

HoloISO Support

Details

Most of these extensions have been tested to function against HoloISO. HoloISO is close enough to SteamOS in implementation that minimal levels of support code is needed to target both.

All of these extensions assume that the player's username is deck, and a few won't function on HoloISO installs using a different username. Specific details about this are mentioned in the individual extension's documentation at the end of this README.

How It Works: systemd-sysext

Details

The mechanism this repo provides is little more than a supplement to systemd's built-in systemd-sysext mechanism. The primary addition this mechanism adds is a way to automatically load systemd units from installed systemd-sysext extensions, whereas normal extensions require users to manually enable any units they wish to use, which won't survive upgrades.

For documentation on how to build systemd-sysext extensions, please see here: https://www.freedesktop.org/software/systemd/man/latest/systemd-sysext.html

The rest of this README.md will focus on the specific differences needed to use this extension system wrapper.

steamos-extension-loader

The only required extension is provided by steamos-extension-loader.raw.

To install the loader, place the steamos-extension-loader.raw file in /var/lib/extensions.

Next, get into a terminal session and run as root:

systemctl enable --now systemd-sysext.service
systemctl enable --now steamos-extension-loader-installer.service

How it Works: steamos-extension-loader

Details

steamos-extension-loader.service and steamos-extension-loader-installer.service have two purposes:

  1. They make sure that system updates do not uninstall their services and supporting files.
  2. They install themselves as a boot service that loads any other installed extensions by making sure the appropriate unit files are enabled and running.

Persistence

steamos-extension-loader-installer.service maintains its persistence in a fairly straightforward way. First, it checks /etc/steamos-extension-loader, /etc/systemd/system/steamos-extension-loader.service and /etc/atomic-update.d/steamos-extension-loader.conf, ensuring they have identical checksums to the files packaged in the extension. If they don't exist or have mismatching checksums, it copies the bundled file into those locations.

Secondly, steamos-extension-loader-installer.service enables and runs the steamos-extension-loader.service unit if it is not already enabled and active.

steamos-extension-loader.service, among other things, will start and enable steamos-extension-loader-installer.service and systemd-sysext.service, thus ensuring that steamos-extension-loader.raw updates get copied up into /etc.

Finally, the file placed in /etc/atomic-update.d ensures that none of the installed files are lost after a system update.

If persistence is ever lost, it should be enough to re-run the installation commands.

Unit Files

steamos-extension-loader.service, in addition to helping with persistence, also ensures that services from other extensions are enabled and loaded. This is the advantage of steamos-extension-loader.service, as systemd-sysext.service provides no equivalent mechanism (at least as far as this author was able to determine; please correct me if I have overlooked anything here).

The algorithm it uses to enable units is very straightforward:

  1. Any system unit file starting with steamos-extension- is passed to systemctl preset. After that, it checks if the unit is enabled. If it is enabled and it is not yet running, steamos-extension-loader.service starts the unit. This allows extension authors to decide which services and timers should be loaded by providing a correct systemd-preset file.

  2. User unit files are treated differently. Systemd does not have an equivalent to systemd preset for user units; thus, every single unit is simply passed to systemctl enable --global, so that they will be loaded during logon. To control which units are running, you must ensure a correct install target. If you have a service fired by a timer that shouldn't run otherwise, omit the entire [Install] section in the unit file. User units also need to start with steamos-extension- to be considered for loading.

System Updates

The SteamOS update mechanism does not like systemd-sysext.service to be running, as it creates a read-only overlayfs on /usr. To solve this problem, systemd-sysext.service unloads itself when rauc.service (the update service) is started. Unfortunately, rauc.service does not unload itself until reboot, which means all extensions are unloaded until reboot. Updates that occur during boot-up do not conflict with systemd-sysext.service, as only steam client updates can apply during boot-up.

Optional Extensions

Installing additional extensions is as easy as placing them in /var/lib/extensions and rebooting.

Extensions can be uninstalled by removing their extension file from /var/lib/extensions, and rebooting. It is safe to leave the loader installed even if all extensions are uninstalled, it just won't do anything.

Some extensions may change grub boot options in order to add kernel parameters. You can permanently uninstall the changes they make by removing the extension, swapping from stable to beta branch or vice versa, and then switching back. SteamOS will regenerate the boot configuration during upgrades, overwriting the changes the extensions made. Make sure that the extension file is removed before the changes in branch take place.

A number of example extensions that I personally use are included in this repo, with explanations of what they do in the following sections.

steamos-extension-hibernate-after-sleep

Why? Because I was tired of finding my steamdeck dead if I didn't use it for a few days but forgot to put it on the charger. I would rather wait 20 seconds if I haven't used it in > 1 hour (or x time, configurable) This will also help to preserve battery life long-term by not needlessly cycling the battery.

This extension enables hibernate-after-sleep functionality, automatically hibernating the Steam Deck after being suspended for a configurable period (default: 60 minutes). It changes also changes the swap file (default: 20GB), configures GRUB with resume parameters, and fixes Bluetooth issues after resume.

This code was based off of the following publication: https://github.com/nazar256/publications/blob/main/guides/steam-deck-hibernation.md

To configure, copy /usr/share/doc/steamos-extension-hibernate-after-sleep/example-config to /home/deck/.config/hibernate-after-sleep, edit HibernateDelaySec (e.g., "30min", "2h") and TargetSwapFileSizeInGbs (e.g., 10, 30), and run sudo /usr/sbin/steamos-extension-hibernate-after-sleep-setup. Changes require a reboot. Additionally, this script copies an uninstaller to /home/deck/.bin for easy removal should you want to turn the extension off, simply run sh /home/deck/.bin/steamos-extension-hibernate-after-sleep-uninstall.sh

Thanks to nazar256 for documenting how to get hibernation working on the steamdeck. I simply took his work, and some of the tips mentioned in github issues, to create the script that was the original basis for this extension.

steamos-extension-retain-boot

This extension sets SteamOS as the next boot entry after each reboot. This can be useful when dual booting if the other OS likes to mess with the boot order.

This extensiom functions on HoloISO, but might choose the boot order incorrectly on systems dual booting HoloISO and SteamOS.

steamos-extension-clean-games

This extension automatically removes any game directory from Steam's common install path if they are not tracked by an installed package (game). It also removes any shadercache for missing packages, preventing size buildup of shadercache.

steamos-extension-compat-tools

This extension regularly installs and updates Boxtron, Luxtorpeda, Roberta, and Proton GE. It always installs the latest version, and it changes their labels to "DosBox", "Source Ports", "ScummVM", and "Proton GE" respectively. In particular, you can set games to use "Proton GE" by default, and they will always use the latest version.

steamos-extension-update-decky-loader

If you use Decky Loader, this extension will automatically update it when an update is available. Be warned, it only supports the stable channel, and can't update plugins. Additionally, whenever an update occurs, the Steam client will restart, returning you to the main menu. Your game will still be running and accessible.

Note that this extension cannot perform the initial Decky Loader install. The Decky Loader installation scripts do not appear to function for fresh installs when invoked directly from a root context.

This extension only functions on HoloISO of the player's username is deck.

steamos-extension-update-btrfs

If you use steamos-btrfs, this extension will automatically update it on a schedule.

Don't use this extension with HoloISO. steamos-btrfs likely doesn't function correctly against HoloISO.

steamos-extension-update-flatpak

This extension repairs and updates all installed user and system flatpaks on a schedule. It also removes any unused dependencies after updates.

steamos-extension-performance-tuning

This extension applies various performance tuning changes. Additionally, it installs udev rules that will change the CPU governor, NVMe parameters, etc. when the system transitions from on AC power to off AC power and vice versa. When on AC power, everything is pinned to a maximum performance setting. When off AC power, settings are pinned to values that should give a good balance between performance and power savings.

This extension changes some kernel command line parameters and will cause an additional reboot after updates are applied. When used together with disable-mitigations, only one additional reboot will occur, not two.

This extension does not apply kernel command line performance tweaks on HoloISO if it is detected. The kernel parameters caused boot issues for this author, and have been set to only apply to SteamOS, where they function correctly.

steamos-extension-thermal-tdp

This extension bundles a daemon that automatically sets the system TDP limit to 20w, and lowers it slowly back down to 15w based on system temperature.

This should allow bursty games to run at 20w, while keeping sustained loads at 15w to prevent overheating.

This utility should not be used on any hardware except the steam deck! Most likely, it won't do anything, however, there is a small possibility that this daemon could set inappropriate TDP values for some other AMD SoC than the steam deck.

steamos-extension-preload

This extension installs the preload service. preload attempts to minimize system latency by pre-caching commonly loaded files. A state file will be left at /var/lib/preload.state if you uninstall this extension. The state file is minimal in size (under a megabyte typically).

steamos-extension-prelockd

This extension installs prelockd to help minimize system latency by preventing executable memory-mapped pages from being swapped.

steamos-extension-nohang

This extension installs nohang to help minimize system latency in low memory conditions.

steamos-extension-irqbalance

This extension installs and runs the irqbalance service, which automatically balances interrupts across CPU cores. It is configured to try and minimize the number of running cores in addition to balancing interrupts to strike a better balance between power consumption and performance.

steamos-extension-disable-mitigations

This extension adds mitigations=off to SteamOS' boot config. It is debatable whether this improves performance, so treat this extension with caution. This also definitely makes your installation less secure.

I recommend only using this extension if you understand spectre-like vulnerabilities and can perform your own risk and threat assessment.

This extension will cause an additional reboot after updates are applied. When used together with performance-tuning, only one additional reboot will occur, not two.

steamos-extension-zram

This extension hijacks the Steam Deck's zram configuration in an obtuse way. I'm not sure I'd recommend anyone else use it; it is almost a toy.

This extension sets up a zram-based swap that uses a third of the system's RAM allocation, then it creates a second zram device with ext4 that is mounted in /home/deck/.zram and uses another third. Then, it bind mounts various directories (e.g., ~/.cache, the Steam client appcache, the Decky Loader log directories, ...) into that zram device so that things like mesa cache updates get to skip the disk when writing. On shutdown, it synchronizes the RAM cache to disk, and on the next boot, will only buffer the changed files. I've seen this use around max 600 MiB RAM, but after the cache is hot, it generally seems to cap out around 100 MiB.

The motivation for this extension was that btrfs seemed to cause hangs under heavy write loads, which would cause games to hitch for a second when other games were being updated. This was an attempt to alleviate that.

This extension significantly slows down shutdowns and system updates, as they have to wait for the RAM cache to synchronize to disk first.

This extension will only function on HoloISO if the player's username is deck.

About

Steamos-extensions for modifying SteamOS with persistence across reboots

Resources

License

Stars

Watchers

Forks

Contributors

Languages

  • Python 69.4%
  • Shell 29.1%
  • C 1.5%