Je sais que le BIOS charge sa première instruction à partir de 0xFFFFFFF0, mais pourquoi cette adresse spécifique? J'ai de nombreuses questions et j'espère que vous pourrez m'aider avec au moins certaines d'entre elles.
Mes questions:
J'ai lu à ce sujet cet après-midi et je ne comprends toujours pas.
0xFFFFFFF0
est l'endroit où un processeur compatible x86 commence à exécuter des instructions à la mise sous tension. Il s’agit d’un aspect câblé, non modifiable (sans matériel supplémentaire) de la CPU et différents types de CPU se comportent différemment.
Pourquoi la première instruction du BIOS se situe-t-elle au sommet d'une RAM de 4 Go?
Il est situé au "sommet" de 4 Go espace d'adressage - et à la mise sous tension du BIOS ou UEFI ROM est configuré pour répondre aux lectures de ces adresses.
Ma théorie sur pourquoi c'est:
À peu près tout dans la programmation fonctionne mieux avec des adresses contiguës. Le concepteur de la CPU ne sait pas ce qu'un constructeur de système voudra faire avec la CPU. Il est donc déconseillé pour la CPU d'exiger que les adresses situées au milieu de l'espace soient utilisées à des fins diverses. Il est préférable de garder cela "à l'écart" en haut ou en bas de l'espace d'adressage. Bien sûr, gardez à l'esprit que cette décision a été prise lorsque le 8086 était nouveau, et qu'il n'avait pas de signe MMU .
Dans le 8086, des vecteurs d'interruption existaient à l'emplacement de mémoire 0 et supérieur. Les vecteurs d'interruption doivent se trouver à des adresses connues et doivent être placés dans RAM pour plus de souplesse - mais le concepteur de la CPU ne pouvait pas savoir combien de RAM allait être dans un système. Donc, partir de 0 et travailler vers le haut était logique pour ceux-ci (car aucun système en 1978, lorsque le 8086 a été inventé, n'aurait 4 Go de RAM - donc attendre que RAM soit à 0xFFFFFFF0 n'était pas bonne idée), puis ROM devra se trouver à la limite supérieure.
Bien sûr, à partir d’au moins 80286, les vecteurs d’interruption pourraient être déplacés vers un emplacement de départ différent de 0, mais les processeurs modernes 64 bits x86 démarrent toujours en mode 8086, de sorte que tout fonctionne toujours à l’ancienne pour des raisons de compatibilité (aussi ridicule que possible). comme il semble en 2015 avoir encore besoin de votre processeur x86 pour pouvoir exécuter DOS).
Ainsi, étant donné que les vecteurs d'interruption commencent à 0 et vont vers le haut, ROM devrait commencer par le haut et aller vers le bas.
Que se passerait-il si mon ordinateur ne disposait que de 1 Go de RAM?
Une CPU 32 bits a 4 294 967 296 adresses numérotées de 0 (0x00000000) à 4294967295 (0xFFFFFFFF). ROM peut habiter certaines adresses et RAM peut habiter d'autres. Avec la MMU de la CPU, vous pouvez même l'activer à la volée. RAM n'a pas à vivre à toutes les adresses.
Avec seulement 1 Go de RAM, certaines adresses n’auront rien à répondre lorsqu’elles seront lues ou écrites. Cela peut entraîner la lecture de données non valides lors de l'accès à de telles adresses ou le blocage du système.
Qu'en est-il des systèmes avec plus de 4 Go de RAM (par exemple: 8 Go, 16 Go, etc.)?
Tout cela reste simple: les processeurs 64 bits ont plus d'adresses (ce qui les rend par exemple 64 bits - par exemple, 0x0000000000000000 à 0xFFFFFFFFFFFFFFFFFF), donc le supplément RAM "convient". En supposant que la CPU soit en mode long . Jusque-là, le RAM est là, mais pas adressable.
Pourquoi la pile est-elle initialisée avec une valeur (dans ce cas, une valeur située à 0xFFFFFFF0)?
Je ne trouve rien immédiatement sur quoi x86 attribue le pointeur de pile à la mise sous tension, mais il devrait éventuellement être réaffecté par une routine d'initialisation de toute façon une fois que cette routine découvre combien RAM se trouve dans le système. . (@Eric Towers dans les commentaires ci-dessous indique qu'il est défini sur zéro lors de la mise sous tension.)
Il n'est pas situé au sommet de la RAM; il se trouve dans ROM dont l'adresse se situe en haut de l'espace d'adressage de la mémoire, ainsi que toute mémoire sur des cartes d'extension, telles que les contrôleurs Ethernet. Il est là pour éviter tout conflit avec la RAM, du moins jusqu'à ce que vous ayez 4 Go installés. Les systèmes dotés de 4 Go ou plus de RAM peuvent faire deux choses pour résoudre le conflit. Les cartes mères bon marché ignorent tout simplement les parties de RAM qui entrent en conflit avec l'emplacement de la ROM. Les plus honnêtes remappent que RAM semble avoir une adresse supérieure à 4 Go.
Je ne suis pas sûr de ce que vous demandez à propos de la pile. Ce n'est certainement pas initialisé pour être en ROM. Lorsque la CPU se réinitialise, elle passe initialement en "mode réel", où elle agit comme le 8086 d'origine et utilise un adressage segmenté de 16 bits, ne lui permettant d'accéder qu'à 1 Mo de mémoire. Le code du BIOS est situé en haut de ce 1 MB. Le BIOS choisit quelque part dans RAM pour configurer la pile, puis charge et exécute le premier secteur du premier lecteur amorçable. Il appartient au système d'exploitation de passer en mode 32 ou 64 bits une fois qu'il prend le relais et configure ses propres piles (une par tâche/thread).
Tout d’abord, cela n’a vraiment rien à voir avec la RAM. Nous parlons ici d’espace d’adresse - même si vous n’avez que 16 Mo de mémoire, vous disposez toujours des 32 bits d’espace adresse sur 32 bits. -bit CPU.
Cela répond déjà à votre première question. En fait, au moment de sa conception, les PC du monde réel n’avaient aucune mémoire proche des 4 GiB de mémoire; ils étaient plus dans la gamme de 1-16 Mio de mémoire. L'espace d'adressage était, à toutes fins pratiques, gratuit.
Maintenant, pourquoi 0xFFFFFFF0 exactement? Le processeur ne sait pas quelle quantité de BIOS il y a. Certains BIOS peuvent ne prendre que quelques kilo-octets, alors que d'autres peuvent occuper tout un mégaoctet de mémoire - et je n'entre même pas dans les différentes mémoires RAM optionnelles. Le processeur doit être câblé à une adresse quelconque pour commencer - il n'y a pas de configuration pour configurer le processeur. Mais il ne s'agit que d'un mappage de l'espace d'adressage - l'adresse est mappée directement dans la puce BIOS ROM (oui, cela signifie que vous n'avez pas accès à l'intégralité de 4 GiB de RAM à ce stade, si vous en avez beaucoup - mais cela n'a rien de spécial, de nombreux périphériques ont besoin de leur propre plage d'adresses). Sur un processeur 32 bits, cette adresse vous donne 16 octets complets pour effectuer l’initialisation très basique - ce qui suffit pour configurer vos segments et, si nécessaire, le mode adresse (rappelez-vous, x86 démarre en mode réel 16 bits - l’espace adresse n'est pas plat) et faites un saut vers la "procédure" de démarrage real . À ce stade, vous n'utilisez pas du tout RAM - tout est simplement une ROM mappée. En fait, RAM n'est même pas prêt à être utilisé à ce stade - c'est l'une des tâches du BIOS POST! Vous vous demandez peut-être comment un mode réel de 16 bits peut accéder à l'adresse 0xFFFFFFF0? Bien sûr, il y a des segments, vous avez donc un espace d'adressage de 20 bits, mais cela ne suffit toujours pas. Eh bien, il y a une astuce: les 12 bits de poids fort de l'adresse sont définis jusqu'à ce que vous exécutiez votre premier saut en longueur, ce qui vous donne accès à l'espace d'adressage en hauteur (tout en refusant l'accès à un élément inférieur à 0xFFF00000 - jusqu'à ce que vous exécutiez un saut en longueur) .
Tous ces éléments sont essentiellement masqués par les programmeurs (sans parler des utilisateurs) sur les systèmes d'exploitation modernes. Vous n’avez généralement accès à aucun niveau aussi bas - certaines choses sont déjà irrécupérables (vous ne pouvez pas changer de mode de processeur à tout moment), d’autres sont traitées exclusivement par le noyau du système d’exploitation.
Donc, une vue plus agréable vient du codage old-school sous MS DOS. Un autre exemple typique de mappage direct de la mémoire de périphérique sur un espace d'adressage est l'accès direct à la mémoire vidéo. Par exemple, si vous voulez écrire rapidement du texte sur l’affichage, vous écrivez directement à l’adresse B800:0000
(plus décalage - en mode texte 80x25, cela signifie (y * 80 + x) * 2
si ma mémoire est exacte - deux octets par caractère, ligne par ligne). Si vous vouliez dessiner pixel par pixel, vous utilisiez un mode graphique et l'adresse de début A000:0000
(généralement 320x200 à 8 bits par pixel). Faire quelque chose de très performant signifiait généralement plonger dans les manuels des appareils pour trouver comment y accéder directement.
Cela survit à ce jour - c'est juste caché. Sous Windows, vous pouvez voir les adresses de mémoire mappées aux périphériques dans le Gestionnaire de périphériques. Ouvrez simplement les propriétés de votre carte réseau, allez à l'onglet Ressources. Tous les éléments de la plage de mémoire sont des mappages de la mémoire du périphérique sur votre espace d'adressage principal. Et sur 32 bits, vous verrez que la plupart de ces périphériques sont mappés au-dessus de la marque 2 GiB (3 GiB plus tard) - encore une fois, afin de minimiser les conflits avec la mémoire utilisable par l'utilisateur, bien que ce ne soit pas vraiment le cas. un problème avec la mémoire virtuelle (les applications ne s'approchent d'aucun espace d'adressage réel , matériel - elles ont leur propre bloc de mémoire virtualisé, qui peut être mappés sur la RAM, la ROM, les périphériques ou le fichier de page, par exemple).
Pour ce qui est de la pile, cela devrait aider à comprendre que par défaut, la pile se développe à partir du haut. Donc, si vous faites une Push
, le nouveau pointeur de pile sera à 0xFFFFFEC
- en d’autres termes, vous n’essayez pas d’écrire sur l’adresse d’initialisation du BIOS :) Cela signifie bien entendu que les routines d’initialisation du BIOS peuvent utiliser la pile en toute sécurité, avant remapper dans un endroit plus utile. Dans la programmation traditionnelle, avant que la pagination ne devienne la valeur par défaut, la pile commençait généralement à la fin de la mémoire vive et un "débordement de pile" se produisait lorsque vous commenciez à écraser la mémoire de votre application. La protection de la mémoire a beaucoup changé, mais en général, elle maintient la compatibilité ascendante autant que possible. Notez que même le processeur le plus moderne x86-64 peut toujours démarrer MS DOS 5 - ou comment Windows peut toujours exécuter de nombreuses applications DOS qui n’ont aucune idée de la pagination.
En plus des autres points mentionnés, il peut être utile de comprendre ce qu'est une adresse . Tandis que les architectures récentes compliquent les choses, une machine publiait à chaque cycle de mémoire l’adresse désirée sur 20 à 32 fils (selon l’architecture, avec quelques astuces spéciales pour noter si elle nécessitait une paire ou quatre octets simultanément); diverses parties du système de mémoire examineraient l'état de ces fils et s'activeraient lorsqu'elles verraient certaines combinaisons de valeurs hautes et basses.
Si une machine avec 32 fils d’adresse ne devait utiliser que 1 Mo de RAM et 64 Ko de ROM [tout à fait plausible pour certains contrôleurs intégrés], elle pourrait activer le RAM pour toutes les adresses où le fil d’adresse supérieur était bas et le ROM pour toutes les adresses où il était haut. Les 20 fils d’adresse du bas seraient alors liés au RAM pour sélectionner l’un des 1 048 576 octets et le 16 inférieur serait également relié au ROM, pour en sélectionner l’un des 65 536 octets. Les 11 fils d’adresse restants ne seraient tout simplement pas connectés à quoi que ce soit.
Sur une telle machine, les accès aux adresses 0x00100000-0x001FFFFF seraient équivalents aux accès à RAM adresses 0x00000000-0x000FFFFF. De même avec les adresses 0x000200000-0x0002FFFFF ou 0x7FF00000-0x7FFFFFFFF. Les adresses supérieures à 0x80000000 liraient toutes en ROM, avec un modèle 64K répété dans tout l'espace.
Même si le processeur dispose d'un espace d'adressage de 4 294 967 296 octets, il n'est pas nécessaire que le matériel reconnaisse autant d'adresses distinctes. Placer le vecteur de réinitialisation près du haut de l’espace adresse est une conception qui fonctionnera bien quel que soit le nombre ou le peu de RAM et ROM du système et évite le décodage complet. l'espace d'adressage.
Mon cas est parce que nous utilisons la logique négative le numérique (1) n'est pas du tout tension (O volts). Nous n'avons qu'à mettre la tension sur les 4 derniers bits à l'initialisation pour que le compteur de programme (ou le pointeur Instruction) soit à 1111 1111 1111 1111 1111 1111 1111 0000. Nous n'avons pas à nous adresser aux 28 bits supérieurs, car la plupart des processeurs (anciens) avaient 16 bits et les nœuds inférieurs pouvaient être adressés par une puce d'adresse autrefois. Maintenant que nous avons 64 bits avec compatibilité à 32 bits et 32 bits à 16 bits, la méthode matérielle a été améliorée mais la méthode reste en place. De plus, les bioses ne sont pas toujours programmées sur 64 ou 32 bits. Mon opinion est également puisque les souvenirs ne sont pas toujours les mêmes, le bios doit être situé sur le même segment. La façon dont nous abordons le bios n’est pas la vraie adresse tout le temps. Juste un appris de moi ...
lors de la réinitialisation, un processeur compatible 8088/8086 exécute les instructions à 0FFFF0, soit 16 octets sous la limite de 1 mégaoctet. Normalement, le ROM situé à cet emplacement (dans les implémentations de PC) serait le BIOS. Ainsi, à la fin de la ROM du BIOS, il y a un saut au début de la ROM du BIOS.
montré ici: vecteur de départ et signature 'date' derrière, BIOS 5150 d'IBM 5150 PC 8KB date du: 19/10/1981
00001FEE FF db 0xff
00001FEF FF db 0xff
00001FF0 EA5BE000F0 jmp Word 0xf000:0xe05b
00001FF5 3130 xor [bx+si],si
00001FF7 2F das
00001FF8 3139 xor [bx+di],di
notez que l'adressage correspond à une rom de 8KB, ce qui place l'adresse de départ (le JMP absolu, à n'importe quel autre emplacement, dans ce cas dans la rom de 8KB elle-même, mais pas à l'adresse la plus basse possible dans cette rom) à $ FFFF: Segmenté à 0 $ ou linéaire FFFF0.
en ce qui concerne la compatibilité: si un processeur "futur" ou actuel "s'attend" à ce qu'il ait beaucoup plus de F devant l'adresse, cela n'a pas d'importance. pour la compatibilité des processeurs les plus récents dans les systèmes plus anciens, les lignes d’adresse supplémentaires ne sont pas connectées et les données sur le bus de données sont donc exactement les mêmes. tant que les bits les moins significatifs restent FFFF0.
(Dans un système avec seulement 1 Mo de RAM et la ROM située à la fin de celui-ci, rien de plus, il sera heureux de penser qu'il parle à l'adresse la plus élevée tout en obtenant exactement les mêmes données, car ces implémentations n'ont jamais entendu parler de lignes d'adresse supérieures à A19)
notez que le monde n’est pas que des "ordinateurs" ... l’ordinateur IBM était un "accident", ces processeurs n’ont jamais été spécifiquement conçus pour les "ordinateurs" et représentent bien plus que de simples ordinateurs (tels que systèmes d'armes, etc.). Les modes protégés 32 et 64 bits ne sont généralement pas souhaités. (Le mode virtuel 8086 est beaucoup plus intéressant en tant que raison de choisir une version plus récente (386+) par exemple). par conséquent, la "compatibilité ascendante" comporte bien plus que la simple exécution.
La carte mère veille à ce que l'instruction du vecteur de réinitialisation corresponde à un saut vers l'emplacement de mémoire mappé sur le point d'entrée du BIOS. Ce saut efface implicitement l'adresse de base cachée présente à la mise sous tension. Tous ces emplacements de mémoire ont le bon contenu nécessaire à la CPU grâce à la carte mémoire conservée par le chipset. Ils sont tous mappés sur une mémoire flash contenant le BIOS car à ce stade, les modules RAM ont une merde aléatoire.