Reiniciando e Desligando (Reset e Estados de Energia do ACPI)
x86 não oferece uma única instrução para reiniciar ou desligar uma máquina, diferente de travar uma única CPU (hlt) ou disparar uma exceção, ambos com suporte direto e documentado em nível de instrução; um kernel deliberadamente reiniciando ou desligando o sistema inteiro em vez disso precisa passar por um de vários mecanismos indiretos, nenhum deles universalmente disponível em toda placa.
Reiniciando
Seção intitulada “Reiniciando”O mecanismo clássico reaproveita o controlador de teclado 8042, o mesmo chip que a linha A20 já cobre pulsando para um propósito não relacionado: escrever o byte de comando 0xFE na porta 0x64 pulsa a linha de reset do controlador, que a maioria dos chipsets conecta diretamente à própria entrada de reset da CPU.
; reset clássico via 8042in al, 0x64test al, 2 ; espera o buffer de entrada ficar livrejnz $-2mov al, 0xFEout 0x64, al ; pulsa a linha de resetUm caminho mais moderno e mais confiável passa pela tabela FADT do ACPI, que carrega um campo dedicado RESET_REG (um endereço genérico, comumente um registrador de I/O de porta ou mapeado em memória dependendo da plataforma) e um byte RESET_VALUE: escrever esse valor específico nesse registrador específico dispara uma sequência de reset definida pela plataforma que o firmware já validou para a placa exata em que está rodando, contornando a dependência do truque do controlador de teclado em hardware que alguns sistemas mais novos não conectam mais da mesma forma.
O triple fault como último recurso
Seção intitulada “O triple fault como último recurso”Causar deliberadamente um triple fault, uma exceção ocorrendo enquanto a CPU já está tentando tratar um double fault, força a maioria das implementações x86 a resetar como um failsafe em nível de hardware, sem instrução de reset explícita nem escrita de registrador alguma envolvida: carregar uma IDT deliberadamente inválida (limite zero) e depois executar qualquer instrução que levante uma interrupção é uma forma confiável de disparar um.
lidt [null_idtr] ; um descritor com limite = 0int 0x03 ; qualquer tentativa de interrupção agora falha, escalando para triple faultIsso é tratado como último recurso especificamente porque não é realmente um mecanismo de reset algum, apenas uma consequência bem conhecida de esgotar a própria maquinaria de tratamento de exceção da CPU; Emulating & Debugging já cobre a flag -no-reboot do QEMU em grande parte porque esse exato modo de falha, seja disparado deliberadamente ou por um bug real, é comum o suficiente durante o desenvolvimento de kernel para precisar de uma forma de congelá-lo em vez de assistir a máquina reiniciar silenciosamente.
Por que desligar é um problema diferente e mais difícil
Seção intitulada “Por que desligar é um problema diferente e mais difícil”Nenhum dos mecanismos acima de fato corta energia da máquina; um reset reinicia a execução do começo sem nunca remover energia, enquanto desligar de verdade exige cooperar com a própria lógica de gerenciamento de energia da plataforma para fazer isso com segurança. Em qualquer sistema capaz de ACPI, isso significa invocar o método _S5, definido em AML dentro da DSDT, que define os valores específicos que PM1a_CNT (e, onde presente, PM1b_CNT) precisam para de fato transicionar a plataforma para o estado de energia S5 (soft-off): diferente das tabelas de offset fixo que um kernel consegue analisar sem interpretador algum, os valores exatos de _S5 são específicos de placa e só descobríveis executando (ou, no mínimo, avaliando) o método AML relevante, exatamente o interpretador que o próprio artigo de ACPI já identifica como fora do escopo da maioria dos kernels hobbyist. Um kernel que não implementou um interpretador de AML fica sem forma limpa alguma de desligar: alguns simplesmente resetam e dependem do firmware ou do usuário para cortar energia manualmente, enquanto outros fixam no código a porta e o valor de PM1a_CNT para uma placa ou emulador específico já testado, uma abordagem frágil que só funciona no hardware para o qual nunca foi de fato pensada para generalizar.
Notas de implementação
Seção intitulada “Notas de implementação”O QEMU expõe um atalho conveniente ao redor desse problema inteiro para propósitos de desenvolvimento: escrever um valor específico na porta de I/O 0xF4 (o dispositivo “isa-debug-exit”, adicionado com -device isa-debug-exit,iobase=0xf4 e não presente por padrão) sai do emulador de forma limpa em vez de exigir uma sequência real de desligamento via ACPI, útil especificamente para testes automatizados onde um kernel precisa sinalizar “terminado” sem implementar desligamento real algum. Em hardware real, ou num emulador sem esse dispositivo de depuração habilitado, um kernel incapaz de invocar _S5 e sem vontade de deixar a máquina simplesmente girando tem essencialmente duas opções honestas: resetar via o registrador da FADT acima e deixar o usuário desligar manualmente, ou imprimir uma mensagem dizendo ao usuário que agora é seguro fazer isso, em vez de silenciosamente fingir desligar quando o mecanismo para de fato fazer isso não está implementado.
Referências
Seção intitulada “Referências”- ^ UEFI Forum, ACPI Specification, Capítulo 4 (registrador de reset da FADT) e Capítulo 7 (estados de energia do sistema, incluindo o estado soft-off S5 e o objeto
_S5).
Ver também
Seção intitulada “Ver também”- ACPI: o registrador de reset da FADT e a dependência de AML/
_S5da qual o caminho de desligamento deste artigo depende. - Emulating & Debugging: a flag
-no-rebootdo QEMU que existe especificamente para observar o momento em que um dos mecanismos deste artigo dispara. - A Linha A20: o outro propósito, não relacionado, para o qual o controlador de teclado 8042 que o truque de reset deste artigo também usa é pulsado.