paint-brush
Un voyage à travers les secrets du micrologiciel : du BIOS/UEFI au système d'exploitationpar@tristejoursoir
730 lectures
730 lectures

Un voyage à travers les secrets du micrologiciel : du BIOS/UEFI au système d'exploitation

par Aleksandr Goncharov20m2024/08/22
Read on Terminal Reader

Trop long; Pour lire

Découvrez l'évolution du BIOS traditionnel au micrologiciel UEFI moderne, comprenez comment les séquences de démarrage sont gérées et découvrez les rôles des services de démarrage et des services d'exécution. Plongez dans les complexités des chargeurs de démarrage du système d'exploitation et découvrez comment le micrologiciel prend désormais en charge les fonctionnalités et applications avancées.
featured image - Un voyage à travers les secrets du micrologiciel : du BIOS/UEFI au système d'exploitation
Aleksandr Goncharov HackerNoon profile picture
0-item
1-item


Vous êtes-vous déjà demandé ce qui se passe lorsque vous appuyez sur le bouton d'alimentation de votre ordinateur ? Derrière cette brève pause, avant que votre écran ne s'allume, une série complexe de processus se déroule. Cet article vous plongera dans le monde fascinant du firmware , en explorant la façon dont les différents composants interagissent pendant le processus de démarrage .


En comprenant ces connexions, vous obtiendrez une image plus claire des éléments fondamentaux qui donnent vie à votre système. Nous nous concentrerons principalement sur l' architecture Intel x86 , mais de nombreux principes s'appliquent également à d'autres architectures.


Si vous avez manqué la première partie de notre série, cliquez ici pour la rattraper. Découvrons maintenant les mystères qui se cachent derrière le firmware.

Table des matières:

  • Définitions
  • Architecture globale du micrologiciel
  • Chargeur de démarrage de première étape (FSBL)
    • BIOS (phase POST)
    • Initialisation de la plateforme UEFI (PI)
    • démarrage de base
    • Autres solutions
  • Chargeur de démarrage de deuxième étape (SSBL)
    • BIOS
    • UEFI
  • Chargeur de démarrage du système d'exploitation


Définitions

  • Micrologiciel : un type spécialisé de logiciel intégré au matériel, fournissant un contrôle de bas niveau et permettant au matériel de fonctionner correctement et d'interagir avec d'autres composants du système.


  • Basic Input/Output System (BIOS) : un micrologiciel hérité (créé à l'origine pour l' IBM PC ) responsable de l'initialisation du matériel après la mise sous tension de la plateforme. De nos jours, on l'appelle souvent vaguement l'ensemble complet du micrologiciel.


  • Bootloader : nom générique du micrologiciel responsable du démarrage d'un ordinateur. Il est utilisé comme concept moderne à la place du BIOS , fournissant souvent un cadre avec un code d'amorçage pour initialiser le processeur et le chipset, ainsi que des interfaces pour que des tiers (par exemple, les développeurs de cartes mères) puissent effectuer une initialisation spécifique à la plate-forme.


  • Charge utile : logiciel à exécuter lorsque le chargeur de démarrage se ferme. Il peut s'agir d'un chargeur de démarrage de deuxième niveau, d'un système d'exploitation, d'une application BIOS/UEFI, etc. Il prend généralement en charge le flux de démarrage en fonction de la conception du micrologiciel.


  • L'utilisation des termes BIOS et bootloader peut prêter à confusion, car leurs significations dépendent du contexte. Cependant, lorsque quelqu'un mentionne firmware , BIOS ou bootloader , il fait généralement référence à l'ensemble complet de firmwares exécutés entre le système d'exploitation et le matériel .


  • EFI vs. UEFI : L'interface EFI (Extensible Firmware Interface) était la spécification d'origine développée par Intel. L' interface UEFI (Unified Extensible Firmware Interface) est le successeur de l'EFI , créé par le Forum UEFI pour normaliser et étendre la spécification d'origine. Dans la plupart des cas, EFI et UEFI sont utilisés de manière interchangeable.

Architecture globale du micrologiciel

Pour comprendre comment les composants du firmware interagissent, nous allons explorer l'architecture entière avec toutes ses parties connectées. Le flux d'exécution, illustré dans le diagramme ci-dessous, démarre à partir du vecteur de réinitialisation , qui fait partie du chargeur de démarrage de première étape . À partir de là, il progresse à travers différentes étapes du firmware :



