- SteamOS 3 “Holo” es una distribución basada en Arch para Steam Deck, pero para corregir el problema al reanudar desde suspensión en una PC de sala fue necesario revertir un commit del kernel y hacer un fork directo hasta de la imagen rootfs
- La estructura de actualización usa un esquema A/B: instala un nuevo rootfs de solo lectura en la partición inactiva y luego reinicia;
/etcconserva los cambios mediante overlayfs - Los parches del kernel de Valve siguen un flujo en el que se clona un repositorio Git bare desde tarballs de código fuente como
linux-neptune-61-6.1.52.valve9-1.src.tar.gzdel mirror de fuentes de pacman, y se compilan paquetes con tags propios y PKGBUILD - Reempaquetar el rootfs implica extraer
rootfs.img.caibxdel bundle RAUC de SteamOS, convertirlo en imagen, cambiar el UUID de Btrfs, reemplazar paquetes, cambiar elbuildid, reemplazar las URL de actualización y el certificado RAUC, y volver a empaquetarlo como bundle RAUC - Si un servidor web propio ofrece
live.jsony se cambianQueryUrl,ImagesUrlyMetaUrldesteamos-atomupd, también se puede actualizar una instalación existente de SteamOS con una imagen propia
Por qué hice un fork de SteamOS para una PC de sala
- SteamOS 3 “Holo” es una distribución Linux basada en Arch para Steam Deck, la PC portátil de videojuegos de Valve Software
- Su método de actualización usa una estructura de actualizaciones atómicas A/B: descarga un nuevo rootfs de solo lectura en la partición inactiva y reinicia hacia esa partición
- El usuario puede ejecutar
steamos-devmodepara desbloquear el rootfs y normalizar la base de datos de pacman, y así tratarlo como una distribución Linux común - El objetivo era crear un fork adecuado que pudiera modificar la propia imagen rootfs, en lugar de esquivarlo fácilmente con
steamos-devmode - En la PC de sala, SteamOS funcionaba casi por completo, pero fallaba únicamente al reanudar desde suspensión
- En la misma computadora, otras distribuciones que usan kernels mainline o stable sí reanudan desde suspensión correctamente
- Tras encontrar el código fuente del kernel de Valve y ejecutar
git bisect, el resultado fue que un commit que parece corregir la reanudación desde suspensión en el hardware de Steam Deck causaba problemas en esta PC - La razón directa de todo el trabajo fue tener que revertir ese commit y compilar el kernel manualmente
- También existía la opción de usar Arch directamente, entre otras, pero si había que ajustar una distribución Linux para ejecutar juegos, era preferible apoyarse en el conjunto de paquetes probado por Valve
Particiones y estructura de actualización de SteamOS
- El sistema SteamOS usa 8 particiones
- La EFI system partition contiene el stage 1 bootloader y metadatos para seleccionar el conjunto de particiones A/B
- Cada conjunto A/B incluye GRUB como stage 2 bootloader, el root filesystem y una partición
/var - El resto del espacio del disco lo ocupa una única partición
home
- Durante el arranque se montan además varios pseudo-filesystems
- Casi una docena de directorios, como
/var/log,/rooty/nix, se montan con bind mount desde/home/.steamos/offloadpara hacer persistentes los datos
- Casi una docena de directorios, como
/etcse maneja con overlayfs- Los cambios se guardan en
/var/lib/overlays/etc/upper - Se conservan elementos que normalmente deben permanecer en
/etc, comomachine-idy las conexiones de NetworkManager - Los archivos de configuración que no se hayan tocado pueden actualizarse
- Este método gestiona a la vez la conservación y la actualización de archivos de configuración dentro de una estructura de particiones A/B, sin lógica de gestor de paquetes
- Los cambios se guardan en
- La actualización del sistema comienza cuando el cliente de Steam o un usuario en la terminal ejecuta
steamos-update- Este comando ejecuta el programa Python
steamos-atomupd-client - El cliente envía la información del SO actual y la configuración del canal de actualización del usuario a la URL en
/etc/steamos-atomupd/client.confpara comprobar si hay una actualización nueva
- Este comando ejecuta el programa Python
- Si hay una actualización nueva, el servidor responde con la ruta de un bundle RAUC
- El cliente descarga el bundle y ejecuta
rauc install - RAUC verifica la firma del bundle y busca
rootfs.img.caibx - Con
casync extract, descarga los fragmentos de la nueva imagen y los escribe en la partición rootfs inactiva - El script post-install sincroniza selectivamente datos desde el
/varactivo hacia el/varinactivo, y cambia la configuración del stage 1 bootloader en la EFI system partition para que arranque desde el nuevo conjunto de particiones
- El cliente descarga el bundle y ejecuta
Crear paquetes desde el código fuente del kernel de Valve
- Valve usa en SteamOS un kernel de Linux muy modificado, y el código fuente está disponible para descarga
- El código fuente de la imagen actual de SteamOS puede encontrarse en
sources/holo-3.5ysources/jupiter-3.5del mirror pacman de Valve - Al momento de escribir, el kernel de la imagen stable era
6.1.52-valve9-1-neptune-61, y el tarball de código fuente correspondiente pesa 2.9GiB - El tarball es grande porque incluye todo el árbol Git de Linux
- Dentro del tarball hay elementos como
PKGBUILD,config,config-neptuneyarchlinux-linux-neptune/ archlinux-linux-neptune/no es un working tree normal listo para trabajar, sino un repositorio bare
- Dentro del tarball hay elementos como
- El PKGBUILD apunta como fuente a un repositorio GitLab privado con la forma
git+ssh://git@gitlab.steamos.cloud/jupiter/linux-integration.git#tag=$_tag- No se puede clonar directamente ni enlazar commits
- Desde las fuentes de
makepkgse puede obtener un snapshot que contiene todo el historial de commits de cada tag - Gracias a esta estructura fue posible hacer bisect del commit que rompía la reanudación desde suspensión en la PC de sala
- El flujo de trabajo consiste en clonar el repositorio bare como un working tree normal y mantener una rama y tags propios
- El ejemplo consiste en crear
my-branchdesde el tag6.1.52-valve9 - Los cambios propios se suben a otro host Git, y en PKGBUILD se cambia el source a ese repositorio y a un tag propio
- Como repositorio de ejemplo está linux
- El ejemplo consiste en crear
- Se puede crear el paquete del kernel con
makepkgmakepkg MAKEFLAGS=-j$(nproc)o actualizar/etc/makepkg.confresulta útil cuando no se está en una VM pequeña- En lo revisado, los paquetes específicos de SteamOS también usaban una estructura similar, con un repositorio Git como primer source
- Para facilitar los pasos posteriores, se configuró un repo pacman propio
- Se colocan los paquetes en un directorio, se ejecuta
repo-add $REPO_NAME.db.tar.zst [PACKAGES...]y luego se sube a un host web - Este repo también ayuda a que las herramientas funcionen correctamente si más tarde se ejecuta
steamos-devmode
- Se colocan los paquetes en un directorio, se ejecuta
Obtener y montar el root filesystem
- Como no se encontraron scripts de release engineering, se optó por reempaquetar el root filesystem existente según las necesidades
- Los scripts sin explicaciones ni comentarios están en fauxlo
- El método habitual para obtener la imagen rootfs de SteamOS es comprar una Steam Deck o descargar la imagen de recuperación de Steam Deck, pero ambos requieren aceptar el Steam End User License Agreement
- La versión de release actual puede verse en el JSON de snapshots que parece ser la URL fallback del sistema de actualizaciones
- Al momento de escribir, la versión stable era
20231122.1 - También hay un JSON de snapshots separado para el canal preview
- Al momento de escribir, la versión stable era
- La descarga del rootfs sigue el mismo orden que
steamos-atomupd-client- Se descarga el archivo
.raucb, que es el bundle RAUC - Del bundle, que es un filesystem SquashFS, se extrae
rootfs.img.caibx - Con
casync extract, se toman fragmentos desde el store.castry se generarootfs.img - La URL del store
.castres la URL del bundle RAUC reemplazando.raucbpor.castr - Este comportamiento está hardcodeado en
steamos-atomupd - El script de automatización está en fetch-current.sh
- Se descarga el archivo
- Los archivos
.img.zipy.img.zstcercanos no son rootfs, sino una imagen de recuperación booteable separada- También se podría extraer la partición rootfs de la imagen de recuperación y usarla en el siguiente paso
- Pero no era idéntica bit a bit a la imagen recibida con RAUC y casync, y de todos modos esas herramientas son necesarias para volver a crear el update bundle
- Antes de modificar el rootfs hay que cambiar el UUID del filesystem
- Si se actualiza desde una imagen existente de SteamOS a una imagen personalizada sin cambiar el UUID, dos filesystems distintos tendrán el mismo UUID
- Ese estado puede causar problemas
- Un ejemplo es
btrfstune -fu rootfs.img
- Valve usa una imagen Btrfs con compresión zstd
- Para mantener la compresión durante los cambios, se monta con
mount -o compress=zstd rootfs.img rootfs - Como SteamOS usa la propiedad de subvolume
readonlyde Btrfs, se desactiva conbtrfs property set -ts rootfs ro false
- Para mantener la compresión durante los cambios, se monta con
- Modificar paquetes como el kernel de Linux puede disparar scripts que requieren
/devy/proc- Se montan
devtmpfsyprocdebajo del rootfs - Para evitar escrituras en directorios que se montarán en el sistema booteado, se monta tmpfs en
/tmp,/run,/vary/home - Se hace bind mount del
/etc/resolv.confdel host para que la resolución de nombres funcione dentro del chroot
- Se montan
Reemplazar paquetes y modificar metadatos de la imagen
- El repositorio propio se agrega como primera entrada de repo en
/etc/pacman.conf- Así, aunque haya paquetes de versiones más recientes en los repos de Valve, los paquetes propios tienen prioridad
- Incluso si más adelante se ejecuta
steamos-devmode, se pueden reinstalar los paquetes propios
- El stanza de repo de ejemplo usa
[fauxlo],Server = https://fauxlo.ili.fyi/pacman/$archySigLevel = NeverSigLevel = Neverpermite paquetes sin firma- Para instalar paquetes con firma GPG hay que poblar el keyring de pacman
- En lugar de tocar el keyring vacío de
/etc/pacman.d/gnupg, se usó un método que puebla un keyring nuevo sobre tmpfs
- La instalación de paquetes se realiza con una forma como
pacman --sysroot rootfs --noconfirm -Sy linux-neptune-61- En el script real se evita
-yy solo se sincroniza por detrás la base de datos del repo propio de pacman - Esto permite fijar el estado de los demás repositorios al momento en que se construyó la imagen original
- Es una decisión para reducir los cambios que aparecen en el diff de la imagen
- En el script real se evita
steamos-atomupdlee la versión de la imagen actual y el build ID desde/lib/steamos-atomupd/manifest.json; si no existe, usa/etc/os-release- Si el build ID de la actualización ofrecida por el servidor es igual al de la imagen actual, rechaza la actualización
- También es útil para identificar qué imagen se está ejecutando
- El build ID debe estar obligatoriamente en formato
YYYYMMDD.N- Si el formato no coincide,
steamos-atomupdtermina con un traceback de Python - Para evitar incrementarlo manualmente, se puede poner
HHMMSSo un timestamp Unix enN - Se cambian juntos el
buildiddemanifest.jsony elBUILD_IDdeos-release - El fragmento de script Bash para esta tarea está en repack.sh
- Si el formato no coincide,
- RAUC usa certificados X.509 para la configuración de confianza
- El certificado confiable está en
/etc/rauc/keyring.pem - Basta con un certificado simple self-signed
- Se instala el nuevo certificado en
rootfs/etc/rauc/keyring.pem
- El certificado confiable está en
- También se cambian las URL de
rootfs/etc/steamos-atomupd/client.confal servidor propioQueryUrlImagesUrlMetaUrl
- Mientras no se exceda el espacio de la imagen Btrfs de 5GiB, se pueden hacer otros cambios
- Por ejemplo, si se quiere encontrar el dispositivo SteamOS en la red como
hostname.local, se puede eliminarrootfs/usr/lib/systemd/resolved.conf.d/00-disable-mdns.conf - También se podría sobrescribir mediante la configuración overlay de
/etc, pero se consideró engorroso
- Por ejemplo, si se quiere encontrar el dispositivo SteamOS en la red como
- Como principio, los cambios que pueden hacerse fácilmente sin tocar la imagen no se incluyen en el rootfs
- Firefox puede instalarse en el rootfs
- Pero habría que volver a reempaquetar la imagen con cada actualización de seguridad de Firefox
Desmontar el rootfs y crear el bundle RAUC
- Al terminar las modificaciones, el filesystem se marca otra vez como read-only
btrfs property set -ts rootfs ro true
- Los bloques no usados se descartan con
fstrim -v rootfs - Para desmontar resulta útil
umount --recursive rootfs- Permite procesar también los pseudo-filesystems montados antes
- Antes de crear el bundle RAUC hay que generar el casync store y el blob index
- Un ejemplo es
casync make --store=rootfs.img.castr bundle/rootfs.img.caibx rootfs.img
- Un ejemplo es
- El bundle RAUC necesita tres archivos
manifest.raucmrootfs.img.caibxUUID, con el UUID del filesystem
manifest.raucmcontiene información de la actualización y de la imagen rootfscompatible=steamos-amd64version=$versionsha256sizefilename=rootfs.img.caibx
- El archivo
UUIDse crea conblkid -s UUID -o value rootfs.img >bundle/UUID - Después de preparar los tres archivos, se ejecuta
rauc bundle- Se especifican el certificado y la clave en
--signing-keyring,--certy--key - El resultado es
rootfs.img.raucb
- Se especifican el certificado y la clave en
rootfs.img.raucbyrootfs.img.caibxse suben al servidor web al que apuntaImagesUrlenclient.conf- Ambos archivos deben estar en el mismo directorio
Servidor de actualizaciones propio y aplicación
- El servidor web usado en
QueryUrlyMetaUrldebe servir archivos JSON - En una configuración simple, basta con un único
live.json- El objeto
.minor.candidates[0].imagedebe ser igual a/lib/steamos-atomupd/manifest.jsondentro de la imagen update_pathes la ruta que el cliente de actualización agrega después deImagesUrlpara descargar el bundle
- El objeto
- El ejemplo de configuración de Caddy reescribe hacia
live.jsonlas solicitudes questeamos-atomupdenvía aQueryUrlyMetaUrl- Reescribe
/updatesa/live.json - Reescribe
/meta/*/*/*/*.jsony/meta/*/*/*/*/*.jsona/live.json - Usa
file_server browse
- Reescribe
- Las
QueryUrlyMetaUrlreales de SteamOS parecen tener más lógica, pero solo con esta configuraciónsteamos-atomupdya puede encontrar una actualización nueva - Hay lógica para evitar la actualización si la imagen ya anunciada es la que se está ejecutando actualmente
- Para actualizar una instalación existente de SteamOS a una imagen propia, basta con modificar
/etc/rauc/keyring.pemy/etc/steamos-atomupd/client.conf- No hace falta
steamos-readonly disable - Los cambios entran en el overlay de
/etc - Después de ejecutar
steamos-update, conviene considerar limpiar esos cambios desde/var/lib/overlays/etc/upper
- No hace falta
- Parece que también se podría instalar un SteamOS modificado editando una de las imágenes de recuperación de Valve y reemplazando el rootfs por una imagen propia, pero este método no fue probado
1 comentarios
Opiniones de Hacker News
Me gustan estos artículos sobre personalizar a fondo el software/OS de un dispositivo propio. También me alegra que en Steam Deck no haya que preocuparse por la tivoización.
La parte que me pareció más interesante del artículo fue la partición
/nix. No sabía que Steam Deck soportara nixpkgs; investigando un poco más, vi que, aunque no viene en la instalación por defecto, sí se puede poner en el dispositivo sin tener que bifurcar todo el OS.El repositorio de Nix puede estar en cualquier ubicación con permisos de escritura, y basta con cambiar
$PATHpara que apunte a un directorio de enlaces simbólicos.Es un artículo realmente minucioso e interesante. Personalmente, creo que jamás llegaría tan lejos.
Mi experiencia con Linux se limita a la época en que usaba una Raspberry Pi, y aun eso habrá sido como un 1%, así que el autor me parece admirable.
Algo parecido a https://github.com/kiler129/relax-intel-rmrr, aunque ese no es mi repositorio.
La causa de fondo solo se puede resolver con una actualización de ROM del fabricante, pero mi viejo DL360 ya no tiene soporte de HPE.
El parche en sí es un cambio de una sola línea, pero actualizar el kernel es engorroso. Hay que conseguir el SRPM; como no hay repositorio Git, hay que desempaquetar el SRPM, aplicar el parche y luego volver a compilar e instalar.
Ya existen distribuciones basadas en componentes de SteamOS y adaptadas para usarse en PC con controladores. ChimeraOS incluso incluye EmuDeck, una herramienta adicional para Steam Deck, y en mi entorno funciona bastante sin problemas.
Pedí una GPU para correr Steam Headless en un servidor NAS con unRaid usando una imagen Docker muy buena, y conectarme desde una laptop con Windows mediante un cliente como Moonlight.
Si funciona bien, es mucho mejor que comprar otra vez hardware de escritorio para juegos teniendo un NAS que está inactivo la mayor parte del tiempo. Eso sí, hay que mantener la configuración de energía de la tarjeta Nvidia en reposo cuando no se use. Espero que se pueda con una llamada a
nvidia-persistenced.1: https://github.com/Steam-Headless/docker-steam-headless
1: https://github.com/games-on-whales/gow
https://kubevirt.io/user-guide/virtual_machines/host-devices...
¡Ejecución de juegos declarativa y cloud native!
kubectl apply -f crysis.yamlHoy conocí RAUC (https://rauc.io/). Me preguntaba cómo había implementado Valve el esquema de actualizaciones A/B.
¿No extrañas un poco el favicon de lluvia de meteoros de Netscape?
Artículo interesante. Las actualizaciones A/B me parecen un poco excesivas. Si algo sale mal, puedes arrancar una distribución live o instalar un sistema de recuperación de una versión anterior en una partición separada.
En los últimos años usé NixOS y luego volví a Arch; antes de eso también había usado Arch durante mucho tiempo, y creo que las preocupaciones del autor no están bien encaminadas.
Arch es sin duda una distribución muy seria y madura, y me resulta más confiable que Valve.
Me pasé a Arch por la calidad de los paquetes. El repositorio principal se actualiza realmente rápido y en AUR hay muchos paquetes útiles.
Que el sistema se recupere automáticamente después de una actualización fallida es casi indispensable para un OS de bajo mantenimiento hoy en día.
En general, yo considero que la calidad de los paquetes de NixOS es alta.
Hace poco conseguí una Legion Go, un dispositivo portátil para gaming, y estoy metiéndome más en Linux. Antes lo evitaba porque parecía una pérdida de tiempo interminable en ajustes y parches, y además tenía compatibilidad limitada con las cosas que realmente quería usar.
Me dio curiosidad al leer sobre sistemas de archivos inmutables y sobre cómo el Linux tradicional les concede fácilmente permisos de root a todo tipo de software arbitrario.
Ahora estoy usando NixOS y, aunque sin duda puede convertirse en una pérdida de tiempo haciendo ajustes, es muy bueno para explorar. Permite probar fácilmente distintos componentes y, si decides no mantenerlos, puedes eliminarlos por completo salvo por cierta contaminación en
~/.config. Parchear antes de instalar también es algo trivial, así que es fácil agregar parches del kernel que permitan usar Linux en hardware peculiar, como dispositivos portátiles para gaming.Una comunidad de NixOS llamada Jovian está reconstruyendo los tarballs arbitrarios de SteamOS de Valve como commits etiquetados en GitHub, así que puedes revisar el código fuente como si fueras empleado de Valve. Con solo agregar unas líneas a la configuración de Nix, permiten instalar tu propia copia de SteamOS sobre NixOS.
Está claro que son expertos en Linux y, al ver el código fuente, se puede comprobar que reciben los paquetes de Valve prácticamente sin modificarlos, salvo por ajustes simples como detectar la ubicación del botón de encendido en vez de codificarla de forma fija.
Si quieres una experiencia SteamOS pura, pero no quieres operar tu propio mirror del sistema de actualizaciones de Valve, o si quieres explorar el código fuente de Valve sin descargar un tarball de 3 GB, vale la pena probar Jovian.
Guía de instalación: https://jovian-experiments.github.io/Jovian-NixOS/getting-st...
Mirror del código fuente de Valve: https://github.com/orgs/Jovian-Experiments/repositories?type...
bazzite.gg también hace esto muy bien. En hardware AMD, 120Hz VRR funcionó de inmediato, y el soporte de HDR también se puede probar en alfa.
“Bazzite es una imagen OCI que puede usarse como sistema operativo alternativo para Steam Deck, y es un entorno similar a SteamOS listo para jugar, para computadoras de escritorio, PC de home theater para la sala y varios PC portátiles”.
https://github.com/ublue-os/bazzite/
Aunque no te interese, vale la pena leer el README. La lista de cosas incluidas es enorme, y muchas parecen bastante geniales y útiles, especialmente para gamers o streamers.
No he investigado lo suficiente como para explicarlo de forma concisa y perfecta en un comentario de HN, pero la idea central es tener en la raíz una distribución Linux verificada y de solo lectura, y encima apilar paquetes en capas. Es una estructura muy inspirada en los contenedores del lado servidor.
Busca ser más seguro, más confiable, reproducible y más fácil de personalizar que el Linux tradicional. Si anotas los paquetes que quieres en un manifiesto de contenedor, cuando sale una actualización la ejecuta y luego reinstala esos paquetes encima.
https://universal-blue.org/guide/fork-your-own/
Y como es un OS inmutable, si algo sale mal también puedes volver a una imagen anterior.
La mayor parte fue en Steam Deck o corriendo Bazzite en una máquina virtual con passthrough de GPU, y está realmente muy bien hecho.
¿PC para la sala? ¿Ya casi no se usan expresiones como HTPC o “centro multimedia”?