Beaucoup de gens s'intéressent à la façon dont l'ordinateur démarre. C'est là que la magie commence et continue tant que l'appareil est allumé. Dans cet article, nous donnerons un aperçu du processus de démarrage , y compris ses différentes étapes, les composants clés impliqués et les défis rencontrés au cours du processus.
Bien que nous nous concentrions principalement sur l' architecture x86 (la plus largement utilisée), d'autres architectures auraient de nombreuses similitudes dans leur processus de démarrage. J'espère que cet article sera une ressource précieuse pour tous ceux qui cherchent à approfondir leurs connaissances dans ce domaine. Nous y voilà!
Un circuit intégré (puce) situé sur la carte mère et stockant le code du micrologiciel responsable du démarrage de l'ordinateur est appelé BOOT ROM . Ce nom n'est pas standardisé, donc les autres développeurs l'appellent souvent FLASH ROM , BIOS FLASH , BOOT FLASH , SPI FLASH , etc. (ces noms leur sont donnés en raison de la technologie, de l'interface et des noms d'objectif). Ne vous inquiétez pas, ces termes sont interchangeables. Le code du micrologiciel dans la BOOT ROM est exécuté en premier lorsque l'ordinateur est sous tension. Il effectue des tests de base, initialise le matériel, puis charge le chargeur de système d'exploitation à partir d'un périphérique amorçable, tel qu'un disque dur ou une clé USB, dans la mémoire. Cette puce est fabriquée à partir de mémoire non volatile (NVM) .
La mémoire non volatile est un type de mémoire d'ordinateur qui conserve son contenu même lorsque l'alimentation est coupée . Cela rend ce type de mémoire idéal pour stocker des données importantes qui doivent être conservées même lorsque l'ordinateur est éteint. De plus, la discussion se concentrera uniquement sur la mémoire qui contient le code du firmware. Nous ne parlerons pas de stockage tels que les disques durs (HDD), les disques SSD (Solid State Drives), les disquettes, etc.
Fondamentalement, nous pouvons classer ce type de mémoire dans les groupes suivants.
Programmable électriquement effaçable (EEPROM) : peut être reprogrammé plusieurs fois à l'aide de signaux électriques .
Mémoire Flash NOR : Agencement architectural en blocs où les données sont effacées au niveau du bloc et peuvent être lues ou écrites au niveau de l'octet . La mémoire NOR est directement accessible à l'aide d'une interface standard telle que byte parallel, I2C ou SPI.
Dans l'industrie, il existe une convention pour réserver le terme EEPROM aux mémoires effaçables par octet par rapport aux mémoires flash effaçables par bloc.
La mémoire programmable est livrée avec une règle : effacer avant d'écrire . Dans une telle mémoire, l'écriture de nouvelles données est plus compliquée car les données sont stockées sous forme de charge sur une grille flottante (la raison principale réside simplement dans la physique des cellules de mémoire). La quantité de charge sur la grille détermine si la cellule stocke "0" ou "1".
Lorsque vous effacez une puce de mémoire flash, vous définissez tous les bits de données qui y sont stockés sur un état connu (par défaut), généralement un "1" logique. Cela vous permet de commencer avec une table rase, pour ainsi dire, et de programmer de nouvelles données sur la puce sans avoir de restes des anciennes données qui y sont encore stockées. Lorsque de nouvelles données sont écrites sur la puce, l'état des bits individuels passe de "1" à "0" pour représenter les nouvelles données.
Si vous écrivez simplement de nouvelles données sur la puce sans les effacer au préalable, les nouvelles données seraient combinées avec les anciennes, ce qui donnerait des résultats imprévisibles. Par exemple, considérons une puce de mémoire flash dotée de 8 bits de mémoire stockant la valeur "0110 0010". Si vous écrivez de nouvelles données "1100 1001" sur la puce sans les effacer au préalable, l'état résultant de la puce serait "0100 0000", ce qui n'est peut-être pas ce que vous vouliez.
La principale confusion est liée au mot ROM qui signifie Read Only Memory . Le terme "mémoire en lecture seule" a été historiquement utilisé pour désigner la mémoire qui est permanente et ne peut pas être modifiée par l'utilisateur. Cependant, à mesure que la technologie a progressé, la définition de la ROM a changé et elle est maintenant souvent utilisée pour désigner une mémoire préprogrammée en usine et qui ne peut pas être facilement modifiée par l'utilisateur final. Mais si l'utilisateur a les compétences souhaitées et l'équipement spécialisé (par exemple, un programmeur), il peut reprogrammer la puce. Le nom ROM est resté, même si la définition a changé, comme une référence historique à l'objectif initial de la mémoire.
En appliquant une protection en écriture, certains types de ROM reprogrammables peuvent temporairement devenir une mémoire en lecture seule.
Ce ne sont PAS TOUS les types de mémoire non volatile existants, mais la plupart des plus populaires dont vous pourriez entendre parler par hasard. De nos jours, sur la plupart des cartes mères, ces puces sont fabriquées en utilisant la technologie NOR Flash .
L'exécution sur place (XIP) est une méthode qui permet au processeur d'exécuter du code directement à partir de la mémoire flash sans le copier d'abord dans la mémoire volatile (telle que la RAM ). Ceci est réalisé en mappant la mémoire flash dans l'espace d'adressage du processeur, de sorte que l'exécution du code puisse être effectuée directement à partir de la mémoire flash. Ainsi, le système est capable de commencer à exécuter le code dès que possible, sans avoir à attendre que la RAM soit initialisée en premier.
Attendez... le CPU peut communiquer avec BOOT ROM via le protocole SPI/Parallel/etc ? Bien sûr que non, il ne s'agit que de récupérer les instructions de la mémoire système, les requêtes vers cette région mémoire sont redirigées vers Intel Direct Media Interface (DMI ) ou AMD Infinity Fabric (IF) / Unified Media Interface (UMI) (prédécesseur). C'est le lien entre le CPU et le chipset de la carte mère. À ce stade, le décodage de l'adresse est effectué via des décodeurs situés dans le jeu de puces et les données de la puce sont renvoyées au processeur.
Lorsque la puce est fabriquée à partir de mémoire flash NOR, qui prend en charge les lectures à accès aléatoire, mais pas les écritures à accès aléatoire, un problème s'est posé. Tant que la mémoire inscriptible n'est pas disponible, tous les calculs doivent être effectués dans les registres du processeur. À ce stade, le code ne peut être écrit qu'en langage d'assemblage et tend à configurer l'environnement pour un langage de haut niveau (généralement, pour le langage C ). La raison en est que l'initialisation de la mémoire est devenue si complexe qu'il serait difficile d'écrire uniquement en assembleur. Étant donné que ces langages nécessitent au moins un tas et une pile, nous avons besoin de mémoire inscriptible. Certains processeurs ont de la SRAM intégrée dans la puce elle-même, mais une approche plus moderne consiste à utiliser la mémoire cache intégrée en tant que RAM (CAR) .
Le cache du processeur est une mémoire à grande vitesse qui stocke une copie des données et des instructions fréquemment utilisées à partir de la mémoire principale. Un cache est situé plus près du processeur et organisé en plusieurs niveaux (L1, L2, L3, ...), chaque niveau étant plus grand et plus lent que le précédent.
Si les données sont dans le cache, le processeur peut récupérer les données demandées dans le cache (c'est ce qu'on appelle un succès de cache ). Lorsque le cache du processeur est incapable de trouver les données requises, cela entraîne un échec du cache . Cela peut se produire soit parce que les données n'ont jamais été stockées dans le cache, soit parce que les données ont été précédemment stockées mais ont été supprimées du cache. Quoi qu'il en soit, le processeur doit aller jusqu'à la mémoire principale pour accéder aux données et les copier dans le cache.
L'éviction du cache est le processus de suppression des données du cache pour libérer de l'espace pour de nouvelles données. L'éviction des données peut être initiée soit par le système de mise en cache (généralement lorsqu'un cache est plein et que de nouvelles données doivent être stockées, ou lorsque la politique de durée de vie des données a expiré) ou par une demande explicite.
Cependant, si nous voulons utiliser le cache du processeur comme RAM , nous devons configurer le cache pour qu'il fonctionne en mode sans expulsion , également appelé mode sans remplissage . Cette technique empêche l'éviction due à un défaut de cache . Au lieu de cela, le cache est traité comme une SRAM normale et tous les accès (lecture/écriture) atteindront le cache et n'atteindront pas la mémoire principale. Le mode peut être activé à l'aide d'instructions CPU spécifiques au fournisseur.
En réalité, la BOOT ROM contient plusieurs types de firmware. Une fois qu'un groupe de micrologiciels est stocké dans la BOOT ROM, il doit être organisé d'une manière ou d'une autre pour les distinguer. Découvrons comment c'est fait.
À l'origine, le chipset effectue un mappage direct de l'intégralité du contenu de la BOOT ROM vers la mémoire (de 4 Go à 4 Go - 16 Mo). Généralement, si la BOOT ROM est inférieure à 16 Mo, le contenu est mappé à plusieurs reprises. Le CPU et le firmware peuvent lire/écrire sur la mémoire flash sans aucune restriction.
Le mode non-descripteur n'est plus pris en charge sur les nouveaux chipsets.
Finalement, dans l'ICH8, Intel introduit une disposition spéciale pour BOOT ROM. Le flash est divisé dans les régions suivantes :
Flash Descriptor (FD) - cette structure de données doit être située au début de l'appareil avec un décalage 0x10
. Il est composé de onze sections comme le montre la figure ci-dessous :
Le descripteur MAP a des pointeurs vers les autres régions et la taille de chacune également.
La section Composant contient des informations sur le(s) flash(s) du système (nombre de composants, densité de chacun, instructions non valides, etc.).
La section Master définit les autorisations de lecture/écriture pour les régions. En ce qui concerne la lecture/écriture, les autorisations doivent être définies sur Lecture seule, les informations stockées dans cette région ne peuvent être écrites que pendant le processus de fabrication.
Le descripteur Flash et Intel ME sont les seules régions requises.
Le FIT est une structure de données à l'intérieur de la région du BIOS et contient diverses entrées qui décrivent la configuration de la plate-forme. Chaque entrée du tableau a une taille de 16 octets. Le premier s'appelle l' en-tête FIT , l'autre s'appelle l' entrée FIT . Il est localisé par un pointeur FIT à une adresse physique 0xFFFFFFC0
(4 Go - 0x40).
Ces composants doivent être traités avant l'exécution de la première instruction CPU à partir du vecteur de réinitialisation . Les entrées incluent les mises à jour du microcode du processeur, l'ACM de démarrage, les politiques de démarrage de la plate-forme/TPM/BIOS/TXT et d'autres éléments. Mais au moins, le FIT doit inclure les entrées d'en-tête FIT et de mise à jour du microcode . Ainsi, l'usage courant de FIT est de mettre à jour le microcode avant d'exécuter le vecteur de réinitialisation .
Voici à quoi ressemble la carte mémoire :
Malheureusement, il y a beaucoup moins d'informations, je n'ai trouvé aucune documentation de chipset AMD divulguée avec des détails sur leur mise en page. Je ne peux donc pas vous dire mieux que ce que dit la documentation coreboot . Il est écrit sur la base de la documentation AMD qui n'est disponible que sous NDA.
En fait, il suffira de savoir que l'analogue AMD du descripteur Flash est Embedded Firmware Structure et qu'il contient des pointeurs vers la table de répertoire PSP , la table de répertoire BIOS et d'autres micrologiciels.
Si vous souhaitez voir comment la mémoire et le processeur modernes sont exactement initialisés, je dois vous contrarier. Intel et AMD ne sont pas pressés de publier le Silicon Initialization Code à la communauté. Dans la mesure où ces informations ne sont pas accessibles au public, elles offrent une distribution binaire du code d'initialisation de silicium nécessaire. Ceci doit être considéré comme une bibliothèque pour les développeurs de micrologiciels et contient du code binaire pour initialiser le contrôleur de mémoire, le chipset, le processeur et d'autres parties différentes du système.
Ce binaire peut être divisé en 4 composants :
Voici un référentiel de binaires Intel FSP publié par Intel que vous pouvez trouver sur leur GitHub. La spécification FSP v2.1 peut être obtenue sur le site Web d'Intel.
AGESA pour les produits antérieurs à la famille 17h est connu sous le nom de v5 ou Arch2008 . À cette époque, AGESA était open source et le code était disponible dans le référentiel coreboot (il était obsolète après la version 4.18). La spécification pour Arch2008 peut être trouvée sur le site Web d'AMD.
Avec l'introduction des produits de la famille 17h (microarchitecture Zen), AMD n'a pas publié de code source AGESA, uniquement des solutions binaires préconstruites. Un tel successeur s'appelle AGESA v9 et prend en charge la famille 17h et les versions ultérieures.
Il n'y a pas d'informations détaillées disponibles, seulement des nouvelles .
Une partie intégrante du processus de démarrage x86 moderne, sans lequel les cœurs x86 ne seraient jamais activés. Il est donc impossible de les désactiver complètement . Ces technologies sont responsables de l'initialisation du matériel, de la vérification de l'intégrité du système, de la gestion de l'alimentation et du lancement du processeur. Le micrologiciel de ces sous-systèmes est chargé et exécuté avant que le processeur principal ne commence à exécuter son propre micrologiciel. Un code sur de tels systèmes s'exécute indépendamment des cœurs de processeur de la plate-forme.
Tant que de nombreuses entreprises de matériel informatique ont intégré le principe de la sécurité par l'obscurité , ni le code source ni la documentation de ces sous-systèmes ne sont disponibles. Heureusement, nous savons comment cela affecte le processus de démarrage - voir Hardware Power Sequences .
Nous n'entrerons pas dans les détails, car il existe déjà de nombreux articles sur Internet rédigés par des chercheurs du monde entier. Mais je vais juste vous donner une brève description de ce que c'est.
Intel ME est un microprocesseur i486/80486 séparé intégré au chipset Intel (PCH) depuis 2008. Il possède sa propre RAM, une ROM intégrée, des ponts de bus vers tous les bus à l'intérieur du chipset (en conséquence, il peut accéder au réseau et même la RAM principale sur le CPU), et ainsi de suite. Exécute un système d'exploitation personnalisé basé sur MINIX.
AMD PSP est un cœur ARM reposant sur l'extension Trustzone, qui est insérée dans la matrice du processeur en tant que coprocesseur. Cette puce est intégrée à la plupart des plates-formes AMD depuis 2013. Exécute un système d'exploitation non documenté et propriétaire.
Ce processus, également connu sous le nom de Power On Sequence ou Power Sequencing , fournit un certain nombre de niveaux de tension dérivés et/ou de rails d'alimentation dans un ordre particulier nécessaire sur la plate-forme. En termes plus simples, il alimente un certain nombre de composants de la plate-forme dans un ordre spécifique. Le processus varie en fonction de la conception du système ou de la plate-forme, mais un PC standard comprend généralement les étapes suivantes :
Systèmes basés sur AMD (pour la famille 17h et versions ultérieures)
PSP s'exécute sur -chip BOOT ROM.
PSP localise le tableau des micrologiciels intégrés dans la ROM de démarrage hors puce et exécute le micrologiciel PSP.
PSP analyse la table de répertoire PSP pour trouver les étapes ABL et les exécute.
Les étapes ABL initialisent la mémoire principale, localisent l'image du BIOS dans la BOOT ROM et la chargent dans la DRAM (se décompresse si l'image est compressée).
Cette plate-forme n'a aucune raison d'utiliser CAR car la DRAM est déjà disponible et la PSP y charge l'image du firmware.
Après la première mise sous tension, le CPU fonctionne en mode réel . La plupart des registres ont des valeurs bien définies , y compris le pointeur d'instruction (IP), le segment de code (CS) et le cache de descripteur , qui est une copie de chaque descripteur de segment dans le processeur pour permettre un accès rapide à la mémoire de segment.
Le descripteur de segment est une entrée dans la table des descripteurs globaux (GDT) et contient l'adresse de base, la limite de segment et les informations d'accès (cette partie est ignorée car le mode réel n'a pas de contrôle d'accès comme le mode protégé). Au lieu d'accéder au GDT (qui est situé dans la mémoire) pour chaque accès à la mémoire, les informations sont stockées dans un cache de descripteurs.
Cependant, le GDT n'est pas impliqué en mode réel, donc le processeur génère des entrées en interne. Le registre du sélecteur CS, utilisé pour accéder au descripteur de segment, est chargé avec 0xF000
. L'adresse de base CS est initialisée à 0xFFFF_0000
. IP est initialisé à 0xFFF0
.
Par conséquent, le processeur commence à récupérer les instructions de la mémoire située à l'adresse physique 0xFFFF_FFF0
( 0xFFFF_0000
+ 0x0000_FFF0
). La première instruction exécutée à cette adresse est appelée le vecteur de réinitialisation .
REMARQUE : cette astuce vous donne accès à l'espace d'adressage élevé, cependant, vous ne pouvez pas accéder au code sous l'adresse 0xFFFF_0000
. L'adresse de base CS reste à cette valeur initiale jusqu'à ce que le registre du sélecteur CS soit chargé par le firmware. Cela peut être fait en exécutant un saut lointain .
À ce stade, la meilleure décision est de passer en mode protégé avec 4 Go d'adressabilité. Si le firmware ne le fait pas, pour que le mode réel fonctionne, le chipset doit être capable d'aliaser une plage de mémoire inférieure à 1 Mo à une plage équivalente juste en dessous de 4 Go. Certains chipsets n'ont pas cet aliasing et peuvent nécessiter de passer à un autre mode de fonctionnement avant d'effectuer le premier saut en longueur.
Je vous recommande de regarder la vidéo ci-dessous sur la séquence de mise sous tension, qui explique le processus en utilisant la carte mère ASUS P9X79 comme exemple. Malgré le fait qu'il soit en langue russe, vous pourrez tout comprendre si vous activez les sous-titres anglais générés automatiquement.
Cet article a fourni de nombreuses informations théoriques sur le fonctionnement du démarrage. Cependant, pour vraiment comprendre ce processus, nous devons examiner de plus près le code source et l'architecture du micrologiciel existant.
Dans le prochain article, nous approfondirons le BIOS , l'UEFI et le coreboot pour les examiner en détail.