Le firmware ou BIOS peut généralement être divisé en deux parties principales, avec une interface généralement minimale entre elles :


  1. Initialisation du matériel : Responsable de l'initialisation des composants matériels du système.
  2. Interface avec le système d'exploitation et l'utilisateur : Fournit les interfaces nécessaires au système d'exploitation et à l'utilisateur.


La conception du micrologiciel de la plateforme peut être soit monolithique , combinant l'initialisation matérielle et la fonctionnalité de démarrage, soit suivre un flux de démarrage modulaire et par étapes. Le choix de la conception dépend des exigences du système et peut être préférable pour certains appareils.


Le diagramme suivant illustre comment les différents composants du micrologiciel interagissent et peuvent être utilisés ensemble pour prendre en charge le processus de démarrage (les flèches indiquent la séquence d'exécution) :



Si ces diagrammes vous semblent complexes maintenant, ne vous inquiétez pas. Relisez-les après avoir lu cet article et ils seront plus clairs.

Chargeur de démarrage de première étape (FSBL)

Ce micrologiciel est conçu pour initialiser les ordinateurs et les systèmes embarqués en mettant l'accent sur l'initialisation matérielle minimale : faire uniquement ce qui est absolument nécessaire, puis passer le contrôle au chargeur de démarrage de deuxième étape afin de démarrer le système d'exploitation. Le FSBL ne charge pas les systèmes d'exploitation à partir de supports de stockage autres que la puce flash . Comme il initialise uniquement le matériel sous-jacent et ne gère pas les supports de démarrage tels que les disques durs, les SSD ou les clés USB, un autre logiciel est nécessaire pour démarrer réellement un système d'exploitation .


Principales responsabilités de la FSBL :


  1. CPU : Passage du mode réel 16 bits au mode protégé 32 bits ( note : ou en mode virtuel 8086 dans le cas du BIOS).
  2. Utilisation du cache : appel de FSP-T pour configurer le cache en tant que RAM pour l' environnement C.
  3. Port de débogage : initialisation du port de débogage configuré en appelant des méthodes d'initialisation spécifiques à la carte.
  4. Initialisation de la mémoire : appel de FSP-M pour initialiser la mémoire principale du système et enregistrer les informations cruciales de la mémoire système.
  5. GPIO : configuration des broches d'entrée/sortie à usage général (GPIO) pour l'interfaçage avec des périphériques externes.
  6. Silicium : Exécution d'une initialisation précoce de la plate-forme et utilisation de FSP-S pour terminer l'initialisation du chipset, du processeur et du contrôleur d'E/S.
  7. Énumération PCI : énumération des périphériques PCI et allocation de ressources telles que les adresses mémoire et les IRQ.
  8. Préparation de la charge utile : configuration des tables SMBIOS et ACPI , y compris les informations de préparation (tables coreboot, HOB) devant être transmises à la charge utile.
  9. Chargement et transfert : Chargement et transfert de contrôle à la charge utile.

BIOS (Phase POST)

Aux débuts de l'informatique, les logiciels open source n'étaient pas très populaires et la plupart des implémentations du BIOS étaient propriétaires. Il n'existe que quelques solutions open source disponibles fournissant le code source POST du BIOS, telles que Super PC/Turbo XT BIOS et GLaBIOS . Ces projets ont été conçus pour fonctionner sur les systèmes IBM 5150/5155/5160 et la plupart des clones XT.


Cependant, les implémentations de BIOS open source les plus connues, comme OpenBIOS et SeaBIOS , n'effectuent pas d'initialisation matérielle car elles ne sont pas destinées à fonctionner sur du matériel nu. Mais elles sont largement utilisées comme chargeurs de démarrage de deuxième étape et fonctionnent nativement dans des environnements virtuels comme QEMU et Bochs.


Quoi qu'il en soit, il y a peu de chances que vous ayez besoin de travailler directement avec ces premiers BIOS ou de vous plonger dans leurs spécificités. Mais si vous souhaitez les explorer, les référentiels mentionnés sont un bon point de départ.


En ce qui concerne les tendances actuelles de développement, il ne semble pas y avoir de développement continu de solutions BIOS propriétaires, et de tels projets sont devenus obsolètes face aux alternatives modernes.

Initialisation de la plateforme UEFI (PI)

Le processus de démarrage suit un flux par étapes, commençant de la gauche vers la droite dans la figure suivante. La chronologie du processus de démarrage de la plateforme est divisée en plusieurs phases, comme indiqué par des cases jaunes :



  • Sécurité (SEC) : Première phase après un vecteur de réinitialisation , sa fonction principale est de configurer la RAM temporaire (CPU Cache-As-RAM ou SRAM).
  • Initialisation pré-EFI (PEI) : cette phase envoie des pilotes spécialisés appelés modules d'initialisation pré-EFI (PEIM) . Ces modules gèrent l'initialisation matérielle essentielle, comme la configuration du processeur et du chipset et la configuration de la mémoire principale (DRAM) .
  • Environnement d'exécution du pilote (DXE) : dans cette phase, le reste de l'initialisation du système est effectué. La phase DXE fournit des services UEFI et prend en charge divers protocoles et pilotes nécessaires au fonctionnement du système.
  • Sélection du périphérique de démarrage (BDS) : cette phase implémente la politique de démarrage de la plateforme, en déterminant la séquence de démarrage et en sélectionnant le périphérique de démarrage/chargeur approprié.
  • Chargement système transitoire (TSL) : pendant cette phase, le système exécute des applications à l'aide des services UEFI pour préparer le système d'exploitation. Elle comprend la transition de l'environnement UEFI vers le système d'exploitation, qui se termine par l'appel ExitBootServices() .
  • Run Time (RT) : Dans cette phase, le système d'exploitation est pleinement opérationnel, gérant le système sous son contrôle.
  • After Life (AL) : cette phase traite des scénarios dans lesquels le matériel ou le système d'exploitation tombe en panne/s'arrête/redémarre. Le micrologiciel peut tenter des actions de récupération, cependant, la spécification UEFI PI ne définit pas d'exigences ou de comportements spécifiques pour cette phase.


Ce processus et ses phases d'exécution sont couverts par la spécification UEFI Platform Initialization (PI) . Cependant, il existe également l' interface UEFI (indiquée par la ligne bleue en gras sur l'image), qui ne fait pas partie du document précédent et est décrite dans la spécification UEFI . Bien que les noms et l'utilisation fréquente de l'UEFI puissent prêter à confusion, ces deux documents ont des objectifs différents :


  • Spécification UEFI PI : se concentre sur les interfaces entre les composants du micrologiciel de bas niveau et détaille la manière dont ces modules interagissent pour initialiser la plate-forme.


  • Spécification UEFI : définit les interfaces d'interaction entre le système d'exploitation (OS) et le micrologiciel. Ce point sera abordé plus en détail dans le contexte du chargeur de démarrage de deuxième étape . Notez que la spécification UEFI s'appuie sur la spécification PI.


En fait, les deux spécifications concernent les interfaces, mais à des niveaux différents. Pour des informations détaillées, vous pouvez accéder aux deux spécifications sur le site Web du Forum UEFI .


L'UEFI PI a été initialement conçu comme une solution de micrologiciel unifiée, sans tenir compte de la distinction entre les chargeurs de démarrage de première et de deuxième étape. Cependant, lorsque nous faisons référence à l'UEFI comme chargeur de démarrage de première étape , cela inclut les phases SEC , PEI et DXE précoce . La raison pour laquelle nous divisons DXE en étapes précoces et tardives est due à leurs rôles différents dans le processus d'initialisation.


Au cours de la phase DXE initiale , les pilotes effectuent généralement l'initialisation essentielle du processeur/du PCH/de la carte et génèrent également des protocoles d'architecture DXE (AP) , qui aident à isoler la phase DXE du matériel spécifique à la plateforme. Les AP encapsulent les détails spécifiques à la plateforme, permettant à la phase DXE tardive de fonctionner indépendamment des spécificités matérielles.



Démarrage de base

Des articles détaillés sur le fonctionnement de Coreboot seront bientôt disponibles. Suivez-moi sur les réseaux sociaux – ils seront publiés très bientôt !

Autres solutions

  • Intel Slim Bootloader (SBL) : chargeur de démarrage de première étape qui assure uniquement l'initialisation des composants matériels de base, suivi du chargement de la charge utile. Cependant, il ne fonctionne que sur les plates-formes Intel x86 et ne prend pas en charge les architectures AMD x86 ou autres.
  • Le U-Boot : à la fois un chargeur de démarrage de première et de deuxième étape. Cependant, la prise en charge du démarrage direct à partir du vecteur de réinitialisation x86 de la plateforme (connu sous le nom de mode nu) est limitée par rapport aux autres micrologiciels. Il est plus populaire sur les systèmes embarqués et les appareils basés sur ARM. En tant que chargeur de démarrage de deuxième étape, U-Boot implémente un sous-ensemble de l'UEFI mais se concentre sur les systèmes embarqués.

Chargeur de démarrage de deuxième étape (SSBL)

Une fois la configuration matérielle initiale terminée, la deuxième étape entre en jeu. Son rôle principal est de mettre en place une interface logicielle entre le système d'exploitation et le micrologiciel de la plateforme , garantissant que le système d'exploitation peut gérer les ressources système et interagir avec les composants matériels.


Le SSBL vise à masquer autant que possible les variations matérielles , en simplifiant le développement du système d'exploitation et des applications en gérant la plupart des interfaces au niveau matériel. Cette abstraction permet aux développeurs de se concentrer sur les fonctionnalités de niveau supérieur sans se soucier des différences matérielles sous-jacentes.


Principales responsabilités de SSBL :


  1. Récupération des informations de la plate-forme : obtient des informations spécifiques à la plate-forme à partir du chargeur de démarrage de première étape , y compris le mappage de mémoire, le SMBIOS, les tables ACPI, le flash SPI, etc.


  2. Exécutez des pilotes indépendants de la plate-forme : inclut des pilotes pour SMM, SPI, PCI, SCSI/ATA/IDE/DISK, USB, ACPI, interfaces réseau, etc.


  3. Implémentation de services (également appelée interface) : fournit un ensemble de services qui facilitent la communication entre le système d'exploitation et les composants matériels.


  4. Menu de configuration : propose un menu de configuration pour la configuration du système, permettant aux utilisateurs d'ajuster les paramètres liés à l'ordre de démarrage, aux préférences matérielles et à d'autres paramètres système.


  5. Logique de démarrage : mécanisme permettant de localiser et de charger la charge utile (probablement le système d'exploitation) à partir du support de démarrage disponible.

BIOS

L'interface du BIOS est connue sous le nom de services/fonctions/appels d'interruption du BIOS . Ces fonctions fournissent un ensemble de routines pour l'accès au matériel, mais les détails spécifiques de la manière dont elles sont exécutées sur le matériel particulier du système sont cachés à l'utilisateur.


En mode réel 16 bits, ils sont facilement accessibles en invoquant une interruption logicielle via l'instruction INT du langage assembleur x86. En mode protégé 32 bits, presque tous les services du BIOS ne sont pas disponibles en raison de la manière différente dont les valeurs de segment sont gérées.




Prenons par exemple Disk Services ( INT 13h ), qui fournit des services de lecture et d'écriture de disque dur et de disquette basés sur des secteurs en utilisant l'adressage CHS (Cylindres-têtes-secteurs) , comme exemple de la façon dont cette interface peut être utilisée. Supposons que nous souhaitons lire 2 secteurs (1024 octets) et les charger à l'adresse mémoire 0x9020 , le code suivant pourrait alors être exécuté :


 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


Si vous êtes intéressé par la manière dont ce service est écrit dans SeaBios, jetez un œil à src/disk.c .

Phase de démarrage

  • Commence à rechercher un périphérique de démarrage (il peut s'agir d'un disque dur, d'un CD-ROM, d'une disquette, etc.) en lisant le premier secteur de 512 octets (secteur zéro) des périphériques.


  • La séquence d'amorçage dans le BIOS charge le premier Master Boot Record (MBR) valide qu'il trouve dans la mémoire physique de l'ordinateur à l'adresse physique 0x7C00 (indice : 0x0000:0x7c00 et 0x7c0:0x0000 font référence à la même adresse physique).


  • Le BIOS transfère le contrôle aux 512 premiers octets de la charge utile. Ce secteur chargé , qui est trop petit pour contenir l'intégralité du code de la charge utile, sert à charger le reste de la charge utile à partir du périphérique de démarrage . À ce stade, la charge utile peut utiliser l'interface exposée par le BIOS.


Il est intéressant de noter que les spécifications du BIOS n'existaient pas à l'origine. Le BIOS est une norme de fait : il fonctionne de la même manière que sur les PC IBM réels, dans les années 1980. Les autres fabricants ont simplement procédé à une rétro-ingénierie et ont créé des BIOS compatibles IBM. Par conséquent, il n'y avait aucune réglementation pour empêcher les fabricants de BIOS d'inventer de nouvelles fonctions du BIOS ou d'avoir des fonctionnalités qui se chevauchent.

Interface de micrologiciel extensible unifiée (UEFI)

Comme mentionné précédemment, l'UEFI n'est qu'une spécification et possède de nombreuses implémentations. La plus utilisée est TianoCore EDK II , une implémentation de référence open source des spécifications UEFI et PI. Bien qu'EDKII seul ne soit pas suffisant pour créer un micrologiciel de démarrage entièrement fonctionnel, il fournit une base solide pour la plupart des solutions commerciales.


Pour prendre en charge différents chargeurs de démarrage de première étape et fournir une interface UEFI, le projet UEFI Payload est utilisé. Il s'appuie sur la configuration initiale effectuée et sur les informations de plate-forme fournies par le micrologiciel de démarrage pour préparer le système à l'environnement UEFI.


La charge utile UEFI utilise les phases DXE et BDS , qui sont conçues pour être indépendantes de la plateforme. Elle offre une charge utile générique qui peut s'adapter à différentes plateformes. Dans la plupart des cas, elle ne nécessite aucune personnalisation ni aucun ajustement spécifique à la plateforme et peut être utilisée telle quelle en consommant les informations de la plateforme à partir du chargeur de démarrage de première étape .


Variantes de la charge utile UEFI :


  1. Charge utile UEFI héritée : nécessite une bibliothèque d'analyse pour extraire les informations de plateforme spécifiques à l'implémentation nécessaires. Si le chargeur de démarrage met à jour son API, la charge utile doit également être mise à jour.



  2. Charge utile UEFI universelle : conforme à la spécification USF (Universal Scalable Firmware) , en utilisant le format ELF (Executable and Linkable Format) ou le format FIT (Flat Image Tree) comme format d'image commun. Au lieu de les analyser lui-même, il s'attend à recevoir les blocs de transfert (HOB) à l'entrée de la charge utile.


Bien que la charge utile UEFI Legacy fonctionne bien, la communauté EDK2 tente de faire évoluer l'industrie vers la charge utile UEFI universelle . Le choix entre les charges utiles dépend des composants de votre firmware. Par exemple, il n'est pas possible d'exécuter la charge utile Legacy avec prise en charge SMM sur Slim Bootloader sans mon patch . D'un autre côté, l'utilisation de la charge utile universelle avec coreboot nécessite une couche de calage pour traduire les tables coreboot en HOB , une fonctionnalité uniquement disponible dans le fork StarLabs EDK2 .

Interface

Chaque système compatible UEFI fournit une table système qui est transmise à chaque code exécuté dans l'environnement UEFI (pilotes, applications, chargeurs de système d'exploitation). Cette structure de données permet à un exécutable UEFI d'accéder aux tables de configuration système telles que ACPI , SMBIOS et un ensemble de services UEFI .



La structure de la table est décrite dans 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;


Les services incluent les types suivants : services de démarrage , services d’exécution et services fournis par des protocoles .


L'UEFI abstrait l'accès au périphérique en configurant des protocoles UEFI . Ces protocoles sont des structures de données contenant des pointeurs de fonction et sont identifiés par un identifiant unique global (GUID) qui permet aux autres modules de les localiser et de les utiliser. Ils peuvent être découverts via les services de démarrage.


Un pilote UEFI génère ces protocoles, et les fonctions réelles (pas les pointeurs !) sont contenues dans le pilote lui-même. Ce mécanisme permet aux différents composants de l'environnement UEFI de communiquer entre eux et garantit que le système d'exploitation peut interagir avec les périphériques avant de charger ses propres pilotes.



Alors que certains protocoles sont prédéfinis et décrits dans la spécification UEFI, les fournisseurs de micrologiciels peuvent également créer leurs propres protocoles personnalisés pour étendre les fonctionnalités d'une plate-forme.


Services de démarrage

Fournit des fonctions qui ne peuvent être utilisées qu'au démarrage. Ces services restent disponibles jusqu'à ce que la fonction EFI_BOOT_SERVICES.ExitBootServices() soit appelée ( MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c ).


Les pointeurs vers tous les services de démarrage sont stockés dans la table des services de démarrage ( 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;


Services d'exécution

Un ensemble minimal de services reste accessible pendant l'exécution du système d'exploitation. Contrairement aux services de démarrage, ces services restent valides après qu'une charge utile (par exemple, le chargeur de démarrage du système d'exploitation) a pris le contrôle de la plateforme via un appel à EFI_BOOT_SERVICES.ExitBootServices() .


Les pointeurs vers tous les services d'exécution sont stockés dans la table des services d'exécution ( 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;


L'image ci-dessous montre la chronologie des services de démarrage et d'exécution, afin que vous puissiez voir exactement quand chacun d'eux est actif.



Phase de sélection du périphérique de démarrage (BDS)

La spécification UEFI définit un moteur de stratégie de démarrage appelé gestionnaire de démarrage UEFI . Il tentera de charger les applications UEFI dans un ordre spécifique. Cet ordre et d'autres paramètres peuvent être configurés en modifiant les variables NVRAM (mémoire vive non volatile) globales. Examinons les plus importantes d'entre elles :


  • Boot#### ( #### est remplacé par une valeur hexadécimale unique) — une option de démarrage/chargement.
  • BootCurrent — l'option de démarrage utilisée pour démarrer le système en cours d'exécution.
  • BootNext — l'option de démarrage pour le prochain démarrage uniquement. Elle remplace BootOrder pour un seul démarrage et est supprimée par le gestionnaire de démarrage après la première utilisation. Cela vous permet de modifier le comportement du prochain démarrage sans modifier BootOrder .
  • BootOrder — la liste de chargement des options de démarrage ordonnées. Le gestionnaire de démarrage essaie de démarrer la première option active de cette liste. En cas d'échec, il essaie l'option suivante, et ainsi de suite.
  • BootOptionSupport — les types d’options de démarrage pris en charge par le gestionnaire de démarrage.
  • Timeout — le délai d'expiration des gestionnaires de démarrage du micrologiciel, en secondes, avant de choisir automatiquement la valeur de démarrage parmi BootNext ou BootOrder .


Ces variables peuvent être facilement obtenues à partir de Linux en utilisant 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


Examinons le démarrage en nous appuyant sur l'extrait de code ci-dessus. UEFI va commencer à parcourir la liste BootOrder . Pour chaque entrée de la liste, il recherche une variable Boot#### correspondante : Boot0000 pour 0000, Boot2003 pour 2003, etc. Si la variable n'existe pas, il passe à l'entrée suivante. Si la variable existe, il lit le contenu de la variable. Chaque variable d'option de démarrage contient un descripteur EFI_LOAD_OPTION qui est un tampon rempli d'octets de champs de longueur variable (il s'agit simplement de la structure de données).


La structure des données est décrite dans [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;


À ce stade, le micrologiciel examinera un chemin d'accès au périphérique ( EFI_DEVICE_PATH_PROTOCOL ). Dans la plupart des cas, notre ordinateur est démarré à partir d'un périphérique de stockage (disque dur/SSD/NVMe/etc.). Ainsi, le chemin d'accès au périphérique contiendrait le nœud HD(Partition Number, Type, Signature, Start sector, Size in sectors) .


  • Type — indique le format utilisé pour le schéma de partitionnement avec les mots-clés MBR (1) ou GPT (2).
  • Signature — une signature MBR de 4 octets si le type est MBR , ou un UUID de 16 octets si le type est GPT .


Remarque : si vous souhaitez savoir comment traduire d'autres chemins, lisez la spécification UEFI v2.10, 10.6.1.6 Référence du nœud de périphérique texte .


L'UEFI examinera le disque et verra s'il contient une partition correspondant au nœud. Si elle existe, elle doit être étiquetée avec un identifiant unique global (GUID) spécifique qui la marque comme partition système EFI (ESP) . Celle-ci est formatée avec un système de fichiers dont la spécification est basée sur la version spécifique du système de fichiers FAT et est nommée Système de fichiers EFI ; en fait, il s'agit simplement d'un FAT12/16/32 normal.


  • Démarrage natif : si le chemin d'accès du périphérique contient un chemin explicite vers le fichier File(\Path\To\The\File.efi) , alors UEFI recherchera ce fichier spécifique. Par exemple, l'option Boot0000 contient File(\EFI\ARCHLINUX\grubx64.efi) .
  • Démarrage de secours : si le chemin d'accès au périphérique pointe simplement vers un disque, dans de telles situations, le micrologiciel utilisera un chemin de démarrage de secours basé sur l'architecture — \EFI\BOOT\BOOT{arch}.EFI ( BOOTx64.EFI pour amd64 ou BOOTia32.EFI pour i386 / IA32 ). Ce mécanisme permet au support amovible de démarrage (par exemple, une clé USB) de fonctionner en UEFI ; ils utilisent simplement un chemin de démarrage de secours . Par exemple, l'option Boot0002 utilisera ce mécanisme.


Remarque : toutes les options Boot#### mentionnées ci-dessus font référence aux options de démarrage affichées dans l'exemple de sortie de efibootmgr .


Dans les deux cas, le gestionnaire de démarrage UEFI charge l' application UEFI (il peut s'agir du chargeur de démarrage du système d'exploitation , du shell UEFI, d'un logiciel utilitaire, de la configuration du système, etc.) en mémoire. À ce moment, le contrôle est alors transféré au point d'entrée de l' application UEFI . Contrairement au BIOS , l' application UEFI peut rendre le contrôle au micrologiciel (en dehors de la situation où l'application prend le contrôle du système). Si cela se produit ou si quelque chose ne va pas, le gestionnaire de démarrage passe à l'entrée Boot#### suivante et suit exactement le même processus.


La spécification mentionne que le gestionnaire de démarrage peut gérer automatiquement les variables de la base de données. Cela inclut la suppression des variables d'option de chargement qui ne sont pas référencées ou qui ne peuvent pas être analysées. De plus, il peut réécrire n'importe quelle liste ordonnée pour supprimer toutes les options de chargement sans variables d'option de chargement correspondantes.


Le texte ci-dessus décrit le démarrage UEFI . De plus, le micrologiciel UEFI peut s'exécuter en mode Compatibility Support Module (CSM) qui émule un BIOS.

Chargeur de démarrage du système d'exploitation

Un logiciel démarré par le micrologiciel (généralement le chargeur de démarrage de deuxième étape ) et utilisant son interface pour charger le noyau du système d'exploitation . Il peut être aussi complexe qu'un système d'exploitation et offrir des fonctionnalités telles que :


  • Lecture à partir de divers systèmes de fichiers (HFS+, ext4, XFS, etc.)
  • Interagir sur un réseau (par exemple, TFTP, HTTP)
  • Démarrage des noyaux compatibles Multiboot
  • Chargement en chaîne
  • Chargement des disques RAM initiaux ( initrd )
  • Et plus encore !


Les conceptions courantes de ces programmes dépassent le cadre de cet article. Pour une comparaison détaillée des chargeurs de démarrage de systèmes d'exploitation les plus courants, vous pouvez vous référer au wiki ArchLinux et à l' article de Wikipédia .


Le système Windows utilise son propre chargeur de démarrage de système d'exploitation appelé Windows Boot Manager (BOOTMGR) .


Le micrologiciel n'est plus un petit morceau de code complexe . Il est devenu une énorme quantité de code complexe , et les tendances actuelles ne font qu'y contribuer. Nous pouvons exécuter Doom , Twitter et bien d'autres applications intéressantes dessus.


Comprendre l'architecture globale permet d'organiser ces composants dans votre esprit. En examinant la conception du micrologiciel existant, vous obtenez un aperçu du processus fascinant qui se déroule à chaque mise sous tension d'un ordinateur. Cette perspective descendante clarifie non seulement le rôle de chaque élément, mais met également en évidence la nature sophistiquée et évolutive des systèmes de micrologiciels modernes.

Ressources