- O SteamOS 3 “Holo” é uma distribuição baseada em Arch para o Steam Deck, mas, para corrigir o problema de retorno da suspensão em um PC de sala de estar, foi necessário reverter um commit do kernel e fazer um fork direto da imagem rootfs
- A estrutura de atualização usa um esquema A/B: instala um novo rootfs somente leitura na partição inativa e reinicia; o
/etcpreserva alterações via overlayfs - O fluxo dos patches de kernel da Valve consiste em clonar um repositório Git bare a partir de um tarball de código-fonte, como
linux-neptune-61-6.1.52.valve9-1.src.tar.gz, no espelho de fontes do pacman, e compilar o pacote com tags próprias e PKGBUILD - O reempacotamento do rootfs envolve extrair
rootfs.img.caibxdo bundle RAUC do SteamOS, transformá-lo em imagem, alterar o UUID do Btrfs, substituir pacotes, mudar obuildid, trocar as URLs de atualização e o certificado RAUC, e empacotar tudo novamente como um RAUC bundle - Com um servidor web próprio fornecendo
live.jsone alterandoQueryUrl,ImagesUrleMetaUrldosteamos-atomupd, uma instalação existente do SteamOS também pode ser atualizada para uma imagem própria
Por que fazer um fork do SteamOS para um PC de sala de estar
- O SteamOS 3 “Holo” é uma distribuição Linux baseada em Arch da Valve Software para o Steam Deck, seu PC portátil para jogos
- O método de atualização usa uma estrutura de atualização atômica A/B, baixando um novo rootfs somente leitura para a partição inativa e reiniciando nela
- O usuário pode executar
steamos-devmodepara desbloquear o rootfs e normalizar o banco de dados do pacman, passando a tratá-lo como uma distribuição Linux comum - O objetivo era criar um fork de verdade, capaz de modificar a própria imagem rootfs, em vez de simplesmente contornar o sistema com
steamos-devmode - Em um PC de sala de estar, o SteamOS funcionava quase totalmente, mas falhava apenas no retorno da suspensão
- Outras distribuições no mesmo computador, usando kernels mainline ou stable, conseguiam retornar da suspensão
- Depois de encontrar o código-fonte do kernel da Valve e executar
git bisect, um commit que aparentemente corrigia o retorno da suspensão no hardware do Steam Deck causava o problema nesse PC - A necessidade de reverter esse commit e compilar o kernel manualmente foi o motivo direto de todo o trabalho
- Havia também a opção de usar Arch ou outra distribuição diretamente, mas, se fosse necessário ajustar uma distribuição Linux para rodar jogos, a preferência era aproveitar o conjunto de pacotes testado pela Valve
Partições e estrutura de atualização do SteamOS
- O sistema SteamOS usa 8 partições
- A EFI system partition contém o bootloader de estágio 1 e metadados para selecionar o conjunto de partições A/B
- Cada conjunto A/B contém o GRUB, que é o bootloader de estágio 2, o root filesystem e uma partição
/var - O restante do espaço em disco é preenchido por uma única partição
home
- Durante a inicialização, vários pseudo-filesystems são montados adicionalmente
- Quase uma dúzia de diretórios, como
/var/log,/roote/nix, são montados via bind mount a partir de/home/.steamos/offloadpara persistir dados
- Quase uma dúzia de diretórios, como
- O
/etcé tratado com overlayfs- As alterações são armazenadas em
/var/lib/overlays/etc/upper - Itens que normalmente precisam permanecer em
/etc, comomachine-ide conexões do NetworkManager, são preservados - Arquivos de configuração não modificados podem ser atualizados
- Esse método lida ao mesmo tempo com preservação e atualização de arquivos de configuração na estrutura de partições A/B, sem lógica de gerenciador de pacotes
- As alterações são armazenadas em
- A atualização do sistema começa quando o cliente Steam, ou um usuário no terminal, executa
steamos-update- Esse comando executa o programa Python
steamos-atomupd-client - O cliente envia as informações do SO atual e a configuração de canal de atualização do usuário para a URL em
/etc/steamos-atomupd/client.conf, verificando se há uma nova atualização
- Esse comando executa o programa Python
- Se houver uma nova atualização, o servidor responde com o caminho de um RAUC bundle
- O cliente baixa o bundle e executa
rauc install - O RAUC verifica a assinatura do bundle e procura
rootfs.img.caibx - Com
casync extract, ele baixa os fragmentos da nova imagem e os grava na partição rootfs inativa - O script post-install sincroniza seletivamente dados do
/varativo para o/varinativo e altera a configuração do bootloader de estágio 1 na EFI system partition para inicializar pelo novo conjunto de partições
- O cliente baixa o bundle e executa
Criando pacotes a partir do código-fonte do kernel da Valve
- A Valve usa no SteamOS um kernel Linux bastante modificado, e o código-fonte está disponível para download
- O código-fonte da imagem atual do SteamOS pode ser encontrado em
sources/holo-3.5esources/jupiter-3.5no espelho pacman da Valve - No momento da escrita, o kernel da imagem stable era
6.1.52-valve9-1-neptune-61, e o tarball de código-fonte correspondente tinha 2,9 GiB - O tarball é grande porque inclui toda a árvore Git do Linux
- Dentro dele há
PKGBUILD,config,config-neptune,archlinux-linux-neptune/e outros arquivos archlinux-linux-neptune/não é uma working tree comum pronta para uso, mas um repositório bare
- Dentro dele há
- O PKGBUILD aponta como fonte para um repositório GitLab privado no formato
git+ssh://git@gitlab.steamos.cloud/jupiter/linux-integration.git#tag=$_tag- Não é possível cloná-lo diretamente nem criar links para commits
- A partir das fontes do
makepkg, é possível obter um snapshot contendo todo o histórico de commits de cada tag - Graças a essa estrutura, foi possível fazer bisect do commit que quebrava a suspensão do PC de sala de estar
- O fluxo de trabalho consiste em clonar o repositório bare para uma working tree comum e manter branches e tags próprios
- O exemplo cria
my-brancha partir da tag6.1.52-valve9 - As alterações próprias são enviadas para um host Git separado, e a fonte do PKGBUILD é alterada para esse repositório e para uma tag própria
- Há um repositório de exemplo em linux
- O exemplo cria
- É possível criar os pacotes do kernel com
makepkgmakepkg MAKEFLAGS=-j$(nproc)ou atualizar/etc/makepkg.confé útil quando não se está em uma VM pequena- Dentro do escopo analisado, os pacotes específicos do SteamOS também usavam uma estrutura semelhante, com um repositório Git como primeira fonte
- Para facilitar as etapas seguintes, foi configurado um repositório pacman próprio
- Coloque os pacotes em um diretório, execute
repo-add $REPO_NAME.db.tar.zst [PACKAGES...]e faça upload para um host web - Esse repo também ajuda as ferramentas a funcionarem corretamente caso
steamos-devmodeseja executado depois
- Coloque os pacotes em um diretório, execute
Obtendo e montando o root filesystem
- Como os scripts de release engineering não foram encontrados, a opção foi reempacotar o root filesystem existente conforme necessário
- O script sem explicações nem comentários está em fauxlo
- A forma comum de obter a imagem rootfs do SteamOS é comprar um Steam Deck ou baixar a imagem de recuperação do Steam Deck, mas ambas exigem concordar com o Steam End User License Agreement
- A versão atual do release pode ser verificada em um snapshot JSON que parece ser a URL de fallback do sistema de atualização
- No momento da escrita, a versão stable era
20231122.1 - Também há um snapshot JSON separado para o canal preview
- No momento da escrita, a versão stable era
- O download do rootfs segue a mesma sequência do
steamos-atomupd-client- Baixa-se o arquivo
.raucb, que é um RAUC bundle - Extrai-se
rootfs.img.caibxdo bundle, que é um filesystem SquashFS - Com
casync extract, os fragmentos são baixados do store.castrpara gerarrootfs.img - A URL do store
.castré a URL do RAUC bundle com.raucbtrocado por.castr - Esse comportamento está hardcoded no
steamos-atomupd - O script de automação está em fetch-current.sh
- Baixa-se o arquivo
- Os arquivos
.img.zipe.img.zstadjacentes não são rootfs, mas imagens de recuperação inicializáveis separadas- Também é possível extrair a partição rootfs da imagem de recuperação e usá-la na etapa seguinte
- Porém, ela não era idêntica bit a bit à imagem recebida via RAUC e casync, e, ao criar novamente o update bundle, essas ferramentas seriam necessárias de qualquer forma
- Antes de modificar o rootfs, é preciso mudar o UUID do filesystem
- Ao atualizar de uma imagem SteamOS existente para uma imagem customizada, se o UUID não for alterado, dois filesystems diferentes terão o mesmo UUID
- Esse estado pode causar problemas
- Um exemplo é
btrfstune -fu rootfs.img
- A Valve usa uma imagem Btrfs com compressão zstd
- Para manter a compressão durante as alterações, monte com
mount -o compress=zstd rootfs.img rootfs - Como o SteamOS usa a propriedade de subvolume
readonlydo Btrfs, desative-a combtrfs property set -ts rootfs ro false
- Para manter a compressão durante as alterações, monte com
- Modificar pacotes como o kernel Linux pode acionar scripts que exigem
/deve/proc- Monte
devtmpfseprocabaixo do rootfs - Monte tmpfs em
/tmp,/run,/vare/homepara evitar gravações nos diretórios que serão montados no sistema inicializado - Faça bind mount do
/etc/resolv.confdo host para que a resolução de nomes funcione no chroot
- Monte
Substituição de pacotes e alteração de metadados da imagem
- O repositório próprio é adicionado como o primeiro item de repo em
/etc/pacman.conf- Assim, mesmo que o repo da Valve tenha uma versão mais recente do pacote, o pacote próprio tem prioridade
- Depois, mesmo ao executar
steamos-devmode, será possível reinstalar o pacote próprio
- O stanza de repo de exemplo usa
[fauxlo],Server = https://fauxlo.ili.fyi/pacman/$archeSigLevel = NeverSigLevel = Neverpermite pacotes sem assinatura- Para instalar pacotes com assinatura GPG, é preciso preencher o pacman keyring
- Em vez de mexer no keyring vazio em
/etc/pacman.d/gnupg, foi usado um novo keyring preenchido sobre tmpfs
- A instalação do pacote é feita no formato
pacman --sysroot rootfs --noconfirm -Sy linux-neptune-61- No script real, evita-se
-ye apenas o banco de dados do repo próprio é sincronizado por trás do pacman - Isso permite manter o estado dos outros repositórios fixo no momento em que a imagem original foi criada
- É uma escolha para reduzir as alterações exibidas no diff da imagem
- No script real, evita-se
- O
steamos-atomupdlê a versão e o build ID da imagem atual em/lib/steamos-atomupd/manifest.json; se não existir, usa/etc/os-release- Se o build ID da atualização fornecida pelo servidor for igual ao da imagem atual, a atualização é recusada
- Isso também é útil para identificar qual imagem está em execução
- O build ID deve obrigatoriamente seguir o formato
YYYYMMDD.N- Se o formato não corresponder, o
steamos-atomupdencerra com um traceback do Python - Para evitar incrementos manuais, é possível colocar
HHMMSSou um Unix timestamp emN - Altere tanto o
buildidemmanifest.jsonquanto oBUILD_IDemos-release - O trecho de script Bash para isso está em repack.sh
- Se o formato não corresponder, o
- O RAUC usa certificados X.509 para configuração de confiança
- O certificado confiável fica em
/etc/rauc/keyring.pem - Um simples certificado self-signed é suficiente
- Instale o novo certificado em
rootfs/etc/rauc/keyring.pem
- O certificado confiável fica em
- As URLs em
rootfs/etc/steamos-atomupd/client.conftambém são alteradas para o servidor próprioQueryUrlImagesUrlMetaUrl
- Outras alterações também são possíveis, desde que não ultrapassem o espaço da imagem Btrfs de 5 GiB
- Por exemplo, se quiser encontrar um dispositivo SteamOS na rede como
hostname.local, é possível removerrootfs/usr/lib/systemd/resolved.conf.d/00-disable-mdns.conf - Também seria possível sobrescrever isso pela configuração de overlay do
/etc, mas foi considerado trabalhoso
- Por exemplo, se quiser encontrar um dispositivo SteamOS na rede como
- A regra é não colocar no rootfs alterações que possam ser feitas facilmente sem imagem
- É possível instalar o Firefox no rootfs
- Mas seria necessário reempacotar a imagem a cada atualização de segurança do Firefox
Desmontando o rootfs e criando o RAUC bundle
- Ao terminar as modificações, marque novamente o filesystem como read-only
btrfs property set -ts rootfs ro true
- Descarte blocos não usados com
fstrim -v rootfs - Para desmontar,
umount --recursive rootfsé útil- Ele também lida com os pseudo-filesystems montados anteriormente
- Antes de criar o RAUC bundle, gere o casync store e o blob index
- Um exemplo é
casync make --store=rootfs.img.castr bundle/rootfs.img.caibx rootfs.img
- Um exemplo é
- O RAUC bundle precisa de três arquivos
manifest.raucmrootfs.img.caibxUUID, contendo o UUID do filesystem
- O
manifest.raucmcontém as informações da atualização e da imagem rootfscompatible=steamos-amd64version=$versionsha256sizefilename=rootfs.img.caibx
- O arquivo
UUIDé criado comblkid -s UUID -o value rootfs.img >bundle/UUID - Depois de preparar os três arquivos, execute
rauc bundle- Especifique o certificado e a chave em
--signing-keyring,--certe--key - O resultado é
rootfs.img.raucb
- Especifique o certificado e a chave em
rootfs.img.raucberootfs.img.caibxsão enviados para o servidor web apontado porImagesUrlemclient.conf- Os dois arquivos devem ficar no mesmo diretório
Servidor de atualização próprio e aplicação
- O servidor web usado por
QueryUrleMetaUrlprecisa fornecer arquivos JSON - Em uma configuração simples, um único
live.jsoné suficiente- O objeto
.minor.candidates[0].imagedeve ser igual ao/lib/steamos-atomupd/manifest.jsondentro da imagem update_pathé o caminho que o cliente de atualização anexa aImagesUrlpara baixar o bundle
- O objeto
- O exemplo de configuração do Caddy reescreve para
live.jsonas solicitações que osteamos-atomupdenvia paraQueryUrleMetaUrl- Reescreve
/updatespara/live.json - Reescreve
/meta/*/*/*/*.jsone/meta/*/*/*/*/*.jsonpara/live.json - Usa
file_server browse
- Reescreve
- As URLs reais de
QueryUrleMetaUrldo SteamOS parecem ter mais lógica, mas essa configuração já permite que osteamos-atomupdencontre novas atualizações - Há uma lógica para evitar atualização se a imagem já anunciada estiver em execução no momento
- Para atualizar uma instalação SteamOS existente para uma imagem própria, basta modificar
/etc/rauc/keyring.peme/etc/steamos-atomupd/client.confsteamos-readonly disablenão é necessário- As alterações entram no overlay de
/etc - Depois de executar
steamos-update, considere limpar essas alterações em/var/lib/overlays/etc/upper
- Parece possível também modificar uma das imagens de recuperação da Valve e substituir o rootfs pela imagem própria para instalar um SteamOS modificado, mas esse método não foi testado
1 comentários
Opiniões no Hacker News
Gosto desse tipo de texto sobre customizar profundamente o software/OS de um dispositivo que possuo. Também é bom saber que, no Steam Deck, não é preciso se preocupar com Tivoization.
A parte mais interessante do texto para mim foi a partição
/nix. Eu não sabia que o Steam Deck tinha suporte a nixpkgs; pesquisando mais, vi que, embora não venha na instalação padrão, dá para colocá-lo no dispositivo sem fazer um fork do OS inteiro.O repositório do Nix pode ficar em qualquer local gravável, e basta mudar o
$PATHpara apontar para um diretório de links simbólicos.É um texto realmente minucioso e interessante. Pessoalmente, acho que eu jamais iria tão longe.
Minha experiência mexendo com Linux se resume à época em que usava Raspberry Pi, e mesmo assim talvez 1%, então o autor me parece impressionante.
Algo parecido com https://github.com/kiler129/relax-intel-rmrr, mas esse não é o meu repositório.
A causa raiz só poderia ser resolvida com uma atualização de ROM do fabricante, mas meu DL360 antigo já não tem mais suporte da HPE.
O patch em si é uma alteração de uma linha, mas atualizar o kernel é trabalhoso. É preciso baixar o SRPM e, como não há repositório Git, desempacotar o SRPM, aplicar o patch, depois compilar e instalar de novo.
Já existem distribuições baseadas em elementos do SteamOS e ajustadas para uso com PC e controle. O ChimeraOS inclui até o EmuDeck, uma ferramenta complementar para Steam Deck, e funciona bem sem grandes problemas no meu ambiente.
Encomendei uma GPU para rodar o Steam Headless no meu servidor NAS unRaid como uma bela imagem Docker e acessar pelo notebook Windows com um cliente como o Moonlight.
Se funcionar bem, é muito melhor do que comprar mais hardware de desktop gamer enquanto o NAS fica ocioso na maior parte do tempo. Só preciso manter as configurações de energia da placa Nvidia em modo ocioso quando ela não estiver em uso. Espero que isso seja possível chamando
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...
Execução declarativa de jogos cloud-native!
kubectl apply -f crysis.yamlHoje conheci o RAUC (https://rauc.io/). Eu tinha curiosidade sobre como a Valve implementou o esquema de atualizações A/B.
Vocês também não sentem um pouco de falta do favicon de chuva de meteoros do Netscape?
Texto interessante. O upgrade A/B parece um pouco exagerado. Se der problema, dá para iniciar uma distribuição live ou instalar em uma partição separada um sistema de recuperação de uma versão anterior.
Nos últimos anos usei NixOS e depois voltei para o Arch; antes disso, também usei Arch por muito tempo, e acho que as preocupações do autor não se confirmam.
O Arch é definitivamente uma distribuição muito séria e madura, e é mais confiável que a Valve.
O motivo de eu ter migrado foi a qualidade dos pacotes. O repositório principal é atualizado muito rapidamente, e o AUR tem muitos pacotes úteis.
Um sistema que se recupera automaticamente após uma falha de upgrade é praticamente essencial em um OS de baixa manutenção hoje em dia.
Em geral, eu considero a qualidade dos pacotes do NixOS alta.
Recentemente consegui um Legion Go, um portátil para jogos, e tenho tido mais contato com Linux. Antes eu evitava porque parecia uma perda de tempo infinita com ajustes, e a compatibilidade com as coisas que eu realmente queria usar também era limitada
Fiquei curioso ao ler sobre sistemas de arquivos imutáveis e sobre como o Linux tradicional entrega facilmente permissões de root a todo tipo de software arbitrário
Agora estou usando NixOS e, de fato, pode virar perda de tempo com ajustes, mas é ótimo para exploração. Dá para testar vários componentes com facilidade e, se eu decidir não mantê-los, removê-los completamente, exceto por alguma contaminação em
~/.config. Aplicar patches antes da instalação também é algo trivial, então é fácil adicionar patches de kernel que permitem usar Linux em hardwares peculiares, como portáteis para jogosUma comunidade NixOS chamada Jovian está reconstruindo os tarballs arbitrários do SteamOS da Valve como commits com tags no GitHub, então dá para navegar pelo código-fonte como um funcionário da Valve. Com algumas linhas na configuração do Nix, eles permitem instalar sua própria cópia do SteamOS sobre o NixOS
Eles claramente são especialistas em Linux, e olhando o código dá para ver que recebem os pacotes da Valve sem modificações, exceto por ajustes simples, como detectar a posição do botão de energia em vez de codificá-la de forma fixa
Se você quer uma experiência SteamOS pura, mas não quer operar seu próprio mirror do sistema de atualizações da Valve, ou quer explorar o código-fonte da Valve sem baixar um tarball de 3 GB, vale experimentar o Jovian
Guia de instalação: https://jovian-experiments.github.io/Jovian-NixOS/getting-st...
Mirror do código-fonte da Valve: https://github.com/orgs/Jovian-Experiments/repositories?type...
bazzite.gg também faz isso muito bem. Em hardware AMD, 120 Hz VRR funcionou de imediato, e o suporte a HDR também pode ser testado em alfa
“O Bazzite é uma imagem OCI que pode ser usada como sistema operacional alternativo para o Steam Deck, e oferece um ambiente semelhante ao SteamOS, pronto para jogos, para computadores desktop, PCs de home theater de sala e vários PCs portáteis”
https://github.com/ublue-os/bazzite/
Mesmo que você não tenha interesse, vale a pena olhar o README. A lista do que vem incluído é enorme, com muitos itens que parecem bem legais e úteis, especialmente para gamers ou streamers
Não me aprofundei a ponto de explicar isso de forma concisa e perfeita em um comentário do HN, mas a ideia central é ter uma distribuição Linux verificada e somente leitura na raiz e colocar pacotes em camadas por cima dela. É uma estrutura muito inspirada em contêineres do lado do servidor
O objetivo é ser mais seguro, mais confiável, reproduzível e mais fácil de customizar do que o Linux tradicional. Você coloca os pacotes desejados em um manifesto de contêiner e, quando sai uma atualização, ela é executada e depois os pacotes são instalados novamente por cima
https://universal-blue.org/guide/fork-your-own/
E, por ser um OS imutável, se algo der errado, você também pode fazer rollback para a imagem anterior
A maior parte foi no Steam Deck ou em uma máquina virtual rodando Bazzite com passagem direta de GPU, e ficou muito bem-feito
PC de sala; hoje em dia quase não se usa mais HTPC ou “media center”?