frostbyte

Un noyau de système d'exploitation amateur pour x86_64, en C et assembleur. Il démarre via Multiboot2, passe en mode 64 bits avec ses propres tables de pages, dispose d'un ordonnanceur préemptif et exécute des programmes en ring 3 - il démarre réellement dans QEMU.

frostbyte
TL;DR

Un noyau de système d'exploitation écrit de zéro - du chargeur d'amorçage jusqu'à l'exécution de ses propres programmes en mode utilisateur. Il démarre vraiment, dans QEMU.

Aperçu

frostbyte est un noyau x86_64 amateur, écrit en C et en assembleur. Le but n'était pas d'écrire un "système d'exploitation" au sens courant, mais de parcourir tout le chemin habituellement caché : du moment où le firmware cède le contrôle jusqu'à l'exécution de son propre programme en mode utilisateur, isolé du noyau.

C'est l'un des types de projet les plus impitoyables que l'on puisse se donner. Il n'y a ici aucune bibliothèque qui fasse quoi que ce soit à votre place, ni couche qui rattrape une erreur. Il y a un processeur nu, le manuel de l'architecture et vous. C'est justement pour cela que c'est une si bonne école.

Dans un programme ordinaire, une erreur est locale : une exception est levée, vous obtenez une trace de pile, vous corrigez une ligne. Dans un noyau, aucun de ces conforts n'existe. Un mauvais bit dans une table de pages et la machine se réinitialise tout simplement - sans message, sans journal, sans rien. Le débogage se transforme en lecture de registres et en devinettes sur lequel de vos trois derniers gestes fut le fatal.

Cette dureté impose une autre façon de travailler. Chaque étape doit être bouclée séparément et vérifiée de façon isolée avant d'ajouter la suivante, car sinon on ne peut pas distinguer laquelle de dix modifications a fait planter toute la machine. La discipline n'est pas ici une vertu, mais une condition pour avancer tout court.

Du firmware au ring 3

Tout le chemin est une suite de transitions entre des niveaux de contrôle de plus en plus élevés. Le firmware charge le noyau via Multiboot2 et transmet une carte mémoire. Ensuite, il faut activer le mode 64 bits, ce qui exige au préalable une pagination initiale. Puis le noyau prend en charge la mémoire virtuelle sur ses propres tables de pages, lance un ordonnanceur qui commute les tâches par interruption d'horloge, et ne saute qu'à la fin vers le ring 3.

1
Amorçage via Multiboot2

le chargeur d'amorçage charge le noyau et transmet une carte mémoire.

2
Passage en mode 64 bits

activer le long mode exige au préalable une pagination initiale.

3
Ses propres tables de pages

le noyau prend en charge la gestion de la mémoire virtuelle.

4
Un ordonnanceur préemptif

une interruption d'horloge commute les tâches, sans leur consentement.

5
Ring 3

un saut en mode utilisateur et l'exécution du premier programme à soi.

Le chemin de la mise sous tension à son propre programme

ÉtapeCe qui se passeMode
Multiboot2le firmware cède le contrôle, une carte mémoire existering 0
Long modeentrée en mode 64 bitsring 0
Tables de pagesle noyau prend en charge la mémoire virtuellering 0
Ordonnanceurl'horloge commute les tâches sans consentementring 0
Ring 3le premier programme, coupé du noyauring 3

Déboguer quand la machine disparaît tout simplement

Comme une erreur ne laisse aucune trace, il nous fallait un moyen pour que le noyau puisse dire quoi que ce soit avant d'avoir un pilote d'écran. La réponse, c'est QEMU avec sortie sur le port série : le noyau écrit ses journaux en texte sur le série, et cela part directement dans le terminal. Ainsi vous voyez la dernière ligne avant la réinitialisation au lieu d'un écran noir.

run.sh · bash
qemu-system-x86_64 \
  -cdrom frostbyte.iso \
  -m 512M \
  -serial stdio \
  -no-reboot -no-shutdown
!
Attention

En mode noyau, il n'y a pas de "presque ça marche". Une erreur dans un mappage mémoire ne fait pas planter une fonction - elle fait planter toute la machine. C'est pourquoi chaque étape a été testée séparément dans l'émulateur avant d'ajouter la suivante, et les options no-reboot et no-shutdown gardent la machine figée sur une faute au lieu de la laisser disparaître dans une boucle de redémarrage.

Le résultat : un système qui démarre vraiment

Ce qui en sort est un noyau qui démarre réellement dans QEMU et parvient à exécuter son propre programme en ring 3 - il ne s'arrête pas à l'affichage de "hello" mais parcourt tout le chemin jusqu'au mode utilisateur. C'est un projet construit pour comprendre l'ordinateur jusqu'au plus profond, mené au point où cette compréhension est prouvée par l'exécution, et non déclarée.

Plus de projets

D'autres réalisations de la même catégorie - découvrez comment nous abordons des défis similaires.

Vous avez un projet similaire ?

Contactez-nous - le devis est gratuit et arrive sous une heure.