paint-brush
Uma jornada pelos segredos do firmware: do BIOS/UEFI ao sistema operacionalpor@tristejoursoir
687 leituras
687 leituras

Uma jornada pelos segredos do firmware: do BIOS/UEFI ao sistema operacional

por Aleksandr Goncharov20m2024/08/22
Read on Terminal Reader

Muito longo; Para ler

Explore a evolução do BIOS tradicional para o firmware UEFI moderno, entenda como as sequências de inicialização são gerenciadas e descubra as funções dos serviços de inicialização e serviços de tempo de execução. Mergulhe nas complexidades dos carregadores de inicialização do SO e veja como o firmware agora oferece suporte a recursos e aplicativos avançados.
featured image - Uma jornada pelos segredos do firmware: do BIOS/UEFI ao sistema operacional
Aleksandr Goncharov HackerNoon profile picture
0-item
1-item


Você já se perguntou o que acontece no momento em que você aperta o botão de energia do seu computador? Por trás dessa breve pausa, antes que sua tela acenda, uma série complexa de processos está ocorrendo. Este artigo vai mergulhar no fascinante mundo do firmware , explorando como diferentes componentes interagem durante o processo de inicialização .


Ao entender essas conexões, você terá uma imagem mais clara dos elementos fundamentais que dão vida ao seu sistema. Nosso foco principal será a arquitetura Intel x86 , mas muitos princípios se aplicam a outras arquiteturas também.


Se você perdeu a primeira parte da nossa série, clique aqui para recuperar o atraso. Agora, vamos desvendar os mistérios por trás do firmware.

Índice:

  • Definições
  • Arquitetura geral do firmware
  • Carregador de inicialização de primeiro estágio (FSBL)
    • BIOS (fase POST)
    • Inicialização da plataforma UEFI (PI)
    • inicialização do núcleo
    • Outras soluções
  • Carregador de inicialização de segundo estágio (SSBL)
    • BIOS
    • UEFI
  • Carregador de inicialização do sistema operacional


Definições

  • Firmware : um tipo especializado de software incorporado ao hardware, que fornece controle de baixo nível e permite que o hardware funcione corretamente e interaja com outros componentes do sistema.


  • Basic Input/Output System (BIOS) : um firmware legado (originalmente criado para o IBM PC ) responsável pela inicialização do hardware após a inicialização da plataforma. Hoje em dia, é frequentemente vagamente chamado de conjunto completo de firmware.


  • Bootloader : um nome geral para firmware que é responsável por inicializar um computador. É usado como um conceito moderno no lugar do BIOS , frequentemente fornecendo uma estrutura com código bootstrap para inicializar o processador e o chipset, bem como interfaces para terceiros (por exemplo, desenvolvedores de placas-mãe) para executar inicialização específica da plataforma.


  • Payload : Um software a ser executado quando o bootloader sai. Pode ser um bootloader de segundo estágio, sistema operacional, aplicativo BIOS/UEFI, etc. Geralmente cuida do fluxo de bootstrapping de acordo com o design do firmware.


  • O uso dos termos BIOS e bootloader pode ser confuso, pois seus significados dependem do contexto. No entanto, quando alguém menciona firmware , BIOS ou bootloader , geralmente está se referindo ao conjunto completo de firmware em execução entre o sistema operacional e o hardware .


  • EFI vs. UEFI : A Extensible Firmware Interface (EFI) foi a especificação original desenvolvida pela Intel. A Unified Extensible Firmware Interface (UEFI) é a sucessora da EFI , criada pelo UEFI Forum para padronizar e estender a especificação original. Na maioria dos casos, EFI e UEFI são usados de forma intercambiável.

Arquitetura geral do firmware

Para entender como os componentes do firmware interagem, exploraremos toda a arquitetura com todas as suas partes conectadas. O fluxo de execução, mostrado no diagrama abaixo, começa a partir do vetor de reinicialização , que faz parte do First-Stage Bootloader . A partir daí, ele progride por vários estágios de firmware:



