Shopping cart

Subtotal $0.00

View cartCheckout

Building better devs

TnewsTnews
Programação

CPU com Amnésia: Como o Apple M4 Quebra o Linux Ao Dormir

Email : 12

Imagine que você está debugando um crash no kernel do Linux. Tudo funciona com um core. Você habilita os cores secundários e o sistema explode. Sem stack trace útil, sem mensagem de erro clara, só um crash misterioso durante a inicialização do interrupt controller. Bem-vindo ao pesadelo que os desenvolvedores do Asahi Linux enfrentaram ao portar Linux para o chip M4 da Apple.

O problema? A CPU literalmente esquece tudo quando recebe uma instrução para dormir. E isso viola uma das garantias mais básicas da arquitetura ARM64.

O que é a instrução WFI (e por que ela importa)

Antes de entrar no bug, precisa entender o que WFI faz. WFI significa “Wait For Interrupt”, uma instrução da arquitetura ARM que diz ao processador: “não tem nada pra fazer agora, entra em modo de baixo consumo até chegar uma interrupção”.

É uma instrução fundamental. Toda vez que seu computador fica idle (sem processar nada), o kernel manda um WFI para economizar energia. No seu Mac, isso acontece milhares de vezes por segundo. No seu celular Android, idem.

A especificação ARM64 é cristalina sobre uma regra: WFI não pode causar perda de estado arquitetural. Traduzindo: quando a CPU acorda, todos os registradores precisam estar exatamente como estavam antes de dormir. É tipo salvar o jogo antes de pausar. Quando volta, tudo precisa estar no lugar.

Essa garantia existe desde as primeiras versões do ARM. Sem ela, nenhum sistema operacional consegue funcionar de forma confiável, porque o scheduler depende de que o estado do processador sobreviva aos períodos de idle.

// Pseudo-código simplificado do kernel Linux
void cpu_idle_loop() {
    while (1) {
        if (!need_resched()) {
            // "Dorme até chegar interrupção"
            asm volatile("wfi");
            // Ao acordar, TODOS os registradores devem estar intactos
        }
        schedule();  // Troca de contexto normal
    }
}

O M4 decidiu ignorar as regras

Os chips M1, M2 e M3 da Apple também tinham um comportamento peculiar com WFI. O processador podia, internamente, descartar o estado dos registradores para atingir estados de sleep mais profundos. Mas existia um mecanismo de controle: um “chicken bit” (sim, esse é o nome técnico) que os desenvolvedores do Asahi Linux configuravam via m1n1 para desabilitar esse comportamento.

O m1n1 é o bootloader criado pelo projeto Asahi Linux que funciona como uma ponte entre o sistema de boot da Apple e o ecossistema Linux. Ele roda antes de qualquer outro software e configura o hardware para que o kernel Linux consiga usar os recursos do chip Apple Silicon. Se você já se interessou por como a Apple projeta seus processadores, vale conferir a engenharia reversa do Apple Neural Engine que publicamos recentemente.

No M1 até o M3, o fluxo era:

  1. m1n1 inicializa
  2. Configura o chicken bit para desabilitar o comportamento de perda de estado no WFI
  3. Linux assume e usa WFI normalmente
  4. Mais tarde, o kernel Asahi re-habilitava o comportamento quando queria explorar deep sleep states

No M4, a Apple trancou a porta. O chicken bit foi removido ou está locked, impossível de modificar. E o comportamento padrão agora é: WFI zera todos os registradores x0 a x31. Trinta e dois registradores de 64 bits, simplesmente apagados. Como se alguém formatasse sua memória RAM toda vez que a tela desligasse.

A caçada ao bug

Yureka Lilian, uma das desenvolvedoras do Asahi Linux, documentou a jornada de debugging em um post técnico que rapidamente viralizou no Hacker News. O processo foi um exercício de paciência e eliminação sistemática.

Os primeiros obstáculos apareceram antes mesmo de chegar ao bug do WFI. O M4 veio com novas proteções:

GXF (Guarded Exception Levels): um mecanismo de segurança da Apple que restringe o que pode ser executado em cada nível de exceção. Precisou ser desabilitado.

RVBAR (Reset Vector Base Address Register): o registrador que define onde a CPU começa a executar código após um reset. No M4, as escritas nesse registrador estão bloqueadas, exigindo uma abordagem diferente para configurar os cores secundários.

