Projet Vhex (Kernel pour les calculatrices Casio)
Posté le 18/09/2020 23:23
Comme vous l'avez peut-être remarqué au cours de mes dernières activités sur PC, j'ai commencé à toucher pas mal au bas niveau ainsi qu'à faire des essais de projet ambitieux. Seulement, ces derniers jours, je me suis rendu compte que je bossais en sous-marin sur plusieurs projets en même temps et qu'ils mériteraient peut-être d'être mis en lumière (mais dans le pire des cas, les idées présentées serviront bien à quelqu'un, un de ces quatre
)
C'est pourquoi j'ai créé ce topic, qui me permet de vous montrer ce que j'aimerais mettre en place et aussi pour voir si le projet pourrait potentiellement intéresser des personnes.
Globalement, j'aimerais mettre en place plusieurs projets qui sont tous plus ou moins "interconnectés" entre eux et qui ont pour objectif principal de fournir un
kernel UNIX-likeet
libre pour les calculatrices Casio.
Par contre, je préfère mettre les choses au clair dès le début, le projet n'a pas pour but d'être un kernel révolutionnaire, si vous avez envie de faire un OS meilleur que celui de Casio pour lancer
des super-jeux en 3D,
connecter votre calculatrice à Internet, ou encore avoir une interface plus jolie que ce bon vieux menu de nos Casio, ce n'est PAS le but premier du projet. C'est juste un projet qui me permet d'apprendre sur plein de domaines différents.
Mais le temps commence à me manquer et j'aimerai laisser au moins une petite trace de mes idées avant que tout finisse sous le tapis.
Vous avez ici la vue d'ensemble des projets :
|----------------------------------------------------------|
| Kernel / OS | Librairies |
|-------------------------|--------------------------------|
| fxBoot (bootloader) | fxlibc (C standard librairies) |
| |-- FixOS (OS) | fxCompositor (windows manager) |
| `-- Vhex (kernel) | fxGUI (graphical librairies) |
| |-- GladOS (OS) | |
| `-- testOS (OS) | |
|----------------------------------------------------------|
Chaque partie que vous voyez la sera indépendantes pour permettre à quiconque le souhaite de participer au projet.
Petite description des projets :
FxBoot: (bootloader)
C'est un
bootloader qui permettra de charger les noyaux sur la machine (mais aussi les addins). C'est une des parties les plus importantes du projet et j'aimerais qu'il ait suffisamment de souplesse pour arriver à charger des OS qui n'ont pas été pensé pour être loader (par exemple FixOS).
FixOS: (OS)
Un OS pour les calculatrices SH3 développé par Kristaba il y a quelques années maintenant. Il ne fait pas partie du projet mais c'est juste pour indiquer que Vhex ne sera probablement pas porté sur SH3 pour des raisons techniques (et matériel car je n'ai pas de SH3 fonctionnel sous le coude).
Vhex: (kernel)
La pièce maitresse du projet. C'est
mon kernel que j'ai développé cette année et qui étais presque arrivé au stade de FixOS. Cependant, l'architecture ne me plait pas (monolithique non-modulaire) et j'aimerais que chaque fonctionnalité du noyau puisse être chargé sur demande (via des modules kernel, qui seront probablement des librairies dynamique). Un topic sera créé (ou je récupèrerais l'ancien topic de Vhex comme thread principal ?) pour vous tenir au courant des dernières avancées et pour vous permettre de me proposer des correctifs ou des features que vous aimeriez bien voir sur le noyau (je ne vous promets pas de les réaliser ceci-dit
)
GladOS: (OS s'appuyant sur Vhex)
C'est
mon premier prototype de kernel que j'avais commencé à réaliser il y a plus d'1 an maintenant. Il a toujours pour objectif de remplacer Casio de la machine mais il se basera sur Vhex pour fonctionner (et non un truc custom). Il permettra d'utiliser la machine à son plein potentiel (driver USB, gestion de la mémoire virtuelle, EEPROM, ...).
TestOS: (OS s'appuyant sur Vhex)
C'est un "OS" qui, actuellement, se base sur un fork de Vhex et qui me permet de tracer l'OS de Casio pas-à-pas, faire des tests hardware, analyser la RAM. C'est un truc absolument pas stable mais très utile pour faire de la rétro-ingénierie directement sur la calculatrice. Il se basera entièrement sur Vhex à l'avenir. Par contre, je ne pense pas donner les sources avant de l'avoir sécurisé un minimum (car le code manipule beaucoup de choses dangereuses pouvant casser la calculatrice si on ne sait pas ce qu'on fait. (si vraiment vous les voulez, je peux vous les donner hein? Faites juste gaffe avec)).
fxlibc: (librairie standard C pour les calculatrices Casio)
C'est un projet que j'ai commencé hier et qui a pour but de fournir une libraire standard pour les calculatrices et qui pourra être configurable (par exemple pour permettre de choisir l'
ABI que l'on souhaite (Casio, Vhex ou FixOS), le format, ...). Elle sera utilisée pour la plupart des projets liés au noyau.
fxGui: (libraire graphique)
Ce sera une librairie qui fournira un moyen pour les gestionnaires de fenêtres "composite" de communiquer directement avec les applications graphiques ainsi que le matériel vidéo.
fxCompositor: (compositing window manager)
Ce sera
un gestionnaire de fenêtres de Vhex (un logiciel chargé de l'affichage et du placement des fenêtres d'applications) qui reprendra le fonctionnement de Wayland. Elle sera basée sur les libs "bopti" et "topti" de Lephenixnoir (je pense).
Ou est-ce que ça en est aujourd'hui ?
Je suis encore en train de mettre sur papier la nouvelle architecture du noyau histoire de voir toutes les possibilités qui pourraient être implémentées. Mais je suis confronté à plusieurs problèmes techniques assez complexes à résoudre proprement, notamment concernant le chargement des modules kernel (sans rentrer dans les détailles, la toolchain utiliser ne permet pas de générer des librairies dynamiques qui sont essentielles pour charger des bouts de code "à-la volée") ce qui est fort cocasse étant donnée que la nouvelle architecture du noyau repose dessus
.
Aussi, je suis en train de documenter la machine le plus possible avant de me replonger dans le développement des projets.
J'ai plusieurs cibles notamment :
* Fugue, le "nouveau" système de ficher propriétaire utiliser par les "nouvelles générations" de calculatrice Casio.
* Le driver USB de Casio. Grâce à Lephenixnoir, on a pu certifier que le module hardware qui gère l'USB et pratiquement le même que sur le SH7724 mais je n'arrive toujours pas avoir les infos sur le bus ainsi que de notifier l'hôte que je suis connecté.
* l'ABI de la Graph90+E, qui n'est pas aussi biens connu que sur monochrome.
À part ça, j'ai commencé à créer la fxlibc, la librairie C standard que j'utiliserai pour mes projets. Je sais que
Memallox a porté newlib sur la calto mais j'ai besoin d'avoir quelque chose de suffisamment modulaire pour choisir quel ABI je veux utiliser (CASIOABS, Vhex ou FixOS) ainsi que le format de la librairie (statique '.a' ou dynamique '.so'). J'ai encore quelque hésitation sur le comment architecturer tout ça mais je ferrai un topic quand j'aurais à nouveau du temps devant moi. Dites-vous que le prototype est quasiment finis, il manque juste énormément de fonction (que j'ajouterai au fur et à mesure de mes besoins) ainsi que de l'optimisation sur toutes les fonctions.
J'ai aussi commencé à poser sur papier les features du bootloader ainsi que sa documentation. Une fois le prototype de la fxlibc finie ce sera ma priorité. Là aussi je ferrais un topic quand j'aurais commencé a dev quelque chose. Tous ce que je peux dire pour l'instant c'est qu'il reposera uniquement sur les fonctionnalités de l'OS de Casio pour faciliter son portage. Au passage, ce projet a été passer en projet "Hub" à Epitech (
mon école), ce qu'il signifie qu'il me permettra de valider une partie de mon année si j'arrive à le finir.
Je sais d'avance que cette année ainsi que l'année qui arrive risque d'être compliqué pour continuer ces projets. C'est pourquoi, si vous avez envie de participer, vous êtes les bienvenus !
Prévisions avant juin 2021
J'aimerai avoir :
* un prototype correct du bootloader pouvant tourner sur toutes les calculatrices Casio qui supporte les addins.
* la libc supportant l'ABI de Vhex ainsi que la création de librairies dynamique.
* une documentation / organisation correcte pour que n'importe qui puisse continuer.
* un "prof-of-concept" de Vhex en version modulaire.
J'espère sincèrement que le projet prendra vie et arrivera à maturité. Dans tous les cas, de tous les projets annoncés, j'ai déjà réalisé des "profs of concept" qui traine de mon côté, je peux donc vous affirmer que le projet serait réalisable ! Le challenge va être d'organiser et maintenir tout ça dans le temps.
Citer : Posté le 21/09/2020 11:03 | #
Sympa ! Ça donne très envie tout ça, surtout l'aspect "composant réutilisable" de FxBoot ou fxlibc !
• Est-ce que la conception de fxBoot permettrait (dans le futur) de l'installer dans la ROM ? Spécifiquement à la place de l'OS après le bootloader de Casio, de sorte que l'installation de l'OS original soit encore possible et sans risque de bricker des machines ? L'état dans lequel le bootloader de Casio laisse la calculatrice n'est certainement pas très différent de celui dans lequel tu l'obtiens au lancement d'un add-in.
• Comment comptes-tu opérer la transition de Vhex du binaire monolithique à la version modulaire avec des libs partagées ? D'expérience je sais (et toi aussi je pense) que tout recommencer de zéro serait un coup assez violent à encaisser. Est-ce que le code actuel permet de partir dans cette direction ?
• Tu veux mettre l'USB et la gestion de la mémoire virtuelle en-dehors du noyau (?!)
• Niveau libc on a le port de newlib par Memallox mais j'ai eu des problèmes (peut-être d'ABI) à une époque et il crashait sur des fonctions mémoire de base, donc pour l'instant j'ai pas de méthode finale pour gint. Est-ce que tu penses que le code de fxlib peut être partagé et récupéré entre plusieurs projets ? Je peux notamment contribuer des fontions mémoire genre memcpy/memset optimisées aux petits oignons.
• Est-ce que tu envisages de supporter la Graph 90+E ? D'expérience de gint c'est vraiment comme la Graph SH4 excepté que l'écran a un driver différent et des couleurs différentes, et si tu fais des aller-retours avec l'OS il faut faire attention au DMA (l'OS l'utilise, contrairement aux Graph mono).
En attendant, GG ! C'est clairement le projet bas niveau le plus abouti avec FiXoS, sinon plus.
Citer : Posté le 21/09/2020 16:42 | #
En gros, le bootloader va être basé sur le principe de fonctionnement de GNU/Grub donc il y aura une partie "graphique" et une partie "shell". Dans la partie shell, je compte mettre une commande qui rependra le principe de l'"OS update" de Casio, à savoir attendre le transfert d'un OS via USB pour l'installer directement dans la ROM (tous sera écrasées). Je n'ai pas encore réfléchi pleinement sur le comment implémenter ça correctement surtout que je n'ai que très peu de connaissances sur la ROM actuellement.
Pour ce qui est de la partie "écriture dans la ROM", j'ai un projet de devboard pour la calto (histoire de faire un max de test avec la ROM sans briquer une calto par test). Je n'ai pas encore les connaissances techniques / théoriques pour y parvenir et je sais qu'il y a beaucoup de problèmes que je n'ai pas encore pris en compte mais je suis confiant sur la réalisabilité du projet.
En fait le kernel est relativement biens compartimenté et je ne pense vraiment pas avoir trop de boulot à faire pour effectuer cette transition. Chaque partie du noyau sera un module complètement isolé pour que n'importe qui puisse le maintenir et/ou y ajouter des features.
Le plus complexe ça risque d'être la gestion de la mémoire virtuelle / physique. Car j'aimerais qu'on puisse configurer Vhex de tel sorte qu'on puisse choisir si on veut utiliser le MMU (contrôle totale de la machine, sans aucune compatibilité avec l'OS de Casio) ou non (donc que tout l'environnement du noyau partage le même espace mémoire et ce qui permettra d'avoir une compatibilité avec l'OS de Casio).
Aussi, je ne sais pas encore exactement comment choisir l'OS avec le bootloader. Parce que j'aimerai uniquement lister les OS et non les noyaux (Vhex sera "simplement" une librairie dynamique je pense) mais ça implique aux personnes qui développent un OS de charger le noyau à la main. Donc pour simplifier le développement et éviter que chaque OS utilise leur bootstrap pour initialiser la machine a chaque fois, je pense mettre en place des sortes d'"appel systèmes" propre au bootloader. Notamment un qui permettra de charger le noyau que l'on souhaite. Pour schématiser le processus d'initialisation d'un OS:
fxBoot (selection de l'OS) -> OS (demande de chargement du noyau "X") -> fxBoot (chargement du noyau "X") -> Kernel "X" (s'installe puis initialise la machine) -> OS (finit de s'initialiser)
Je sais que c'est techniquement réalisable avec mes connaissances actuelles, par contre je ne sais pas si c'est comme ça qu'il faut faire En tout cas, je pense qu'il est même possible de changer dynamiquement de noyau pendant le runtime (bon, il faut que le noyau sois capable de prendre des infos en paramètre) mais ça serait sympa car ça permettra de mettre a jours le kernel "à-la-volé". Mais il me manque encore à visualiser mentalement comment mettre en place des interfaces propre, viable et fiable. (Et il me manque el famosos driver USB >_<)
La gestion de la mémoire virtuelle non (à par mettre les infos des processus dans /proc/<PID> je ne peux pas faire grand-chose d'autre). Par contre pour l'USB oui mais je n'ai pas suffisamment de connaissance avec udev pour savoir exactement comment l'implémenter actuellement :/
Bien sûr et ce sera ma priorité car je compte utiliser cette machine pour dev la plupart des projets. À dire vrai c'est le portage de Vhex sur la graph35+EII qui ma fait me rendre compte que l'architecture du noyau étais vraiment pas adapté. Je sais aussi que le DMA risque d'être un gros problème en termes d'API (je n’ai jamais vraiment regardé le module pour être franc) mais je ne pense pas que ce sois le truc le plus complexe à surmonter.
Au passage, Casio utilise aussi le DMA sur la Graph35+EII avec Fugue.
hahah, pour l'instant ce ne sont que des idées. J'accepterai cette remarque uniquement le jour où tout ce bordel prendra vie
Citer : Posté le 04/10/2020 13:29 | #
Est-ce que tu es sûr de vouloir écraser le bootcode original ? :o
Ah c'est intéressant ça ! Est-ce que tu peux avoir accès aux pins de la ROM sans la démonter et sans poser de problème pour la calculatrice ?
Bonne nouvelle, pas besoin de tout réécrire donc ! J'aime bien l'idée de virtualiser ou non selon les cas. Par contre j'ai du mal à voir en quoi ça impacterait la compatibilité avec l'OS : parce que dans la mesure où l'OS n'est pas booté si tu te lances depuis la ROM, quelle compatibilité attends-tu ? Je soupçonne qu'il faut différencier ici le cas où tu bootes depuis la ROM de celui où tu bootes depuis un add-in.
Dans GRUB le fichier de config contient des entrées qui se réfèrent au binaire du kernel fourni par l'OS avec des options pour lancer le init de l'OS. Tu ne peux pas séparer un OS de son noyau normalement, donc le bootloader peut toujours charger le noyau qui lui-même charge l'OS.
Là je te suis plus, c'est assez bizarre. Ta première étape de l'OS va juste faire un unique appel qui sera identique pour tous les OS, autant spécifier dans la liste des OS dans fxBoot quel kernel charger tout de suite :
fxBoot (sélection de l'OS) → (lancement du paramètre "kernel") → Kernel "vhex" → (lecture des options, lancement du paramètre "vhex_init") → OS "GladOS"
Changer de noyau au sens "passer de Linux à BSD", non. Mettre à jour, ça dépend de la compatibilité binaire et ABI. Mais c'est une fonctionnalité vraiment pétée et c'est le genre de trucs pour lesquels soit il faut la collaboration du compilateur (thunks et autres shenanigans) soit il faut celle du linker/loader, à moins que ce soit vraiment la fonctionnalité phare de ton projet je te conseille pas d'aller par là.
Je connais pas les détails non plus mais sous Linux les drivers USB sont bien exécutés en mode privilégié et ensuite l'accès au périphérique est autorisé via /dev et avec udev pour donner des autorisations.
Super nouvelle ! Le DMA c'est pas dur à utiliser, dans gint j'ai eu aucun problème pour écrire le driver, le plus subtil a été de bien surveiller les passages gint/OS et de ne les faire qu'une fois que le DMA est inactif.
Certes, mais d'ici là, GG ! C'est clairement le projet bas niveau le plus abouti avec FiXoS, sinon plus.
Citer : Posté le 05/10/2020 09:37 | #
Ah c'est intéressant ça ! Est-ce que tu peux avoir accès aux pins de la ROM sans la démonter et sans poser de problème pour la calculatrice ?
Absolument certain, d'où mon projet de devboard pour réparer mes tests qui vont foirer Pour ce qui est de la ROM, mon idée originale étais de la dessouder, la ressouder sur ma devboard et relier les deux périphériques ensemble via une nappe IDE quelconque. Mais encore une fois, rien n'est fait c'est juste une idée de projet qui me semble réalisable. Pour l'instant j'ai juste désassembler les syscalls liés à l'EEPROM de la mono.
Ce qui me fait peur, c'est comment l'utiliser efficacement et à quel moment. J'ai trop peu utilisé ce truc pour savoir m'en servir correctement. Je pense privilégier les gros transferts de données (comme l'USB par exemple) et non pour les trucs triviaux (genre memcpy()).
Oups, oui, je parle bien de la partie "boot depuis un add-in". Parce que la question ne se pose pas si je suis déjà en ROM(?). Mais oublie la partie "boot depuis la ROM", car ce n'est absolument pas d'actualité en ce moment et j'ai peur d'avoir beaucoup de mauvaise surprise avec cette partie.
Là je te suis plus, c'est assez bizarre. Ta première étape de l'OS va juste faire un unique appel qui sera identique pour tous les OS, autant spécifier dans la liste des OS dans fxBoot
Je sais et c'est ce qui me pose problème avec l'architecture du bootloader. Comme tu l'as expliqué plus haut, il y aura deux façons de booter : depuis un addins et depuis la ROM. Sans parler du fait que la feature "boot depuis la ROM" risque de prendre beaucoup de temps à arriver. Je pressens que pas mal de personnes voudront garder l'OS de Casio (pour les addins, le calcule, les cours, ...) donc je vais privilégier la partie "boot depuis un addin". De plus, au vu de mon usage perso avec les addins, je sais que j'aurrais au moins deux "OS" qui se baseront sur le même noyau et j'aimerais ne pas avoir à dupliquer le code kernel à chaque fois que je veux faire un OS (question de place et aussi parce que sinon je risque de réécrire un gint-like ce qui est tout bonnement contre-productif au vu de la maturité de gint). C'est pour cette raison que j'essaie de séparer le noyau de l'OS, pour ne pas dupliquer inutilement du code.
Pour résumer, dans le contexte où je "boot depuis un addins", le noyau jouera le rôle d'une librairie dynamique (comme gint dans le fond). Mais en écrivant ces lignes, je crois que mélanger les objectifs / rôles du noyau avec cette notion de "boot depuis la ROM" et "boot depuis addins" est une erreur et je pense que la question du "boot depuis la ROM" aura le mérite d'être débattue quand j'en serais arrivé au stade de l'écriture en ROM.
Cependant, il est vrai que ta façon de faire serait vachement plus simple: ça m'éviterait de fetch les exceptions trapa et ça permettra de configurer le noyau plus finement. (Je pensais utiliser une extension genre "*.boot" pour indiquer un fichier de configuration d'un OS(?) ça sera vachement plus simple !)
Mettre à jour oui. Ça ne me semble pas si complexe que ça si je passe uniquement par le loader/linker et si j'ai une bonne architecture au niveau de la gestion de la mémoire, mais je n'ai pas encore regardé correctement tous les problèmes que cela engendre. Je vais attendre d'arriver tranquillement sur vhex pour me pencher correctement sur la question et je ferrai un post pour expliquer clairement mes idées et pour avoir vos avis.
Sinon pour ce qui est du projet, je suis actuellement en train de finaliser la 0.0.1 de FxLibc, il me manque encore le Makefile à peaufiner et trouver une architecture élégante pour la gestion des différentes ABI. Je vous tiendrai au courant des avancées sur un topic à part entière.
Citer : Posté le 05/10/2020 09:43 | #
J'en profite pour dire que c'est un truc que j'ai déjà fait, je conseille fortement l'achat d'un adaptateur type TSOP → DIP 48 qui permettra de ne pas avoir à ressouder la flash.
Le billet de blog que j'avais écrit n'est plus en ligne, je vais essayer de le poster quelque part histoire de ne pas perdre les infos.
Citer : Posté le 05/10/2020 10:05 | #
Ça c'est pas difficile à résoudre comme problème : teste, teste et teste encore ! Dans la RAM le DMA copie jusqu'à 3 fois plus vite que le processeur par paquets de 4 octets, donc tu as tout intérêt à l'utiliser pour les grandes tailles de memcpy(). C'est un super outil donc hésite pas à en user et abuser.
Cependant, il est vrai que ta façon de faire serait vachement plus simple: ça m'éviterait de fetch les exceptions trapa et ça permettra de configurer le noyau plus finement. (Je pensais utiliser une extension genre "*.boot" pour indiquer un fichier de configuration d'un OS(?) ça sera vachement plus simple !)
Je vois. Séparer le noyau de l'OS ça peut se faire sans trop de problèmes. Par exemple ton noyau Linux est dans /boot (sur Raspberry Pi c'est même un seul fichier /boot/kernel.img), et ça tu peux le partager entre deux OS si c'est une partition à part (les options du noyau indiquent qui est la partition système pour rappel). Donc puisque ça marche sur PC, tu peux totalement le faire aussi à ta façon sur la calculatrice.
Tu peux utiliser à peu près ce que tu veux comme format pour les fichiers donnant les différents OS que tu peux booter. Je pense qu'une extension est une bonne idée, tu peux aussi décider de ne regarder que dans un sous-dossier, par exemple fxBoot/*.txt (.boot ça ne passera pas je crois à cause de la taille des extensions ?).
Tout dépend de l'interface entre ton noyau et tes programmes. Mais tu dois penser à plusieurs choses :
• Il faut que ton noyau continue de répondre aux appels système, donc tu dois garder la même API et ABI (... évidemment)
• Il faut que ton nouveau noyau récupère les structures de données de l'ancienne version, y compris les processus, la table des descripteurs de fichiers, etc, donc si le format des structures a changé ça commence à être la merde et si les primitives d'allocation mémoire ont changé ça devient vraiment la merde
• Pareil pour les structures de données utilisées par ton allocateur (listes chaînées, arbres, etc)
• Il faut faire la mise à jour à un moment bien choisi où t'as pas des fonctions en cours d'appel qui vont se faire remplacer à cause de la pile (par exemple tu remplaces kmain() après avoir ajouté une nouvelle variable, la taille du stack frame correspond plus, corruption de pile)
• Et bien sûr il faut avoir essentiellement zéro pointeur vers du code du noyau (genre des fonctions de callback) puisque toutes les fonctions vont changer de place au moment où tu recharges le code
• Tout cela s'applique également aux modules noyau vu que c'est des libs dynamiques ; de plus, si tu veux pas avoir à redémarrer le noyau, tu as intérêt à préserver très agressivement le fonctionnement de ton loader noyau sinon tu perds les modules durant la mise à jour
• Si tu relocalises des modules, ce qui arrivera forcément un jour parce que leur taille changera, il faudra réinitialiser tous les thunks permettant d'accéder à ses fonctions ou re-patcher le code des autres modules pour corriger les fixups
• Et j'en paaaaasse. Honnêtement c'est vraiment vraiment dur. Si tu en vois pas où est la difficulté c'est peut-être que c'est trop sombre pour toi actuellement (sauf bien sûr si tu as déjà prévu la plupart de ces points).
Bon courage ! Comme je l'ai déjà mentionné je suis intéressé par une intégration multi-projets avec gint.
Citer : Posté le 08/10/2020 20:38 | #
Voilà, c'est de nouveau en ligne → https://blog.darks.fr/quoi-dneuf-docteur.html