O firmware ou BIOS geralmente pode ser dividido em duas partes principais, com uma interface tipicamente mínima entre elas:


  1. Inicialização de hardware : responsável por inicializar os componentes de hardware do sistema.
  2. Interface para o sistema operacional e o usuário : fornece as interfaces necessárias para o sistema operacional e o usuário.


O design do firmware da plataforma pode ser monolítico , combinando inicialização de hardware e funcionalidade de boot, ou pode seguir um fluxo de boot modular e em estágios. A escolha do design depende dos requisitos do sistema e pode ser preferível para certos dispositivos.


O diagrama a seguir ilustra como diferentes componentes de firmware interagem e podem ser usados juntos para dar suporte ao processo de inicialização (as setas indicam a sequência de execução):



Se esses diagramas parecem complexos agora, não se preocupe. Revise-os novamente depois de ler este artigo, e eles ficarão mais claros.

Carregador de inicialização de primeiro estágio (FSBL)

Este pedaço de firmware é projetado para inicializar computadores e sistemas embarcados com foco na inicialização mínima de hardware : fazer apenas o que é absolutamente necessário e, em seguida, passar o controle para o Second-Stage Bootloader para inicializar o sistema operacional. O FSBL não carrega sistemas operacionais de mídia de armazenamento diferente do chip flash . Como ele inicializa apenas o hardware subjacente e não manipula mídia de inicialização como discos rígidos, SSDs ou unidades flash USB, outro pedaço de software é necessário para realmente inicializar um sistema operacional .


Principais responsabilidades da FSBL :


  1. CPU : Alternando do Modo Real de 16 bits para o Modo Protegido de 32 bits ( observação : ou no modo Virtual 8086 no caso do BIOS).
  2. Utilização de cache : Chamando FSP-T para configurar Cache-As-RAM para o ambiente C.
  3. Porta de depuração : Inicializar a porta de depuração configurada chamando métodos de inicialização específicos da placa.
  4. Inicialização de memória : invocar o FSP-M para inicializar a memória principal do sistema e salvar informações cruciais da memória do sistema.
  5. GPIO : Configurando pinos de entrada/saída de uso geral (GPIO) para interface com dispositivos externos.
  6. Silício : Executando a inicialização inicial da plataforma e usando FSP-S para concluir a inicialização do chipset, CPU e controlador de E/S.
  7. Enumeração PCI : enumeração de dispositivos PCI e alocação de recursos, como endereços de memória e IRQs.
  8. Preparação da carga útil : configuração de tabelas SMBIOS e ACPI , incluindo as informações de preparação (tabelas de coreboot, HOBs) necessárias para serem passadas para a carga útil.
  9. Carregamento e transferência : Carregamento e transferência de controle para a carga útil.

BIOS (fase POST)

Nos primórdios da computação, o software de código aberto não era muito popular, e a maioria das implementações de BIOS eram proprietárias. Existem apenas algumas soluções abertas disponíveis fornecendo código-fonte BIOS POST, como Super PC/Turbo XT BIOS e GLaBIOS . Esses projetos foram projetados para funcionar em sistemas IBM 5150/5155/5160 e na maioria dos clones XT.


No entanto, as implementações de BIOS de código aberto mais conhecidas, como OpenBIOS e SeaBIOS , não realizam inicialização de hardware porque não são destinadas a rodar em hardware puro. Mas são amplamente usadas como Second-Stage Bootloaders e rodam nativamente em ambientes virtuais como QEMU e Bochs.


Em todo caso, há pouca chance de que você precise trabalhar diretamente com esses BIOSes iniciais ou se aprofundar profundamente em suas especificidades. Mas se você estiver interessado em explorar, os repositórios mencionados são um bom ponto de partida.


No que diz respeito às tendências atuais de desenvolvimento, parece não haver desenvolvimento contínuo de soluções de BIOS proprietárias, e tais projetos se tornaram obsoletos diante de alternativas modernas.

