- Bunnix, lancé comme projet personnel de détente, a servi à tester jusqu’où il était possible de construire un système d’exploitation de type Unix pour x86_64 en environ un mois, et le travail a pris 27 jours effectifs
- Le noyau est principalement écrit en Hare, avec aussi des composants en C comme lwext4 pour la prise en charge d’ext4 et libvterm pour le terminal vidéo du noyau
- Il prend en charge à la fois le legacy boot et l’EFI et a été testé sur quelques vrais ordinateurs portables, mais l’absence de prise en charge USB impose un clavier PS/2 ou une émulation PS/2 par le BIOS
- L’espace utilisateur repose surtout sur des logiciels tiers comme dash, Doom, gzip, less, mandoc, sbase, tcc et Vim 5.7, et la libc est une version de musl libc adaptée à Bunnix
- Bunnix fonctionne, mais comporte beaucoup de bugs et reste un système mono-utilisateur ; il s’agit moins d’un projet à maintenir sur le long terme que d’une expérimentation menant à une refonte de Helios et à des améliorations de conception du noyau
Portée et exécution de Bunnix
- Bunnix est un projet de système d’exploitation de type Unix pour x86_64 lancé le 21 avril 2024
- En excluant les jours sans travail effectif, un total de 27 jours y a été consacré
- Une image Bunnix 0.0.0 iso permettant de l’exécuter directement est fournie
- Dans qemu, l’ISO peut être démarrée avec la commande suivante
qemu-system-x86_64 -cdrom bunnix.iso -display sdl -serial stdio
- Il est aussi possible d’écrire l’ISO sur une clé USB pour démarrer sur du matériel réel
- Cela devrait fonctionner sur la plupart des machines AMD64
- Le système a été testé sur un ThinkPad X220 et un Starlabs Starbook Mk IV
- Il prend en charge à la fois le legacy boot et l’EFI
- La plus grande contrainte d’exécution est l’absence de prise en charge USB
- Un clavier PS/2 ou une émulation PS/2 par le BIOS est nécessaire
- La plupart des claviers d’ordinateurs portables sont connectés en PS/2
- Le fonctionnement de l’émulation PS/2 pour les claviers USB dépend de l’environnement
- Le portage de Doom présente des limites sur les raccourcis clavier et la fermeture du jeu
- WASD pour se déplacer
- Maj droite pour tirer
- Espace pour ouvrir les portes
- La fermeture du jeu ne fonctionne pas, il faut donc redémarrer après avoir joué
Structure du noyau et fonctionnalités prises en charge
- Le noyau de Bunnix est en grande partie écrit en Hare et utilise aussi quelques composants en C
- lwext4 est utilisé pour la prise en charge du système de fichiers ext4
- libvterm est utilisé pour le terminal vidéo du noyau
- Les pilotes pris en charge se concentrent sur le matériel de base et sur ce qui est nécessaire au démarrage depuis un périphérique de stockage
- PCI legacy
- périphériques de bloc AHCI
- tables de partition GPT et MBR
- clavier PS/2
- port série de la plateforme
- horloge CMOS
- framebuffer configuré par le bootloader
- systèmes de fichiers ext4 et memfs
- Les fonctions de base d’un système de type Unix nécessaires au noyau sont également incluses
-
Système de fichiers virtuel et périphériques
- Fournit
/dev avec des périphériques de bloc, des pseudo-périphériques null, zero et full, /dev/kbd, /dev/fb0, des TTY série et vidéo, ainsi qu’un terminal de contrôle /dev/tty
- Inclut un émulateur de terminal relativement abouti et une prise en charge de termios qui fonctionne dans une certaine mesure
-
Appels système et modèle utilisateur
- Prend en charge environ 40 appels système, dont
clock_gettime, poll, openat, fork, exec, pipe, dup, dup2 et ioctl
- Bunnix est actuellement un système mono-utilisateur
- Il n’impose ni les modes de fichiers Unix ni la propriété des fichiers
- Avec quelques jours de travail supplémentaires, il pourrait devenir un système multi-utilisateur
Bootloaders et espace utilisateur
- Bunnix inclut deux bootloaders
- Le bootloader pour le legacy boot est compatible multiboot et écrit en Hare
- Le bootloader EFI est écrit en C
- Les deux bootloaders chargent au besoin le noyau sous forme de fichier ELF et un initramfs
- Le bootloader EFI embarque zlib pour décompresser l’initramfs
- Le bootloader compatible multiboot se charge lui-même de la décompression
- L’espace utilisateur est composé en grande partie de sources tierces
- Colossal Cave Adventure
advent
dash /bin/sh
- Doom
- gzip
- less
lok /bin/awk
- lolcat
- mandoc
- sbase core utils
- compilateur C tcc
- Vim 5.7
- La libc dérive de musl libc et a subi plusieurs modifications pour répondre aux besoins de Bunnix
- La bibliothèque curses est basée sur netbsd-curses
- Le système fonctionne, mais il est très bogué et certaines parties ont été implémentées dans l’urgence, il faut donc s’attendre à des plantages
Facteurs ayant permis l’implémentation rapide et difficultés rencontrées
- Une partie du code de Bunnix provient du projet précédent Helios
- Il inclut une partie du code noyau lié à la configuration générale du CPU, comme la GDT et l’IDT
- Certains pilotes, comme AHCI, ont aussi été adaptés au système Bunnix
- Sans l’expérience acquise avec Helios, il aurait été difficile de créer Bunnix aussi vite
- La prise en charge d’ext4 et l’intégration du terminal virtuel ont été particulièrement difficiles
- Des dépendances externes, lwext4 et libvterm, ont été intégrées
- La couche système de fichiers a été réécrite plusieurs fois et comporte encore des bugs
- Pour implémenter correctement la conception d’un système de fichiers Unix, notamment
openat et la gestion des inodes, il a fallu aller davantage dans les détails internes de lwext4
- Le projet Hare a aussi permis d’acquérir de l’expérience dans l’édition de liens entre sources Hare, assembleur et C
- Globalement, cela fonctionne bien, mais il y a eu des difficultés lors de la mise en place des mécanismes d’intégration ABI
- Le besoin est apparu d’une conversion automatique des en-têtes C en modules de forward declarations pour Hare
- Un travail lié existe en partie dans
hare-c, mais davantage reste à faire
- Le portage de Vim a relevé la difficulté de l’implémentation du terminal
- libvterm est une bonne bibliothèque de machine d’état de terminal, mais sa documentation est limitée
- Beaucoup de réglages fins ont été nécessaires pour une intégration correcte
- Du temps a aussi été consacré à l’optimisation des performances pour obtenir un fonctionnement fluide
- L’ordonnanceur est l’une des zones réécrites en abandonnant largement le code issu de Helios
- Helios comme Bunnix sont tous deux des systèmes mono-CPU
- Contrairement à Helios, Bunnix autorise les changements de contexte dans le noyau
- Le changement de tâche préemptif passe également par le noyau à l’entrée comme à la sortie
- Cette structure exige plusieurs piles noyau et une autre méthode de changement de tâche
- Avec un ordonnanceur suffisamment robuste, des opérations bloquantes comme la lecture disque ou
pipe(2) peuvent être implémentées simplement avec des files d’attente
- L’implémentation des signaux était nécessaire pour la compatibilité Unix
- Helios ne vise pas Unix et fonctionne donc sans signaux
- Dans Bunnix, l’implémentation a surtout été ajustée pour que
SIGCHLD fonctionne correctement pour le portage de dash
- L’implémentation finale des signaux reste très basique
Enseignements de conception appliqués à Helios
- Bunnix est un noyau monolithique, tandis que Helios est un microkernel non Unix
- Du côté du système de fichiers, l’importance du cache s’est confirmée
- Helios répartit l’implémentation du système de fichiers entre plusieurs pilotes et processus séparés
- Le cache de la couche système de fichiers est important ne serait-ce que pour suivre les objets vivants
- La refonte de Helios nécessitera donc beaucoup de refactorisation ou de réécriture du code du système de fichiers
- L’approche des pilotes est naturellement plus simple dans un noyau monolithique
- Cela dit, le fait d’avoir mis beaucoup de choses en ring 0 ne donne pas entière satisfaction
- Certains éléments de flux de contrôle issus du design monolithique pourraient être repris dans l’ordonnanceur de Helios
- En gestion mémoire, l’allocateur bitmap a mieux fonctionné que prévu
- Dans Helios, on avait essayé d’éviter l’allocateur bitmap et la gestion mémoire constituait un point de friction majeur
- Bunnix utilise un simple allocateur bitmap pour toutes les pages générales du système
- La surcharge s’est révélée moins importante qu’attendu et le résultat fonctionne très bien
- Il est estimé qu’il aurait été impossible de construire Bunnix en 30 jours avec une conception en microkernel
- Un noyau monolithique est bien plus simple à implémenter
- Les avantages de la conception microkernel restent attrayants, et une meilleure réponse pourrait être un noyau hybride
État du projet et pistes d’amélioration restantes
- Bunnix ressemble davantage à un projet artistique presque achevé qu’à quelque chose dans lequel investir encore beaucoup de temps
- Il peut encore faire l’objet de quelques journées de travail de temps à autre
- Les améliorations de la communauté peuvent être envoyées sous forme de patchs via public inbox
- Pour la suite du développement OS, l’idée est plutôt de revenir à Helios avec les leçons tirées de Bunnix afin d’y mener une refonte majeure
- Les priorités d’amélioration envisagées sont les suivantes
- cache de répertoires pour le système de fichiers et amélioration générale du cache
- correction des bugs ext4
- procfs et top
- mmap de fichiers
- signaux supplémentaires comme
SIGSEGV
- prise en charge multi-utilisateur
- périphériques de bloc NVMe
- périphériques de bloc IDE
- prise en charge d’ATAPI et d’ISO 9660
- prise en charge de l’audio Intel HD
- pile réseau
- toolchain Hare pour le système de base
- auto-hébergement
1 commentaires
Avis de Hacker News
Vraiment impressionnant. Ça me rappelle l’histoire selon laquelle Unix lui-même aurait été créé pendant les quelques semaines où la famille Ritchie était partie en vacances en Californie pour voir les beaux-parents
La source est UNIX: A History and a Memoir de Brian W. Kernighan
Mes souvenirs sont flous, il faudrait que je vérifie
J’aimerais voir des ressources plus détaillées sur le passage : « J’ai enfin appris comment les signaux fonctionnent de haut en bas, et c’est vraiment laid. J’ai toujours eu le sentiment que c’était l’un des points les plus faibles de la conception d’Unix, et ce projet n’a pas changé mon avis ». Si des utilisateurs de HN ou l’auteur savent quelque chose, ça m’intéresse
https://www.amazon.com/Advanced-Programming-UNIX-Environment...
Il couvre l’API Unix en espace utilisateur, y compris les signaux et les processus
Si tu veux implémenter les signaux dans le noyau, je ne sais pas trop quoi recommander, mais je pense à quelque chose comme https://pdos.csail.mit.edu/6.828/2012/xv6.html
Lire un livre qui explique clairement et systématiquement le fonctionnement d’Unix avec des exemples autonomes est vraiment rafraîchissant. Ne pas connaître le C peut être un obstacle, mais c’est pareil pour lire l’article de blog
Je ne pense pas qu’on trouve une information équivalente quelque part sur le Web. Il y a aussi beaucoup de connaissances diverses sur Unix sur mon blog que les gens lisent encore, mais ce n’est pas du même niveau
Pour comprendre les signaux Unix, je pense que passer par des articles de blog, Google ou des LLM est très inefficace. Même d’occasion, on ne peut pas dire qu’il soit « bon marché », mais c’est un livre dont le prix reste élevé parce que l’information a de la valeur, et pour un programmeur professionnel, il reste relativement abordable
Les signaux sont une tentative maladroite de greffer de force de l’IPC asynchrone sur la conception, ce qui les rend vulnérables aux conditions de concurrence. Que se passe-t-il si l’on reçoit un autre signal pendant le traitement d’un signal ? Que faire d’un signal lorsqu’un processus est en plein appel système ? C’est ambigu. Il faut décider s’il faut le différer, le mettre en file d’attente ou sortir de l’appel système
Si tous les appels système étaient asynchrones, comme le principe de conception suivi par beaucoup de systèmes d’exploitation modernes, cet aspect serait résolu. Et si l’IPC disposait d’un système de canaux fiables, on pourrait implémenter non seulement les signaux, mais aussi une communication interprocessus asynchrone ou des appels de procédure plus sophistiqués
SIGSTOP/SIGCONT/SIGKILL ne signalent pas vraiment quelque chose à un processus : ils font plutôt du contrôle de processus, comme suspendre, reprendre ou terminer
Les simples messages asynchrones comme SIGHUP, SIGUSR1, SIGUSR2, SIGTTIN, SIGTTOU sont détournés pour relire la configuration, etc., et des contournements bricolés comme nohup ont été ajoutés pour la démonisation. gunicorn utilise même les deux derniers pour l’extension et la réduction dynamiques. Dans cette catégorie, il y a aussi des choses bizarrement spécifiques comme SIGWINCH
Il y a aussi SIGILL, SIGSEGV, SIGFPE, qui indiquent une instruction invalide, une violation de segmentation ou une exception en virgule flottante. Il y a même des choses comme SIGSYS pour lesquelles il n’est pas évident qu’il soit bon de les rendre asynchrones dès le départ
Les autres approches ont aussi leurs compromis. Windows a les événements, SEH, les routines de gestion CTRL+C/CTRL+BREAK/arrêt, IOCP, les callbacks, etc. Les notes de Plan 9 étant des chaînes, elles ont l’avantage de permettre d’envoyer des données arbitraires à un autre processus, mais utiliser le même mécanisme pour le contrôle de processus a les mêmes inconvénients que *nix ; ce sont juste des chaînes au lieu de nombres
Il traite des problèmes des signaux Unix et explique aussi pourquoi signalfd, créé par Linux pour tenter de les résoudre, ne fonctionne pas très bien
https://pubs.opengroup.org/onlinepubs/009604499/functions/bs...
Il est aussi important que le code dans un gestionnaire de signal soit réentrant. « Les fonctions non réentrantes ne sont généralement pas sûres à appeler depuis un gestionnaire de signal »
https://man7.org/linux/man-pages/man7/signal-safety.7.html
Hare m’intéressait, mais en voyant cette entrée de FAQ, j’ai trouvé que c’était une politique franchement autodestructrice : https://harelang.org/documentation/faq.html#will-hare-suppor...
Sur le principe, je soutiens l’idée que les développeurs utilisent la licence qu’ils veulent, ciblent les systèmes d’exploitation qu’ils veulent et écrivent le code qu’ils veulent
Mais cela ne fait pas pour autant de cette politique précise une bonne idée. Même la FSF, pourtant considérée comme l’un des groupes les plus extrêmes ou les plus attachés aux principes de la philosophie du logiciel libre, prend en charge Windows et POSIX. On peut râler et l’appeler Woe32, mais Stallman a avancé de manière assez convaincante qu’il est plus utile, dans la lutte pour un monde sans logiciel propriétaire, de faire en sorte que les projets de logiciel libre fonctionnent aussi sur des systèmes propriétaires
Le code des bibliothèques est sous licence MPL, donc utiliser Hare ne vous enferme pas en soi dans une licence particulière. Mais je me demande quelle espérance de vie peut avoir un langage qui adopte, envers plus de 95 % des postes de travail, une attitude du type « pas pris en charge, ne posez pas de questions sur le forum, ne venez pas ici »
Ironiquement, quand on cherche « harelang repo » sur Google, le premier résultat est un port macOS non officiel, et le vrai dépôt SourceHut n’apparaît pas sur la première page
Les langages font boule de neige ou disparaissent. J’écris ceci depuis un Mac, mais si je le voulais, je pourrais utiliser une machine Linux dès maintenant. Alors pourquoi devrais-je apprendre un langage qui impose aux développeurs un test de pureté que même la FSF n’impose pas ? Une part importante de l’open source et du logiciel libre est écrite sur Mac, et une part plus grande qu’on ne le pense l’est aussi sur Windows
À mes yeux, ce qui distingue Hare d’Odin ou de Zig, c’est précisément cette attitude de pureté et d’exclusion. Je leur souhaite de bons moments de hacking et de réussir, mais je suis pessimiste sur ce dernier point
D’un autre côté, ce n’est pas le seul passage de la FAQ qui fait lever un sourcil
« Il n’y a pas de gestionnaire de paquets, et la réutilisation de code est moins encouragée comme valeur partagée »
« qbe génère du code plus lent que LLVM, avec des performances à l’exécution situées entre 25 et 75 % de celles d’un code comparable généré par LLVM »
« Peut-on utiliser le multithreading en Hare ? Probablement pas »
« Alors faut-il implémenter soi-même une table de hachage ? Oui. Les tables de hachage sont une structure de données courante que beaucoup de programmes Hare devront implémenter à partir de zéro »
Pour l’instant, ce n’est clairement pas un langage conçu pour viser une adoption grand public. C’est acceptable, et au moins ils sont honnêtes à ce sujet
On est libre d’exprimer son opinion, mais quand les développeurs ont déjà fixé leurs lignes directrices, je ne trouve pas ce genre de critique constructif
Tous les groupes n’ont pas besoin d’être dans le classement Billboard pour valoir la peine d’être écoutés
Prendre en charge des systèmes d’exploitation que les développeurs n’utilisent pas, c’est une grosse demande
Il existe pas mal de langages qui, sans être très populaires globalement, prospèrent dans des niches solides et jouent un rôle important
Impressionnant, très cool et inspirant. Les exemples du type « construire quelque chose d’impressionnant en X jours » exigent des années d’expérience et de talent accumulés
Il a fallu mettre la chaîne anglaise dans le catalogue, mettre à jour plusieurs tests, lancer les tests sur mon système local, déployer les changements sur le cluster de staging, corriger des échecs de tests inattendus, déployer en production, demander aux responsables de traduction de traduire en plusieurs langues, et mettre aussi la documentation à jour
https://www.ticalc.org/archives/files/fileinfo/463/46387.htm...
Ce qu’il faut pour en faire quelque chose de abouti, c’est de la persévérance plus qu’un génie particulier
C’était vraiment chouette de voir les mises à jour publiées presque tous les jours sur Mastodon. On a pu observer quelqu’un d’expérimenté assembler progressivement un logiciel complexe
https://fosstodon.org/@drewdevault/112319697309218275
Le code est ici : https://git.sr.ht/~sircmpwn/bunnix/tree/master
Il est sous licence GPLv3
L’espace utilisateur est en grande partie assemblé à partir de sources tierces
J’ai d’abord été surpris de voir un téléchargement de 60 Mo en cliquant sur l’ISO, mais j’ai compris pourquoi
À titre de comparaison, Linux 0.01 faisait 71 Ko à télécharger, mais ne contenait que les sources du noyau
Hare semble être un langage intéressant
Toutefois, à l’ère du multicœur, la limitation ci-dessous risque selon moi de freiner son adoption
D’après la FAQ https://harelang.org/documentation/faq.html, à la question de savoir si l’on peut utiliser le multithreading en Hare, la réponse est « probablement pas »
Pour multiplexer les opérations d’entrée/sortie, il recommande une boucle d’événements ; lorsqu’il faut utiliser les ressources CPU en parallèle, il recommande plusieurs processus avec mémoire partagée
À strictement parler, il est possible de créer des threads dans un programme Hare. On peut lier avec la libc pour utiliser pthreads, ou appeler directement l’appel système clone(2). Les systèmes d’exploitation implémentés en Hare, comme Helios, implémentent généralement le multithreading
Mais comme la bibliothèque standard upstream ne fournit aucune garantie de réentrance, il faut entièrement assumer soi-même la responsabilité d’éviter de se tirer une balle dans le pied
Personnellement, je préfère cette approche pour la plupart des usages, car elle limite les risques de data races aux seules zones de mémoire partagée. Du point de vue des data races, cela ressemble à un « unsafe block » en mémoire
Cela vient de « Linux System Call Table – Chromiumos » https://www.chromium.org/chromium-os/developer-library/refer... https://news.ycombinator.com/item?id=33395777
google/syzkalleR
Appels système Fuschia / Zircon : https://fuchsia.dev/fuchsia-src/reference/syscalls
« Memory Sealing ‘Mseal’ System Call Merged for Linux 6.10 »
https://news.ycombinator.com/context?id=40474551