Je suis vraiment curieux en ce moment. Je suis un programmeur Python, et cette question m’a complètement échappé: vous écrivez un système d’exploitation. Comment le dirigez-vous? Il doit être exécuté d'une manière ou d'une autre, et cette manière est dans un autre OS?
Comment une application peut-elle s'exécuter sans être dans un système d'exploitation? Comment pouvez-vous dire à l'ordinateur d'exécuter, par exemple, C, et d'exécuter ces commandes à l'écran, s'il ne dispose pas d'un système d'exploitation à exécuter?
Est-ce que cela a à voir avec un noyau UNIX? Si oui, qu'est-ce qu'un noyau Unix, ou un noyau en général?
Je suis sûr que les OS sont plus compliqués que ça, mais comment ça marche?
kernel
operating-systems
Thor Correia
la source
la source
Réponses:
De nombreux sites Web passent par le processus de démarrage (tel que Comment les ordinateurs démarrent- ils ). En un mot, il s’agit d’un processus en plusieurs étapes qui construit progressivement le système jusqu’à ce qu’il puisse enfin démarrer les processus du système d’exploitation.
Cela commence par le firmware de la carte mère qui tente de mettre le processeur en marche. Il charge ensuite le BIOS, qui est comme un mini système d’exploitation qui permet à l’autre matériel de fonctionner correctement. Une fois que cela est fait, il cherche un périphérique de démarrage (disque, CD, etc.) et, une fois trouvé, il localise le MBR (Master Boot Record), le charge en mémoire et l'exécute. C'est ce petit morceau de code qui sait ensuite comment initialiser et démarrer le système d'exploitation (ou d'autres chargeurs de démarrage au fur et à mesure que les choses se compliquent). C'est à ce stade que des éléments comme le noyau seraient chargés et commenceraient à s'exécuter.
C'est assez incroyable que ça marche du tout!
la source
Un système d'exploitation "nu-metal" ne fonctionne dans rien. Il exécute le jeu d'instructions complet sur la machine physique et a accès à l'ensemble de la mémoire physique, à tous les registres de périphérique et à toutes les instructions privilégiées, y compris celles contrôlant le matériel de prise en charge de la mémoire virtuelle.
(Si le système d'exploitation s'exécute sur une machine virtuelle, il peut penser qu'il se trouve dans la même situation que celle décrite ci-dessus. La différence est que certaines choses sont émulées ou gérées d'une autre manière par l'hyperviseur, c'est-à-dire le niveau d'exécution des machines virtuelles. .)
Quoi qu’il en soit, bien que le système d’exploitation puisse être implémenté en C, par exemple, il ne disposera pas de toutes les bibliothèques C normales. En particulier, il n'aura pas les bibliothèques normales 'stdio'. Au lieu de cela, il implémentera (par exemple) un pilote de périphérique de disque lui permettant de lire et d'écrire des blocs de disque. Il implémentera un système de fichiers au-dessus de la couche de bloc de disque et implémentera les appels système que les bibliothèques d'exécution d'une application utilisateur lancent (par exemple) pour créer, lire et écrire des fichiers ... et ainsi de suite.
Il doit s'agir d'un type d'application particulier (par exemple, un système d'exploitation) capable d'interagir directement avec le matériel d'E / S, etc.
Vous ne.
L'application (qui servait d'argument écrit en C) est compilée et liée sur un autre ordinateur pour donner une image en code natif. L'image est ensuite écrite sur le disque dur à un endroit où le BIOS peut la trouver. Le BIOS charge l’image en mémoire et exécute une instruction pour accéder au point d’entrée de l’application.
Il n'y a (généralement) pas de "C en cours d'exécution et d'exécution de commandes" dans l'application, sauf s'il s'agit d'un système d'exploitation complet. Et dans ce cas, il incombe au système d'exploitation de mettre en œuvre toute l'infrastructure requise pour y parvenir. Pas de magie. Juste beaucoup de code.
La réponse de Bill couvre l' amorçage qui est le processus dans lequel vous passez d'un ordinateur éteint à un ordinateur sur lequel le système d'exploitation normal est opérationnel. Cependant, il convient de noter que lorsque le BIOS termine ses tâches, il (généralement) donne le contrôle total du matériel au système d'exploitation principal et ne joue aucun autre rôle - jusqu'au prochain redémarrage du système. Le système d'exploitation principal ne fonctionne certainement pas "au sein" du BIOS au sens conventionnel.
Oui.
Le noyau UNIX est le noyau du système d'exploitation UNIX. C’est la partie d’UNIX qui exécute tout le «métal nu» décrit ci-dessus.
L'idée d'un "noyau" est que vous essayez de séparer le logiciel système en éléments essentiels (nécessitant un accès à un périphérique physique, toute la mémoire, etc.) et des éléments non essentiels. Le noyau est constitué du noyau.
En réalité, la distinction entre noyau / noyau et non-noyau / non-cœur est plus compliquée que cela. Et il y a eu beaucoup de débats sur ce qui appartient vraiment au noyau et ce qui ne l’est pas. (Recherchez le micro-noyau par exemple.)
la source
The idea of a "kernel" is that you try to separate the system software into core stuff
Facile à retenir en notant que le termekernel
vient de l'allemandKern
, qui signifie noyau / noyau.Au début, il n'y avait pas de courant dans la CPU.
Et l'homme a dit "qu'il y ait du courant", et la CPU a commencé à lire une adresse donnée en mémoire et à exécuter l'instruction qui y était présente. Puis le suivant et ainsi de suite jusqu'à la fin du pouvoir.
C'était le démarrage. Sa tâche consistait à charger un autre logiciel pour accéder à l'environnement où se trouvait le logiciel principal et à le charger.
Enfin, un écran convivial vous invite à vous connecter.
la source
0x7C00
concerne toutesx86
les architectures compatibles et doit d'abord être renseignée par le BIOS, qui charge généralement le premier secteur de tout périphérique amorçable qu'il préfère ... Bonne réponse cependant: -7Désolé d'être en retard, mais je vais le décrire comme tel:
La carte mère est alimentée.
Les circuits de synchronisation démarrent et se stabilisent si nécessaire, en se basant uniquement sur leurs caractéristiques électriques. Certains appareils plus récents peuvent en fait utiliser un microprocesseur ou un séquenceur très limité.
- jkerian à 5h20 le 25 octobre
Le processeur et la RAM sont alimentés.
La CPU charge (en fonction de son câblage interne) les données du BIOS. Sur certaines machines, le BIOS peut être mis en miroir dans la RAM, puis exécuté à partir de là, mais cela est rare, l’IIRC.
-Micheal Steil, 17 erreurs Microsoft commises dans le système de sécurité Xbox ( archive )
Le BIOS appelle les ports matériels et les adresses utilisées par la carte mère pour les E / S de disque et autres matériels. Il fait tourner les disques et fait fonctionner le reste de la RAM, entre autres.
Le code du BIOS (au moyen des paramètres CMOS, stockés dans le matériel) utilise des commandes IDE ou SATA de bas niveau pour lire le secteur de démarrage de chaque disque, dans un ordre spécifié par le CMOS ou un remplacement par un menu.
Le premier disque avec un secteur de démarrage fait exécuter son secteur de démarrage. Ce secteur de démarrage est l’Assemblée qui a pour instructions de charger plus de données à partir du disque, de charger une plus grande
NTLDR
, des étapes ultérieuresGRUB
, etc.Enfin, le code machine du système d'exploitation est exécuté par le chargeur de démarrage, directement ou indirectement via le chargement en chaîne, chargeant un secteur de démarrage à partir d'un emplacement alternatif ou offset.
Vous obtenez alors une panique amicale du noyau, un pingouin étouffé ou votre disque s’arrête de bouger en raison d’un crash de la tête. =) Dans le scénario alternatif, votre noyau configure des tables de processus, des structures en mémoire et monte des disques, charge des pilotes, des modules et une interface graphique ou un ensemble de services (s’il se trouve sur un serveur). Ensuite, les programmes sont exécutés au fur et à mesure que leurs en-têtes sont lus, et leur assemblage est mis en mémoire et mappé en conséquence.
la source
Il y a beaucoup de bonnes réponses mais je voulais ajouter ceci: vous avez mentionné que vous venez d'un contexte Python. Python est un langage ninterpreted (ou "interpiled" ou autre, du moins dans les cas d'utilisation typiques de CPython). Cela signifie que d'autres logiciels (l'interpréteur Python) examinent le code source et l'exécutent d'une manière ou d'une autre. C’est un bon modèle qui permet de jolis langages de haut niveau bien abstraits du matériel actuel. L'inconvénient est que vous avez toujours besoin de ce logiciel d'interprétation en premier.
Un tel logiciel d'interprétation est généralement écrit dans un langage qui compile en code machine, par exemple C ou C ++. Le code machine est ce que le processeur peut gérer. Ce qu'un processeur peut faire, c'est lire quelques octets dans la mémoire et, en fonction des valeurs d'octet, lancer une opération spécifique. Donc une séquence d'octets est une commande pour charger des données de la mémoire dans un registre, une autre séquence pour ajouter deux valeurs, une autre pour stocker la valeur d'un registre dans la mémoire principale et bientôt (un registre est une zone de mémoire spéciale qui fait partie du processeur où cela peut fonctionner le mieux), la plupart de ces commandes sont assez faibles à ce niveau. Le code assembleur est lisible par l'homme pour ces instructions de code machine. Ce code machine correspond en gros à ce qui est stocké dans les fichiers .exe ou.com sous Windows ou à l’intérieur des fichiers binaires Linux / Unix.
Maintenant, si un ordinateur est démarré, il est stupide, mais il possède un câblage qui lira de telles instructions de code machine. Sur un PC, il s’agit généralement (actuellement) d’une puce EEPROM sur la carte mère contenant le BIOS (système d’inputs de base), ce système ne peut pas faire grand chose, il peut faciliter l’accès à certains matériels, puis effectuer une opération de clé: démarrez et copiez les premiers octets (c’est-à-dire l’enregistrement de démarrage principal, MBR) dans la mémoire, puis indiquez à la CPU "ici, voici votre programme", la CPU traitera alors ces octets en tant que code machine et l’exécutera. Il s’agit généralement d’un chargeur de système d’exploitation chargé de charger certains paramètres dans le noyau, puis de céder le contrôle à ce noyau, qui charge ensuite tous ses drivers pour accéder à tout le matériel, charger un programme de bureau ou shell ou autre et permettre à l’utilisateur de se connecter utiliser le système.
la source
Vous demandez "Comment une application peut-elle s'exécuter sans être dans un système d'exploitation". La réponse facile est "un OS n'est pas une application". Bien qu'un système d'exploitation puisse être créé avec les mêmes outils qu'une application et fabriqué à partir de la même matière première, ils ne sont pas la même chose. Un système d'exploitation ne doit pas nécessairement respecter les mêmes règles qu'une application.
OTOH, vous pouvez considérer le matériel et le micrologiciel réels comme le "système d'exploitation" dans lequel "l'application" du système d'exploitation s'exécute. Le matériel est un système d’exploitation très simple: il sait comment exécuter les instructions écrites dans le code machine et sait qu’au démarrage, il doit rechercher une adresse mémoire très spécifique pour sa première instruction. Ainsi, il démarre et exécute immédiatement cette toute première instruction, suivie de la seconde, etc.
Ainsi, le système d'exploitation est simplement un code machine qui existe à un emplacement connu et qui peut interagir directement avec le matériel.
la source
Pour répondre à votre question, vous devez connaître l’aspect du code natif (pour le processeur) et son interprétation par celui-ci.
En général, le processus de compilation consiste à traduire les éléments que vous écrivez en C, Pascal ou même en Python (avec pypy) et C # en éléments compris par le CPU, c.-à-d. et ebx "," call function foo "," comparez eax à 10 ". Ces instructions, exécutées une à une, font ce que vous vouliez faire avec votre code.
Pensez maintenant à ceci: vous n'avez pas vraiment besoin d'un système d'exploitation pour exécuter ce code natif! Tout ce dont vous avez besoin est de charger ce code en mémoire et d'indiquer au processeur qu'il est là et que vous voulez qu'il soit exécuté. Ne vous inquiétez pas trop de cela, cependant. C’est le travail qui devrait préoccuper le BIOS: il charge votre code (un et un secteur seulement), juste après le démarrage du processeur, sous l’adresse physique 0x7C00. Ensuite, la CPU commence à exécuter ce secteur (512 B) de votre code. Et vous pouvez faire ce que vous imaginez! Sans, bien sûr, aucun support de l'OS. C'est parce que VOUS êtes le système d'exploitation. Cool hein? Pas de bibliothèque standard, pas de boost, pas de python, pas de programmes, pas de pilotes! Vous devez tout écrire par vous-même.
Et comment communiquez-vous avec le matériel? Eh bien, vous avez deux choix:
Maintenant vous demandez ce qu'est le noyau. En bref, le noyau est tout ce que vous ne voyez pas et ne faites pas l'expérience directe. Il gère, avec les pilotes, tout, de votre clavier à presque tous les éléments matériels de votre PC. Vous communiquez avec lui par shell graphique ou terminal. Ou par des fonctions dans votre code, maintenant exécutées, heureusement, avec le support du système d'exploitation.
Pour une meilleure compréhension, je peux vous donner un conseil: essayez d’écrire votre propre système d’exploitation. Même si ça va écrire "Hello world" sur l'écran.
la source
Le fonctionnement d’un système d’exploitation dépend énormément de certaines différences. Pour être utile, un système doit avoir un comportement prévisible au démarrage, tel que "démarrer l'exécution à l'adresse X". Pour les systèmes dont la mémoire non volatile (telle que la mémoire flash) est mappée dans leur espace programme, cela est assez facile car vous devez simplement vous assurer que le code de démarrage est bien placé dans l’espace programme du processeur. Ceci est extrêmement courant pour les microcontrôleurs. Certains systèmes doivent extraire leurs programmes de démarrage d'un autre emplacement avant de les exécuter. Certaines opérations seront câblées (ou presque) dans ces systèmes. Certains processeurs récupèrent leur code de démarrage via i2c à partir d’une autre puce,
Les systèmes utilisant la famille de processeurs x86 utilisent généralement un processus de démarrage en plusieurs étapes assez complexe en raison de son évolution et de problèmes de compatibilité ascendante. Le système exécute un micrologiciel (appelé BIOS - Système d’entrée / sortie de base ou similaire) qui se trouve dans une mémoire non volatile de la carte mère. Parfois, tout ou partie de ce microprogramme est copié (déplacé) dans la RAM pour le rendre plus rapide à exécuter. Ce code a été écrit en sachant quel matériel serait présent et utilisable pour le démarrage.
Le microprogramme de démarrage est généralement écrit avec des hypothèses sur le matériel qui sera présent sur le système. Il y a des années, sur une machine 286, on pourrait probablement supposer qu'il y aurait un contrôleur de lecteur de disquette à l'adresse d'E / S X et que le secteur 0 serait chargé dans un certain emplacement de mémoire s'il recevait un certain jeu de commandes (et le code du secteur 0). sait comment utiliser les propres fonctions du BIOS pour charger plus de code, et finalement assez de code pour être un système d'exploitation est chargé). Sur un microcontrôleur, on peut supposer qu’un port série fonctionnant avec certains paramètres doit attendre des commandes (pour mettre à jour un microprogramme plus complexe) pendant une durée X avant de poursuivre le processus de démarrage.
Le processus de démarrage exact d’un système donné n’est pas aussi important pour vous que de savoir qu’il diffère d’un système à l’autre, mais aussi qu’ils ont tous des choses en commun. Souvent, dans le code de démarrage (démarrage), lorsqu'une opération d'E / S doit être effectuée, les périphériques d'E / S sont interrogés au lieu de compter sur des interruptions. En effet, les interruptions sont complexes, utilisez la RAM de pile (qui peut ne pas être entièrement configurée pour le moment) et vous n'avez pas à craindre de bloquer d'autres opérations lorsque vous êtes la seule.
Lors du premier chargement, le noyau du système d'exploitation (le noyau est la partie principale de la plupart des systèmes d'exploitation) agira initialement beaucoup comme le microprogramme. Il devra soit être programmé en fonction de la connaissance du matériel présent, soit configurer celle-ci, configurer une certaine RAM en tant que pile, effectuer divers tests, configurer diverses structures de données, éventuellement détecter et monter un système de fichiers, puis lancer probablement un programme plus performant. comme les programmes que vous avez l'habitude d'écrire (un programme qui repose sur la présence d'un système d'exploitation).
Le code OS est généralement écrit dans un mélange de C et d’assemblage. Le tout premier code pour le noyau du système d'exploitation est probablement toujours en cours d'assemblage et effectue des tâches telles que la configuration de la pile, sur laquelle le code C s'appuie, puis appelle une fonction C. D'autres assemblages écrits à la main y figureront également, car certaines opérations qu'un système d'exploitation doit effectuer ne sont souvent pas exprimables en C (comme le changement de contexte / l'échange de piles). Des indicateurs spéciaux doivent souvent être transmis au compilateur C pour lui dire de ne pas s'appuyer sur les bibliothèques standard utilisées par la plupart des programmes C et de ne pas s'attendre à ce qu'il y ait une
int main(int argc, char *argv[])
dans le programme. De plus, des options spéciales de l'éditeur de liens que la plupart des programmeurs d'applications n'utilisent jamais doivent être utilisées. Celles-ci peuvent donner l’impression que le programme du noyau sera chargé à une certaine adresse ou qu’il semblerait qu’il existe des variables externes à certains emplacements, même si ces variables n’ont jamais été déclarées dans un code C (cela est utile pour les entrées / sorties mappées en mémoire). autres emplacements de mémoire spéciaux).Toute l'opération semble magique au début, mais une fois que vous avez bien compris et compris certaines de ses facettes, la magie devient simplement un ensemble de programmes nécessitant beaucoup plus de planification et de connaissances système à mettre en œuvre. Le débogage, cependant, prend de la magie.
la source
Pour comprendre le fonctionnement des systèmes d'exploitation, il peut être utile de les diviser en deux catégories: celles qui fournissent simplement des services aux applications à la demande et celles qui utilisent des fonctionnalités matérielles dans le processeur pour empêcher les applications de faire ce qu'elles ne devraient pas. MS-DOS était du style précédent; toutes les versions de Windows depuis la version 3.0 ont été ce dernier style (du moins lorsqu’on utilise quelque chose de plus puissant qu'un 8086).
Le PC IBM original exécutant PC-DOS ou MS-DOS aurait été un exemple de l'ancien style de "système d'exploitation". Si une application souhaitait afficher un caractère à l'écran, il y aurait eu plusieurs façons de le faire. Il pourrait appeler la routine qui demanderait à MS-DOS de l'envoyer à la "sortie standard". Si tel était le cas, MS-DOS vérifierait si la sortie était redirigée et sinon, il appellerait une routine stockée dans la ROM (dans un ensemble de routines IBM appelé système d'entrée / sortie de base) qui afficherait un caractère position du curseur et déplacez le curseur ("write teletype"). Cette routine BIOS stockerait alors une paire d'octets quelque part dans la plage 0xB800: 0 à 0xB800: 3999; Le matériel de l'adaptateur graphique couleur récupère de manière répétée des paires d'octets dans cette plage, utiliser le premier octet de chaque paire pour sélectionner une forme de caractère et le second pour sélectionner les couleurs de premier plan et d’arrière-plan. Les octets sont extraits et traités en signaux rouge, vert et bleu, dans une séquence qui donne un affichage lisible du texte.
Les programmes du PC IBM peuvent afficher du texte à l’aide de la routine DOS "sortie standard", de la routine "Écriture télétype" du BIOS ou de l’enregistrement direct dans la mémoire. De nombreux programmes ayant besoin d'afficher beaucoup de texte ont rapidement opté pour cette dernière solution, qui pouvait être littéralement des centaines de fois plus rapide que les routines DOS. Ce n'était pas parce que les routines DOS et BIOS étaient exceptionnellement inefficaces; à moins que l’écran ne soit blanc, il ne peut être écrit qu’à certaines heures. La routine du BIOS pour sortir un caractère a été conçue pour pouvoir être appelée à tout moment. chaque requête devait donc recommencer à attendre le bon moment pour effectuer une opération d'écriture. En revanche, un code d'application qui savait ce qu'il devait faire pouvait s'organiser en fonction des possibilités disponibles pour écrire l'affichage.
Un point clé ici est que, si le DOS et le BIOS offraient un moyen d’afficher du texte sur l’affichage, il n’y avait rien de particulièrement "magique" à propos de telles capacités. Une application qui souhaitait écrire du texte sur l’affichage pouvait le faire tout aussi efficacement, du moins si le matériel d’affichage fonctionnait comme prévu (si l’utilisateur avait installé une carte graphique monochrome similaire au CGA mais avec sa mémoire de caractères) situé à 0xB000: 0000-0xB000: 3999), le BIOS produirait automatiquement les caractères à cet emplacement; une application programmée pour fonctionner avec le MDA ou le CGA pourrait également le faire, mais une application programmée uniquement pour le CGA serait totalement inutile sur le MDA).
Sur les nouveaux systèmes, les choses sont un peu différentes. Les processeurs ont divers modes de "privilège". Ils commencent dans le mode le plus privilégié, où le code est autorisé à faire tout ce qu'il veut. Ils peuvent ensuite basculer vers un mode restreint, dans lequel seules les plages de mémoire sélectionnées ou les fonctionnalités d'E / S sont disponibles. Le code ne peut pas passer directement du mode restreint au mode privilégié, mais le processeur a défini des points d’entrée en mode privilégié, et le code en mode restreint peut demander au processeur de commencer à exécuter du code à l’un de ces points en mode privilégié. De plus, il existe des points d'entrée en mode privilégié associés à un certain nombre d'opérations qui seraient interdits en mode restreint. Supposons, par exemple, que quelqu'un veuille exécuter plusieurs applications MS-DOS simultanément, chacune ayant son propre écran. Si les applications pouvaient écrire directement sur le contrôleur d'affichage à l'adresse 0xB800: 0, il n'y aurait aucun moyen d'empêcher une application d'écraser l'écran d'une autre application. D'autre part, un système d'exploitation peut exécuter l'application en mode restreint et intercepter tout accès à la mémoire d'affichage. si elle découvrait qu'une application supposée être dans le "fond" essayait d'écrire 0xB800: 160, elle pourrait stocker les données dans une mémoire qu'elle avait réservée en tant que mémoire tampon d'écran d'arrière-plan. Si cette application est ensuite basculée au premier plan, le tampon peut alors être copié sur l'écran réel. un système d'exploitation peut exécuter l'application en mode restreint et intercepter tous les accès à la mémoire d'affichage; si elle découvrait qu'une application supposée être dans le "fond" essayait d'écrire 0xB800: 160, elle pourrait stocker les données dans une mémoire qu'elle avait réservée en tant que mémoire tampon d'écran d'arrière-plan. Si cette application est ensuite basculée au premier plan, le tampon peut alors être copié sur l'écran réel. un système d'exploitation peut exécuter l'application en mode restreint et intercepter tous les accès à la mémoire d'affichage; si elle découvrait qu'une application supposée être dans le "fond" essayait d'écrire 0xB800: 160, elle pourrait stocker les données dans une mémoire qu'elle avait réservée en tant que mémoire tampon d'écran d'arrière-plan. Si cette application est ensuite basculée au premier plan, le tampon peut alors être copié sur l'écran réel.
Les éléments clés à noter sont (1) bien qu'il soit souvent pratique de disposer d'un ensemble standard de routines pour effectuer divers services standard tels que l'affichage de texte, elles ne font rien qu'une application qui s'exécutait en "mode privilégié" ne pourrait pas faire. s'il était correctement programmé pour traiter le matériel installé; (2) Bien que leur système d'exploitation empêche la plupart des applications fonctionnant aujourd'hui d'exécuter directement de telles E / S, un programme qui démarre en mode privilégié peut faire ce qu'il veut et peut définir les règles qu'il souhaite pour le mode restreint. programmes.
la source
Comme Stephen C. l’a dit, il ne s’agit pas seulement de démarrer le système d’exploitation, mais également de savoir comment il fonctionne, qui interagit avec le matériel et les logiciels qui s’y trouvent.
J'ajouterai simplement à sa réponse que vous voudrez peut-être jeter un coup d'œil à "Les éléments des systèmes informatiques" . C'est un livre et des outils qui expliquent comment un ordinateur, un système d'exploitation et des compilateurs interagissent. L’unique particularité de ce logiciel est de vous donner les outils nécessaires pour développer très rapidement votre propre système d’exploitation dans un environnement simulé, en ignorant les nombreux détails nécessaires à un système réel, afin que vous puissiez saisir les concepts . Il fait un excellent travail de vous laisser voir la forêt au lieu des arbres.
Si vous souhaitez en savoir plus sur la manière dont le système d'exploitation interagit avec le matériel, consultez Minix .
la source
Votre application est en cours d'exécution dans un système d'exploitation. Ce système d'exploitation fournit des services à votre application, tels que l'ouverture d'un fichier et l'écriture d'octets. Ces services sont généralement fournis via des appels système.
Le système d'exploitation est en cours d'exécution dans le matériel. Le matériel fournit des services au système d’exploitation, notamment la définition du débit en bauds d’un port série et l’écriture d’octets. Ces services sont généralement fournis via des registres mappés en mémoire ou des ports d'E / S.
Pour donner un exemple très simplifié de la façon dont cela fonctionne:
Votre application demande au système d'exploitation d'écrire quelque chose dans un fichier. Pour votre application, le système d'exploitation fournit des concepts tels que les fichiers et les répertoires.
Sur le matériel, ces concepts n'existent pas. Le matériel fournit des concepts tels que des disques divisés en blocs fixes de 512 octets. Le système d'exploitation décide des blocs à utiliser pour votre fichier et de certains autres blocs pour les métadonnées, tels que le nom du fichier, sa taille et son emplacement sur le disque. Il indique ensuite au matériel: écrivez ces 512 octets dans le secteur portant ce numéro sur le disque portant ce numéro; écrivez ces 512 autres octets dans le secteur portant ce numéro différent sur le disque portant le même numéro; etc.
La façon dont le système d'exploitation demande au matériel de le faire varie beaucoup. L'une des fonctions d'un système d'exploitation est de protéger les applications de ces différences. Pour l'exemple de disque, sur un type de matériel, le système d'exploitation doit écrire le numéro de disque et de secteur sur un port d'E / S, puis écrire les octets un par un sur un port d'E / S séparé. Sur un autre type de matériel, le système d'exploitation devrait copier les 512 octets d'un secteur dans une zone de mémoire, écrire l'emplacement de cette zone de mémoire dans un emplacement de mémoire spécial et écrire le numéro de disque et de secteur sur un autre. emplacement mémoire spécial.
Le matériel haut de gamme d'aujourd'hui est extrêmement compliqué. Les manuels contenant tous les détails de la programmation sont des verrous de milliers de pages; Par exemple, le dernier manuel du processeur Intel comprend sept volumes, avec un total de plus de 4000 pages, et ce, uniquement pour le processeur. La plupart des autres composants exposent des blocs de mémoire ou des ports d'E / S, que le système d'exploitation peut demander à la CPU de mapper sur des adresses situées dans son espace d'adressage. Plusieurs de ces composants exposent encore plus d'éléments derrière quelques ports d'E / S ou adresses mémoire; à titre d'exemple, le RTC (Real Time Clock, le composant qui conserve l'heure de l'ordinateur lorsqu'il est éteint) expose quelques centaines d'octets de mémoire derrière une paire de ports d'E / S. Il s'agit d'un composant très simple qui remonte à le PC / AT d'origine. Des choses comme les disques durs ont des processeurs entièrement séparés, auquel le système d'exploitation communique via des commandes standardisées. Les GPU sont encore plus compliqués.
Plusieurs personnes dans les commentaires ci-dessus ont suggéré l'Arduino. Je suis d’accord avec eux, c’est beaucoup plus simple à comprendre: l’ATmega328, qui fait tout sur l’Arduino Uno sauf que le connecteur USB est exposé comme un port série, a un manuel de quelques centaines de pages seulement. Sur l’Arduino, vous exécutez directement sur le matériel, sans système d’exploitation entre les deux; juste quelques petites routines de bibliothèque que vous n’aurez pas à utiliser si vous ne le souhaitez pas.
la source
Exemples exécutables
Techniquement, un programme qui fonctionne sans système d'exploitation est un système d'exploitation. Voyons maintenant comment créer et exécuter des systèmes d’exploitation minuscules Hello World.
Le code de tous les exemples ci-dessous est présent sur ce dépôt GitHub .
Secteur de démarrage
Sur x86, la chose la plus simple et la plus simple à faire est de créer un secteur de démarrage principal (MBR) , qui est un type de secteur de démarrage , puis de l’installer sur un disque.
Ici, nous en créons un avec un seul
printf
appel:Résultat:
Testé sur Ubuntu 18.04, QEMU 2.11.1.
main.img
contient les éléments suivants:\364
en octal ==0xf4
en hex: l'encodage d'unehlt
instruction, qui indique à la CPU de ne plus fonctionner.Par conséquent, notre programme ne fera rien: démarrez et arrêtez seulement.
Nous utilisons octal car les
\x
nombres hexadécimaux ne sont pas spécifiés par POSIX.Nous pourrions obtenir cet encodage facilement avec:
mais l'
0xf4
encodage est bien sûr également documenté dans le manuel d'Intel.%509s
produire 509 espaces. Nécessaire pour remplir le fichier jusqu'à l'octet 510.\125\252
en octal ==0x55
suivi de0xaa
: octets magiques requis par le matériel. Ils doivent être les octets 511 et 512.S'il n'est pas présent, le matériel ne le traitera pas comme un disque amorçable.
Notez que même sans rien faire, quelques caractères sont déjà imprimés à l'écran. Celles-ci sont imprimées par le firmware et servent à identifier le système.
Exécuter sur du vrai matériel
Les émulateurs sont amusants, mais le matériel est la vraie affaire.
Notez cependant que ceci est dangereux et que vous pourriez effacer votre disque par erreur: ne le faites que sur de vieilles machines qui ne contiennent pas de données critiques! Ou encore mieux, des cartes de développement telles que Raspberry Pi, voir l'exemple ARM ci-dessous.
Pour un ordinateur portable typique, vous devez faire quelque chose comme:
Gravez l'image sur une clé USB (détruira vos données!):
branchez la clé USB sur un ordinateur
allume ça
dites-lui de démarrer à partir de l'USB.
Cela signifie que le micrologiciel sélectionne USB avant le disque dur.
Si ce n'est pas le comportement par défaut de votre machine, continuez à appuyer sur Entrée, F12, ESC ou toute autre clé bizarre après la mise sous tension jusqu'à ce que vous obteniez un menu de démarrage dans lequel vous pouvez choisir de démarrer à partir de l'USB.
Il est souvent possible de configurer l'ordre de recherche dans ces menus.
Par exemple, sur mon ancien Lenovo Thinkpad T430, UEFI BIOS 1.16, je peux voir:
Bonjour le monde
Maintenant que nous avons créé un programme minimal, passons à un monde de salut.
La question évidente est: comment faire IO? Quelques options:
port série . C'est un protocole normalisé très simple qui envoie et récupère les caractères d'un terminal hôte.
Source .
Il n’est malheureusement pas exposé sur la plupart des ordinateurs portables modernes, mais c’est le moyen le plus courant d’utiliser des cartes de développement, voir les exemples ARM ci-dessous.
C'est vraiment dommage, car de telles interfaces sont vraiment utiles pour déboguer le noyau Linux par exemple .
utiliser les fonctionnalités de débogage des puces. ARM appelle leur semi-hôte par exemple. Sur du matériel réel, cela nécessite un support matériel et logiciel supplémentaire, mais sur les émulateurs, cela peut être une option pratique et gratuite. Exemple .
Ici, nous allons faire un exemple de BIOS car il est plus simple sous x86. Mais notez que ce n'est pas la méthode la plus robuste.
main.S
link.ld
Assemblez et faites le lien avec:
Résultat:
Testé sur: Lenovo Thinkpad T430, UEFI BIOS 1.16. Disque généré sur un hôte Ubuntu 18.04.
Outre les instructions de montage standard de l’utilisateur, nous avons:
.code16
: indique à GAS de générer du code 16 bitscli
: désactiver les interruptions logicielles. Ceux-ci pourraient faire redémarrer le processeur après lahlt
int $0x10
: fait un appel du BIOS. C'est ce qui imprime les caractères un par un.Les drapeaux de liens importants sont:
--oformat binary
: sortie du code d'assemblage binaire brut, ne le faîtes pas dans un fichier ELF, comme c'est le cas pour les exécutables utilisateur standard.Utilisez C au lieu d'assemblage
Puisque C est compilé en assemblage, l’utilisation de C sans la bibliothèque standard est assez simple, il vous faut en gros:
main
notamment:TODO: lien donc quelques exemples x86 sur GitHub. Voici un bras que j'ai créé .
Cela devient plus amusant si vous souhaitez utiliser la bibliothèque standard, car nous n'avons pas le noyau Linux, qui implémente une grande partie des fonctionnalités de la bibliothèque standard C via POSIX .
Quelques possibilités, sans passer par un système d'exploitation complet tel que Linux, incluent:
Newlib
Exemple détaillé sur: https://electronics.stackexchange.com/questions/223929/c-standard-libraries-on-bare-metal/223931
Dans Newlib, vous devez implémenter vous-même les appels système, mais vous obtenez un système très minimal et il est très facile de les implémenter.
Par exemple, vous pouvez rediriger
printf
vers les systèmes UART ou ARM, ou mettreexit()
en œuvre avec semi-hébergement .systèmes d'exploitation embarqués tels que FreeRTOS et Zephyr .
De tels systèmes d'exploitation vous permettent généralement de désactiver la planification préemptive, vous donnant ainsi un contrôle total sur l'exécution du programme.
Ils peuvent être vus comme une sorte de Newlib pré-implémenté.
BRAS
Dans ARM, les idées générales sont les mêmes. J'ai téléchargé:
Quelques exemples simples de QEMU Baremetal ici sur GitHub . L' exemple prompt.c utilise les entrées de votre terminal hôte et restitue toutes les données à travers l'UART simulé:
Voir aussi: https://stackoverflow.com/questions/38914019/how-to-make-bare-metal-arm-programs-and-run-them-on-qemu/50981397#50981397
une configuration entièrement automatique du clignotant Raspberry Pi à l' adresse : https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker
Voir aussi: https://stackoverflow.com/questions/29837892/how-to-run-ac-program-with-no-os-on-the-raspberry-pi/40063032#40063032
Pour le Raspberry Pi, https://github.com/dwelch67/raspberrypi ressemble au didacticiel le plus populaire disponible à ce jour.
Certaines différences par rapport à x86 incluent:
IO se fait en écrivant aux adresses magiques directement, il n'y a pas
in
etout
instructions.Ceci est appelé IO mappé en mémoire .
pour du matériel réel, comme le Raspberry Pi, vous pouvez ajouter le micrologiciel (BIOS) vous-même à l'image du disque.
C’est une bonne chose, car cela rend la mise à jour de ce micrologiciel plus transparente.
Micrologiciel
En réalité, votre secteur de démarrage n'est pas le premier logiciel qui s'exécute sur le processeur du système.
Ce qui fonctionne réellement en premier est le soi-disant micrologiciel , qui est un logiciel:
Les firmwares bien connus incluent:
Le firmware fait des choses comme:
boucle sur chaque disque dur, clé USB, réseau, etc. jusqu'à ce que vous trouviez quelque chose de bootable.
Quand nous courons QEMU,
-hda
dit quemain.img
est un disque dur connecté au matériel, ethda
est le premier à être essayé, et il est utilisé.chargez les 512 premiers octets dans l’adresse de la mémoire RAM
0x7c00
, placez-y le RIP de la CPU et laissez-le fonctionnerafficher des éléments tels que le menu de démarrage ou les appels d'impression du BIOS sur l'écran
Le micrologiciel offre une fonctionnalité semblable à celle du système d'exploitation dont dépend la plupart des systèmes d'exploitation. Par exemple, un sous-ensemble Python a été porté pour fonctionner sur le BIOS / UEFI: https://www.youtube.com/watch?v=bYQ_lq5dcvM
On peut faire valoir que les firmwares sont indiscernables des systèmes d'exploitation et que les micrologiciels sont la seule "vraie" programmation en métal nu que l'on puisse faire.
Comme le dit ce développeur CoreOS :
Etat initial post-BIOS
Comme beaucoup de choses dans le matériel, la normalisation est faible et l’une des choses que vous ne devriez pas compter est l'état initial des registres lorsque votre code commence à s'exécuter après le BIOS.
Alors faites-vous une faveur et utilisez un code d'initialisation comme celui-ci: https://stackoverflow.com/a/32509555/895245
Les registres aiment
%ds
et%es
ont des effets secondaires importants, vous devriez donc les mettre à zéro même si vous ne les utilisez pas explicitement.Notez que certains émulateurs sont plus agréables qu'un matériel réel et vous offrent un bon état initial. Ensuite, lorsque vous utilisez du matériel réel, tout se brise.
GNU GRUB Multiboot
Les secteurs de démarrage sont simples, mais ils ne sont pas très pratiques:
C’est pour ces raisons que GNU GRUB a créé un format de fichier plus pratique appelé multiboot.
Exemple de travail minimal: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0/multiboot/hello-world
Je l’utilise également sur mon dépôt d’exemples GitHub pour pouvoir exécuter facilement tous les exemples sur du matériel réel sans graver la clé USB un million de fois. Sur QEMU cela ressemble à ceci:
Si vous préparez votre système d'exploitation en tant que fichier à démarrage multiple, GRUB est alors en mesure de le trouver dans un système de fichiers classique.
C’est ce que font la plupart des distributions, en mettant les images du SE sous
/boot
.Les fichiers à démarrage multiple sont essentiellement un fichier ELF avec un en-tête spécial. Ils sont spécifiés par GRUB à l’ adresse suivante : https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
Vous pouvez transformer un fichier à démarrage multiple en un disque amorçable avec
grub-mkrescue
.El Torito
Format pouvant être gravé sur CD: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29
Il est également possible de produire une image hybride qui fonctionne sur ISO ou USB. Ceci peut être fait avec
grub-mkrescue
( exemple ), et est aussi fait par le noyau Linux enmake isoimage
utilisantisohybrid
.Ressources
la source