Tabelas de página do MMU: o kernel não estava expondo o espaço de endereços MMIO (Memory-Mapped I/O), o que quebrava a saída do console serial. Sem console serial, debugar é como navegar no escuro.

Depois de resolver esses problemas iniciais, o sistema bootava com um core. Mas ao habilitar os cores secundários para SMP (Symmetric Multiprocessing), vinha o crash misterioso durante a inicialização do GIC (Generic Interrupt Controller).

# O crash acontecia aqui, ao tentar configurar interrupts nos cores secundários
[    0.003421] GICv3: CPU1: found redistributor 1 region 0
[    0.003425] --- kernel panic ---

A investigação revelou que o crash ocorria logo após uma instrução WFI executada durante o processo de spin-up dos cores. Os registradores que deviam conter ponteiros para estruturas do kernel estavam todos zerados.

A prova de conceito: trocando WFI por NOP

Para confirmar a hipótese, a equipe fez algo drástico: substituiu todas as instruções WFI e WFIT no kernel por NOP (No Operation, instrução que não faz nada). Um NOP gasta ciclos de CPU sem fazer nenhum trabalho útil, mas também não destrói o estado dos registradores.

Resultado: Linux bootou no M4 com todos os cores ativos. Sem crashes, sem pânicos do kernel. A confirmação de que o WFI era o vilão.

Mas trocar WFI por NOP não é uma solução aceitável para produção. WFI é o que permite o processador economizar energia quando está idle. Sem ele, todos os cores ficam em busy-wait, consumindo energia máxima o tempo todo. Seu MacBook viraria uma torradeira.

A solução que foi pro mainline Linux

Will Deacon, um dos mantenedores da árvore ARM64 no kernel Linux, propôs a solução que acabou sendo adotada. Em vez de hackear as instruções diretamente, a abordagem foi criar um novo boot argument (parâmetro de inicialização) que desabilita o uso de WFI para idle.

ComponenteAção
m1n1 (bootloader)Detecta que está rodando em bare-metal num chip M4/M4 Pro/M4 Max/M5
m1n1Adiciona o bootarg para desabilitar WFI idle
Linux kernelLê o bootarg e substitui internamente as chamadas WFI por alternativas seguras
ResultadoSistema estável com todos os cores, sem perda de energia catastrófica

A solução foi mergeada tanto no mainline Linux quanto no m1n1. Qualquer pessoa que compilar as versões mais recentes consegue bootar Linux nativamente em Macs com M4.

# O bootarg adicionado pelo m1n1 automaticamente
arm64.nowfi=1

# No kernel, o idle loop passa a usar polling em vez de WFI
# Consome um pouco mais de energia, mas mantém o estado intacto

Uma observação importante: esse workaround não é necessário em máquinas virtuais. Quando Linux roda dentro de uma VM no M4 (via Virtualization.framework da Apple, por exemplo), o hypervisor já lida com o WFI de forma diferente. O m1n1 só adiciona o bootarg em boot bare-metal.

Por que a Apple fez isso?

Essa é a pergunta que todo mundo faz, e a resposta honesta é: não sabemos com certeza. A Apple não documenta publicamente os detalhes de implementação dos seus chips e não contribui código para o projeto Asahi Linux.

Algumas hipóteses levantadas pela comunidade:

Eficiência energética agressiva. A Apple pode ter decidido que zerar registradores permite ao silício atingir estados de sleep mais profundos, economizando mais bateria. O macOS provavelmente salva e restaura o estado dos registradores em software antes/depois do WFI, algo que o kernel de Cupertino sabe fazer mas que não é obrigação de nenhum kernel de terceiros.

Simplificação do design do chip. Manter o estado dos registradores durante WFI exige circuitos de retenção de estado (state retention logic) que ocupam espaço no die e consomem leakage power mesmo dormindo. Eliminar isso simplifica o design.

Não é um bug, é uma feature (para a Apple). Do ponto de vista do XNU (o kernel do macOS), o comportamento é intencional e totalmente suportado. O “bug” só existe na perspectiva de quem espera compliance total com a especificação ARM64. A Apple licencia a arquitetura ARM, mas fabrica seus próprios cores com design customizado.

O que isso significa para a arquitetura ARM

Esse caso levanta uma questão maior sobre o ecossistema ARM. Diferente do x86, onde Intel e AMD fabricam processadores que seguem (em geral) a mesma ISA, no mundo ARM cada fabricante tem liberdade para implementar seus próprios cores com variações.

