3 points par GN⁺ 2024-05-25 | 1 commentaires | Partager sur WhatsApp
  • 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

 
GN⁺ 2024-05-25
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

    • Il est important de noter qu’avant Unix, ils avaient déjà travaillé longtemps sur Multics. Si ma mémoire est bonne, Unix était plutôt une version « simplifiée » de celui-ci, pas quelque chose sorti soudainement de nulle part
    • Tu parles probablement de Ken Thompson. J’ai la flemme de retrouver l’interview YouTube, mais je me souviens qu’il a raconté plusieurs fois quelque chose du genre : le pilote de disque, quelques programmes et d’autres composants existaient déjà, et pendant que sa femme était en voyage, il s’est dit qu’il avait le temps de combler les trous pour en faire un système d’exploitation complet
    • Il faut considérer qu’Unix lui-même a pris du temps. Si l’on prend V7 comme « Unix vraiment achevé », cela a pris plusieurs années, et la première version n’était par exemple qu’un système de fichiers
    • D’après ce que je sais, l’histoire portait sur 3 programmes manquants, dont un éditeur de texte
      Mes souvenirs sont flous, il faudrait que je vérifie
    • Je pense que tu confonds Dennis Ritchie et Ken Thompson
  • 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

    • Si tu ne l’as pas encore lu, je commencerais par Advanced Programming in the Unix Environment de Stevens
      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 se trouvent à l’intersection des entrées-sorties/appels système asynchrones et de la communication interprocessus. L’asynchronisme et l’IPC sont eux aussi des faiblesses de la conception Unix, et n’étaient pas présents dès le départ
      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
    • Je pense que certaines personnes n’aiment pas les signaux Unix parce qu’ils assument trop de concepts différents
      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
    • « signalfd is useless » est un bon article : https://ldpreload.com/blog/signalfd-is-useless
      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
    • Quand on écrivait des applications portables, les différences de traitement des signaux entre BSD et SYSV posaient problème
      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 côté, on peut respecter le fait que les auteurs s’en tiennent à ce qu’ils veulent accomplir et n’acceptent pas toutes les demandes
      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
    • Je ne suis pas d’accord avec le terme « impose ». Si quelqu’un fait quelque chose gratuitement, tant qu’il n’est pas malveillant, il n’a aucune obligation de le faire d’une manière particulière
      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
    • Vous et l’équipe de Hare n’avez sans doute pas la même définition du succès. Dire que « les langages font boule de neige ou disparaissent » me semble aussi assez réducteur pour beaucoup de langages qui, sans popularité de rockstar, ont progressé régulièrement pendant des décennies
      Tous les groupes n’ont pas besoin d’être dans le classement Billboard pour valoir la peine d’être écoutés
    • Cela veut dire qu’ils ne prendront pas officiellement en charge Windows ou macOS. Si d’autres projets veulent tenter des ports, rien ne les en empêche, non ? Je trouve positif d’être transparent sur le niveau de support prévu
      Prendre en charge des systèmes d’exploitation que les développeurs n’utilisent pas, c’est une grosse demande
    • L’affirmation « les langages font boule de neige ou disparaissent » n’est pas vraie, et elle est naïve
      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

    • Par comparaison avec aujourd’hui, il m’a fallu presque une semaine pour modifier un seul texte de bouton contenant une chaîne internationalisée
      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
    • C’est aussi le créateur de KnightOS, écrit il y a plus de 12 ans uniquement en assembleur Z80
      https://www.ticalc.org/archives/files/fileinfo/463/46387.htm...
    • Drew est intelligent et le calendrier était court, mais je pense que se contenter de le porter aux nues donne une mauvaise perspective. Créer un clone d’UNIX est, dans la plupart des universités, un projet de licence assez courant
      Ce qu’il faut pour en faire quelque chose de abouti, c’est de la persévérance plus qu’un génie particulier
    • Il y avait aussi Helios, une implémentation de noyau antérieure, qui fournissait une bonne partie du code de plus bas niveau. Je ne veux pas minimiser l’accomplissement, mais DD dit assez ouvertement qu’une grande partie de la vitesse de ce projet tient au fait qu’il avait d’abord créé Helios et réutilisé ce code
    • Comme Helios existait déjà, il s’agissait surtout d’intégrer les quelques pièces manquantes
  • 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

  • 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

    • « Si vous devez utiliser les ressources CPU en parallèle, utilisez plusieurs processus avec mémoire partagée » est en réalité assez puissant
      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
    • Si la bibliothèque standard upstream ne garantit pas la réentrance, cela exclut non seulement le multithreading, mais aussi l’utilisation dans les interruptions. Pour un « langage de programmation système », je trouve que c’est une limitation assez importante
    • Ce serait bien qu’il y ait des closures
  • 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