Inicialização da plataforma UEFI (PI)

O processo de inicialização segue um fluxo em estágios, começando da esquerda e movendo-se para a direita na próxima figura. A linha do tempo do processo de inicialização da plataforma é dividida nas seguintes frases, conforme indicado pelas caixas amarelas:



  • Segurança (SEC) : A primeira fase após um vetor de reinicialização , sua função principal é configurar a RAM temporária (CPU Cache-As-RAM ou SRAM).
  • Inicialização Pré-EFI (PEI) : Esta fase despacha drivers especializados chamados Módulos de Inicialização Pré-EFI (PEIMs) . Esses módulos lidam com inicialização de hardware essencial, como configuração da CPU e chipset e configuração da memória principal (DRAM) .
  • Driver Execution Environment (DXE) : Nesta fase, o restante da inicialização do sistema é executado. A fase DXE fornece serviços UEFI e suporta vários protocolos e drivers necessários para a operação do sistema.
  • Seleção de dispositivo de inicialização (BDS) : esta fase implementa a política de inicialização da plataforma, determinando a sequência de inicialização e selecionando o dispositivo/carregador de inicialização apropriado.
  • Transient System Load (TSL) : Durante esta fase, o sistema executa aplicativos usando serviços UEFI para preparar o SO. Inclui a transição do ambiente UEFI para o sistema operacional, concluindo com a chamada ExitBootServices() .
  • Tempo de execução (RT) : Nesta fase, o sistema operacional está totalmente operacional, gerenciando o sistema sob seu controle.
  • After Life (AL) : Esta fase lida com cenários em que o hardware ou o SO trava/desliga/reinicializa. O firmware pode tentar ações de recuperação, no entanto, a especificação UEFI PI não define requisitos ou comportamentos específicos para esta fase.


Este processo e suas fases de execução são cobertos pela UEFI Platform Initialization (PI) Specification . No entanto, há também a UEFI Interface (indicada pela linha azul em negrito na imagem), que não faz parte do documento anterior e é descrita na UEFI Specification . Embora os nomes e o uso frequente de UEFI possam ser confusos, esses dois documentos têm focos diferentes:


  • Especificação UEFI PI : concentra-se nas interfaces entre componentes de firmware de baixo nível e detalha como esses módulos interagem para inicializar a plataforma.


  • UEFI Spec : Define as interfaces para interação entre o Sistema Operacional (SO) e o firmware. Isso será discutido mais adiante no contexto do Second-Stage Bootloader . Observe que a UEFI Specification depende da PI Specification.


Essencialmente, ambas as especificações são sobre interfaces, mas em níveis diferentes. Para informações detalhadas, você pode acessar ambas as especificações no site do UEFI Forum .


O UEFI PI foi inicialmente projetado como uma solução de firmware unificada, não considerando a distinção entre bootloaders de primeiro e segundo estágios. No entanto, quando nos referimos ao UEFI como First-Stage Bootloader , ele inclui as fases SEC , PEI e early DXE . A razão pela qual dividimos o DXE em early e late stages é devido às suas diferentes funções no processo de inicialização.


Na fase inicial do DXE , os drivers geralmente realizam a inicialização essencial da CPU/PCH/placa e também produzem Protocolos Arquitetônicos (APs) do DXE , que ajudam a isolar a fase do DXE do hardware específico da plataforma. Os APs encapsulam os detalhes específicos da plataforma, permitindo que a fase final do DXE opere independentemente das especificações do hardware.



Inicialização do núcleo

Artigos detalhados sobre como o Coreboot funciona em breve. Siga minhas mídias sociais – eles serão publicados muito em breve!

Outras soluções

  • Intel Slim Bootloader (SBL) : bootloader puro de primeiro estágio que fornece apenas a inicialização dos componentes de hardware principais, seguido pelo carregamento do payload. No entanto, ele funciona apenas em plataformas Intel x86 e não suporta AMD x86 ou outras arquiteturas.
  • Das U-Boot : um bootloader de primeiro e segundo estágios. No entanto, o suporte para inicialização direta do vetor de redefinição x86 da plataforma (conhecido como modo bare) é limitado em comparação a outros firmwares. É mais popular em sistemas embarcados e dispositivos baseados em ARM. Como um bootloader de segundo estágio, o U-Boot implementa um subconjunto do UEFI, mas se concentra em sistemas embarcados.

Carregador de inicialização de segundo estágio (SSBL)

Após a conclusão da configuração inicial do hardware, o segundo estágio entra em ação. Sua função principal é configurar uma interface de software entre o sistema operacional e o firmware da plataforma , garantindo que o SO possa gerenciar recursos do sistema e interagir com componentes de hardware.


O SSBL visa esconder variações de hardware o máximo possível, simplificando o desenvolvimento de SO e aplicativos ao lidar com a maioria das interfaces de nível de hardware. Essa abstração permite que os desenvolvedores se concentrem em funcionalidades de nível mais alto sem se preocupar com as diferenças de hardware subjacentes.


Principais responsabilidades do SSBL :


  1. Recuperação de informações da plataforma : obtém informações específicas da plataforma do First-Stage Bootloader , incluindo mapeamento de memória, SMBIOS, tabelas ACPI, flash SPI, etc.


  2. Execute drivers independentes de plataforma : inclui drivers para SMM, SPI, PCI, SCSI/ATA/IDE/DISK, USB, ACPI, interfaces de rede e assim por diante.


  3. Implementação de serviços (também conhecida como interface) : fornece um conjunto de serviços que facilitam a comunicação entre o sistema operacional e os componentes de hardware.


  4. Menu de configuração : oferece um menu de configuração do sistema, permitindo que os usuários ajustem as configurações relacionadas à ordem de inicialização, preferências de hardware e outros parâmetros do sistema.


  5. Lógica de inicialização : Mecanismo para localizar e carregar a carga útil (provavelmente o sistema operacional) da mídia de inicialização disponível.

BIOS

A interface no BIOS é conhecida como BIOS services/functions/interrupt calls . Essas funções fornecem um conjunto de rotinas para acesso ao hardware, mas os detalhes específicos de como elas são executadas no hardware específico do sistema são ocultados do usuário.


No Modo Real de 16 bits, eles podem ser facilmente acessados invocando uma interrupção de software via instrução de linguagem assembly INT x86. No Modo Protegido de 32 bits, quase todos os serviços do BIOS ficam indisponíveis devido à maneira diferente como os valores de segmento são manipulados.




Vamos tomar como exemplo o Disk Services ( INT 13h ), que fornece serviços de leitura e gravação de disco rígido e disquete baseados em setor usando endereçamento Cylinder-Head-Sector (CHS) , como um exemplo de como essa interface pode ser usada. Digamos que queremos ler 2 setores (1024 bytes) e carregá-los no endereço de memória 0x9020 , então o seguinte código poderia ser executado:


 mov $0x02, %ah # Set BIOS read sector routine mov $0x00, %ch # Select cylinder 0 mov $0x00, %dh # Select head 0 [has a base of 0] mov $0x02, %cl # Select sector 2 (next after the # boot sector) [has a base of 1] mov $0x02, %al # Read 2 sectors mov $0x00, %bx # Set BX general register to 0 mov %bx, %es # Set ES segment register to 0 mov $0x9020, %bx # Load sectors to ES:BX (0:0x9020) int $0x13 # Start reading from drive jmp $0x9020 # Jump to loaded code


Se você estiver interessado em como esse serviço é escrito no SeaBios, dê uma olhada em src/disk.c .

Fase de inicialização

  • Inicia a busca por um dispositivo inicializável (pode ser um disco rígido, CD-ROM, disquete, etc.) lendo o primeiro setor de 512 bytes (setor zero) dos dispositivos.


  • A sequência de bootstrap no BIOS carrega o primeiro Master Boot Record (MBR) válido que encontra na memória física do computador no endereço físico 0x7C00 (dica: 0x0000:0x7c00 e 0x7c0:0x0000 referem-se ao mesmo endereço físico).


  • O BIOS transfere o controle para os primeiros 512 bytes do payload. Este setor carregado , que é muito pequeno para conter todo o código do payload, serve ao propósito de carregar o restante do payload do dispositivo inicializável . Neste ponto, o payload pode usar a interface exposta pelo BIOS.


Vale ressaltar que as especificações do BIOS não existiam nos primeiros dias. O BIOS é um padrão de fato - ele funciona da mesma forma que funcionava nos PCs IBM reais, na década de 1980. O resto dos fabricantes apenas fizeram engenharia reversa e tornaram os BIOS compatíveis com IBM. Como resultado, não havia regulamentação para impedir que os fabricantes de BIOS inventassem novas funções do BIOS ou tivessem funcionalidades sobrepostas.

Interface de Firmware Extensível Unificada (UEFI)

Como mencionado antes, o UEFI em si é apenas uma especificação e tem muitas implementações. O mais amplamente usado é o TianoCore EDK II , uma implementação de referência de código aberto das especificações UEFI e PI. Embora o EDKII sozinho não seja suficiente para criar um firmware de inicialização totalmente funcional, ele fornece uma base sólida para a maioria das soluções comerciais.


Para dar suporte a diferentes First-Stage Bootloaders e fornecer uma interface UEFI, o projeto UEFI Payload é usado. Ele depende da configuração inicial feita e das informações de plataforma fornecidas pelo firmware de inicialização para preparar o sistema para o ambiente UEFI.


O UEFI Payload usa as fases DXE e BDS , que são projetadas para serem independentes de plataforma. Ele oferece um payload genérico que pode se adaptar a diferentes plataformas. Na maioria dos casos, ele não requer nenhuma personalização ou ajustes específicos de plataforma e pode ser usado como está, consumindo informações de plataforma do First-Stage Bootloader .


Variantes do UEFI Payload :


  1. Legacy UEFI Payload : requer uma biblioteca de análise para extrair informações de plataforma específicas da implementação necessárias. Se o bootloader atualizar sua API, o payload também deverá ser atualizado.



  2. Universal UEFI Payload : segue a especificação Universal Scalable Firmware (USF) , usando Executable and Linkable Format (ELF) ou Flat Image Tree (FIT) como um formato de imagem comum. Em vez de analisá-los ele mesmo, ele espera receber os Hand Off Blocks (HOBs) na entrada do payload.


Enquanto o Legacy UEFI Payload funciona bem, a comunidade EDK2 está tentando mudar a indústria para o Universal UEFI Payload . A escolha entre os payloads depende dos seus componentes de firmware. Por exemplo, não é possível executar o Legacy Payload com suporte a SMM no Slim Bootloader sem meu patch . Por outro lado, usar o Universal Payload com coreboot requer uma camada shim para traduzir tabelas coreboot em HOBs , um recurso disponível apenas no fork do StarLabs EDK2 .

Interface

Cada sistema compatível com UEFI fornece uma System Table que é passada para cada código em execução no ambiente UEFI (drivers, aplicativos, carregadores de SO). Essa estrutura de dados permite que um executável UEFI acesse tabelas de configuração do sistema , como ACPI , SMBIOS e uma coleção de serviços UEFI .



A estrutura da tabela é descrita em MdePkg/Include/Uefi/UefiSpec.h :


 typedef struct { EFI_TABLE_HEADER Hdr; CHAR16 *FirmwareVendor; UINT32 FirmwareRevision; EFI_HANDLE ConsoleInHandle; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; EFI_HANDLE ConsoleOutHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; EFI_HANDLE StandardErrorHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; // // A pointer to the EFI Runtime Services Table. // EFI_RUNTIME_SERVICES *RuntimeServices; // // A pointer to the EFI Boot Services Table. // EFI_BOOT_SERVICES *BootServices; UINTN NumberOfTableEntries; EFI_CONFIGURATION_TABLE *ConfigurationTable; } EFI_SYSTEM_TABLE;


Os serviços incluem os seguintes tipos: Serviços de inicialização , Serviços de tempo de execução e Serviços fornecidos por protocolos .


O UEFI abstrai o acesso ao dispositivo configurando Protocolos UEFI . Esses protocolos são estruturas de dados que contêm ponteiros de função e são identificados por um Globally Unique IDentifier (GUID) que permite que outros módulos os localizem e os utilizem. Eles podem ser descobertos por meio de Boot Services.


Um driver UEFI produz esses protocolos, e as funções reais (não ponteiros!) estão contidas no próprio driver. Esse mecanismo permite que diferentes componentes dentro do ambiente UEFI se comuniquem entre si e garante que o SO possa interagir com dispositivos antes de carregar seus próprios drivers.



Embora alguns protocolos sejam predefinidos e descritos na especificação UEFI, os fornecedores de firmware também podem criar seus próprios protocolos personalizados para estender a funcionalidade de uma plataforma.


Serviços de inicialização

Fornece funções que podem ser usadas somente durante o tempo de inicialização. Esses serviços permanecem disponíveis até que a função EFI_BOOT_SERVICES.ExitBootServices() seja chamada ( MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c ).


Ponteiros para todos os serviços de inicialização são armazenados na Tabela de Serviços de Inicialização ( MdePkg/Include/Uefi/UefiSpec.h ):


 typedef struct { EFI_TABLE_HEADER Hdr; ... EFI_GET_MEMORY_MAP GetMemoryMap; EFI_ALLOCATE_POOL AllocatePool; EFI_FREE_POOL FreePool; ... EFI_HANDLE_PROTOCOL HandleProtocol; ... EFI_EXIT_BOOT_SERVICES ExitBootServices; ... } EFI_BOOT_SERVICES;


Serviços de tempo de execução

Um conjunto mínimo de serviços ainda é acessível enquanto o Sistema Operacional está em execução. Diferentemente dos Serviços de Inicialização, esses serviços ainda são válidos após qualquer payload (por exemplo, bootloader do SO) ter assumido o controle da plataforma por meio de uma chamada para EFI_BOOT_SERVICES.ExitBootServices() .


Ponteiros para todos os serviços de tempo de execução são armazenados na Tabela de Serviços de Tempo de Execução ( MdePkg/Include/Uefi/UefiSpec.h ):


 typedef struct { EFI_TABLE_HEADER Hdr; ... EFI_GET_TIME GetTime; EFI_SET_TIME SetTime; ... EFI_GET_VARIABLE GetVariable; EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; EFI_SET_VARIABLE SetVariable; ... EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; EFI_RESET_SYSTEM ResetSystem; ... } EFI_RUNTIME_SERVICES;


A imagem abaixo mostra a linha do tempo dos serviços de inicialização e tempo de execução, para que você possa ver exatamente quando cada um está ativo.



Fase de seleção de dispositivo de inicialização (BDS)

A especificação UEFI define um mecanismo de política de inicialização chamado gerenciador de inicialização UEFI . Ele tentará carregar aplicativos UEFI em uma ordem específica. Essa ordem e outras configurações podem ser configuradas modificando as variáveis globais NVRAM (nonvolatile random-access memory) . Vamos discutir as mais importantes delas:


  • Boot#### ( #### é substituído por um valor hexadecimal exclusivo) — uma opção de inicialização/carregamento.
  • BootCurrent — a opção de inicialização usada para iniciar o sistema em execução no momento.
  • BootNext — a opção de inicialização somente para a próxima inicialização. Isso substitui BootOrder somente para uma inicialização e é excluído pelo gerenciador de inicialização após o primeiro uso. Isso permite que você altere o comportamento da próxima inicialização sem alterar BootOrder .
  • BootOrder — a lista de carregamento de opções de inicialização ordenada. O gerenciador de inicialização tenta inicializar a primeira opção ativa nesta lista. Se não for bem-sucedido, ele tenta a próxima opção, e assim por diante.
  • BootOptionSupport — os tipos de opções de inicialização suportadas pelo gerenciador de inicialização.
  • Timeout — o tempo limite dos gerenciadores de inicialização do firmware, em segundos, antes de escolher automaticamente o valor de inicialização entre BootNext ou BootOrder .


Essas variáveis podem ser facilmente obtidas do Linux usando efibootmgr(8) :


 [root@localhost ~]# efibootmgr BootCurrent: 0000 Timeout: 5 seconds BootOrder: 0000,0001,2001,2002,2003 Boot0000* ARCHLINUX HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi) Boot0001* Windows Boot Manager HD(1,GPT,6f185443-09fc-4f15-afdf-01c523565e52,0x800,0x32000)/File(\EFI\Microsoft\Boot\bootmgfw.efi)57a94e544f5753000100000088900100780000004200430044039f0a42004a004500430054003d007b00390064006500610038003600320063002d1139006300640064002d0034006500370030102d0061006300630031002d006600330032006200330034003400640034003700390035007d00000033000300000710000000040000007fff0400 Boot0002* ARCHLINUX HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000) Boot2001* EFI USB Device RC Boot2002* EFI DVD/CDROM RC Boot2003* EFI Network RC


Vamos dar uma olhada na inicialização confiando no trecho de código acima. O UEFI começará a iterar a lista BootOrder . Para cada entrada na lista, ele procura uma variável Boot#### correspondente — Boot0000 para 0000, Boot2003 para 2003 e assim por diante. Se a variável não existir, ele continua para a próxima entrada. Se a variável existir, ele lê o conteúdo da variável. Cada variável de opção de inicialização contém um descritor EFI_LOAD_OPTION que é um buffer compactado em bytes de campos de comprimento variável (é apenas a estrutura de dados).


A estrutura de dados é descrita em [MdePkg/Include/Uefi/UefiSpec.h][ https://github.com/tianocore/edk2/blob/edk2-stable202405/MdePkg/Include/Uefi/UefiSpec.h#L2122 )


 typedef struct _EFI_LOAD_OPTION { /// The attributes for this load option entry. UINT32 Attributes; /// Length in bytes of the FilePathList. UINT16 FilePathListLength; /// The user readable description for the load option. /// Example: 'ARCHLINUX' / 'Windows Boot Manager' / `EFI USB Device` // CHAR16 Description[]; /// A packed array of UEFI device paths. /// Example: 'HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi)' // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; /// The remaining bytes in the load option descriptor are a binary data buffer that is passed to the loaded image. /// Example: '57a9...0400' in Boot0001 variable // UINT8 OptionalData[]; } EFI_LOAD_OPTION;


Neste ponto, o firmware examinará um Device Path ( EFI_DEVICE_PATH_PROTOCOL ). Na maioria dos casos, nosso computador é inicializado a partir de um dispositivo de armazenamento (Hard Drive/SSD/NVMe/etc). Então, o Device path conteria HD(Partition Number, Type, Signature, Start sector, Size in sectors) .


  • Tipo — indica o formato usado para o esquema de particionamento com as palavras-chave MBR (1) ou GPT (2).
  • Assinatura — uma assinatura MBR de 4 bytes se o Tipo for MBR , ou um UUID de 16 bytes se o Tipo for GPT .


Observação : se você estiver interessado em como traduzir outros caminhos, leia a Referência de nó de dispositivo de texto da especificação UEFI v2.10, 10.6.1.6 .


O UEFI examinará o disco e verá se ele tem uma partição que corresponde ao nó. Se existir, ele deve ser rotulado com um Globally Unique IDentifier (GUID) específico que o marca como EFI System Partition (ESP) . Este é formatado com um sistema de arquivos cuja especificação é baseada na versão específica do sistema de arquivos FAT e é chamado EFI File System ; na verdade, é apenas um FAT12/16/32 regular .


  • Inicialização nativa : se o Device Path contiver um caminho explícito para o arquivo File(\Path\To\The\File.efi) , então o UEFI procurará por esse arquivo específico. Por exemplo, a opção Boot0000 contém File(\EFI\ARCHLINUX\grubx64.efi) .
  • Inicialização de fallback : se o Device Path simplesmente apontar para um disco, então, em tais situações, o firmware usará um caminho de inicialização de fallback que é baseado na arquitetura — \EFI\BOOT\BOOT{arch}.EFI ( BOOTx64.EFI para amd64 ou BOOTia32.EFI para i386 / IA32 ). Este mecanismo permite que a mídia removível inicializável (por exemplo, uma unidade USB) funcione em UEFI; eles apenas usam um caminho de inicialização de fallback . Por exemplo, a opção Boot0002 usará este mecanismo.


Nota: Todas as opções Boot#### mencionadas acima referem-se às opções de inicialização exibidas na saída de exemplo do efibootmgr .


Em ambos os casos, o UEFI Boot Manager carregará o aplicativo UEFI (pode ser o bootloader do SO , o UEFI Shell, o software utilitário, a configuração do sistema e o que for) na memória. Neste momento, o controle é então transferido para o ponto de entrada do aplicativo UEFI . Ao contrário do BIOS , o aplicativo UEFI pode retornar o controle para o firmware (além da situação em que o aplicativo assume o controle do sistema). Se isso acontecer ou algo der errado, o Boot Manager passa para a próxima entrada Boot#### e segue exatamente o mesmo processo.


A especificação menciona que o gerenciador de boot pode manter automaticamente as variáveis do banco de dados. Isso inclui remover variáveis de opção de carregamento que não são referenciadas ou não podem ser analisadas. Além disso, ele pode reescrever qualquer lista ordenada para remover quaisquer opções de carregamento sem variáveis de opção de carregamento correspondentes.


O texto acima descreve a inicialização UEFI . Além disso, o firmware UEFI pode ser executado no modo Compatibility Support Module (CSM) que emula um BIOS.

Carregador de inicialização do sistema operacional

Um pedaço de software iniciado pelo firmware (geralmente Second-Stage Bootloader ) e usando sua interface para carregar o kernel do SO . Pode ser tão complexo quanto um SO, oferecendo recursos como:


  • Leitura de vários sistemas de arquivos (HFS+, ext4, XFS, etc)
  • Interagindo em uma rede (por exemplo, TFTP, HTTP)
  • Inicializando kernels compatíveis com Multiboot
  • Carregamento em cadeia
  • Carregando ramdisks iniciais ( initrd )
  • E muito mais!


Os designs comuns desses programas estão além do escopo deste artigo. Para uma comparação detalhada de bootloaders de SO populares, você pode consultar o wiki do ArchLinux e o artigo da Wikipedia .


O sistema Windows usa seu bootloader proprietário conhecido como Windows Boot Manager (BOOTMGR) .


Firmware não é mais um pequeno e complexo pedaço de código. Ele se tornou uma enorme quantidade de código complexo , e as tendências atuais só contribuem para isso. Podemos rodar Doom , Twitter e muitos outros aplicativos interessantes nele.


Entender a arquitetura geral ajuda a organizar esses componentes em sua mente. Ao examinar o design do firmware existente, você ganha insights sobre o fascinante processo que se desenrola cada vez que um computador é ligado. Essa perspectiva de cima para baixo não apenas esclarece o papel de cada parte, mas também destaca a natureza sofisticada e evolutiva dos sistemas de firmware modernos.

Recursos