A Qualcomm faz isso com os Oryon. A Apple com os cores da família Avalanche/Blizzard. Samsung com Mongoose (antes de desistir). E cada um pode ter suas próprias peculiaridades.

O kernel Linux já tem um sistema robusto para lidar com isso: as ARM64 errata. É basicamente uma lista de “bugs conhecidos por chip” que o kernel consulta durante o boot para aplicar workarounds específicos. O bug do WFI no M4 foi adicionado a essa lista.

// Exemplo simplificado de como errata são declaradas no kernel
// arch/arm64/kernel/cpu_errata.c

static const struct arm64_cpu_capabilities arm64_errata[] = {
    {
        .desc = "Apple M4 WFI state loss",
        .capability = ARM64_WORKAROUND_APPLE_WFI,
        .matches = is_apple_m4_or_later,
    },
    // ... centenas de outras errata para vários chips
};

A lista de errata no kernel Linux é enorme. Cortex-A53, Cortex-A57, Neoverse, cada um tem seus quirks. O M4 só adicionou mais um à coleção.

Asahi Linux: o estado atual do suporte ao M4

O projeto Asahi Linux vem progredindo de forma impressionante. O relatório de progresso do Linux 7.2 (publicado em agosto de 2026) mostrou avanços significativos:

FeatureM1/M2M3M4
Boot com todos os coresSimSimSim (com workaround)
GPU aceleradaSimEm progressoPlanejado
Wi-FiSimSimEm progresso
ThunderboltSimSimEm progresso
WebcamSimSimPlanejado
ÁudioSimSimEm progresso

O suporte ao M3 está quase pronto para release, com webcam, áudio e Thunderbolt funcionando. M4 e M5 estão no pipeline, e a correção do WFI foi um dos grandes bloqueios que agora está resolvido.

Para quem quer experimentar, o Asahi Linux ainda recomenda Macs com M1 ou M2 para uso diário. Mas a base está sendo construída para que M4 seja totalmente suportável no futuro próximo. E se a ideia de rodar Linux em hardware Apple te anima, a migração da França para Linux mostra que o mundo está cada vez mais aberto a alternativas.

Chicken bits: a engenharia por trás do nome ridículo

Antes de encerrar, vale uma curiosidade técnica. O termo “chicken bit” é usado de verdade na indústria de semicondutores. São bits de configuração em registradores internos do processador que servem para desabilitar features novas ou experimentais. O nome vem de “chicken switch”, tipo “botão de covarde”, porque serve para voltar ao comportamento seguro quando uma feature nova dá problema.

A Intel usa chicken bits extensivamente. A AMD também. No caso da Apple, os chicken bits controlam comportamentos específicos dos cores customizados, e são documentados apenas internamente.

No M1 ao M3, o chicken bit SYS_APL_IPI_CR_EL1 (entre outros) controlava o comportamento do WFI. No M4, esse registrador foi locked, impossível de escrever. Uma decisão de engenharia que provavelmente faz sentido para a Apple, mas que forçou a comunidade Linux a encontrar outro caminho.

Lições para quem trabalha com sistemas embarcados

Se você desenvolve para ARM (embedded, IoT, ou até cloud com Graviton da AWS), esse caso é um lembrete importante:

  • Nunca assuma que a especificação está 100% implementada. Leia as errata do seu chip. Sempre.
  • Teste com múltiplos cores desde o início. Muitos bugs só aparecem em SMP.
  • Console serial é seu melhor amigo. Sem saída de debug, você está às cegas.
  • Chicken bits existem por um motivo. Se a documentação do seu SoC menciona, saiba o que cada um faz.

O trabalho do Asahi Linux é open source. Todo o código, incluindo o workaround do WFI, está disponível no GitHub do projeto m1n1. Se você tem curiosidade sobre como funciona o boot em Apple Silicon ou quer contribuir, é um ótimo ponto de partida.

Aquele M4 dentro do seu MacBook Pro pode ser o chip mais rápido em single-thread do mercado. Mas quando o Linux manda ele dormir, o processador acorda sem lembrar quem é. E por enquanto, a solução é simplesmente não deixar ele dormir.


Fonte de inspiração: The Forgetful CPU (Linux on M4), por Yureka Lilian

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts