Projet système PC : 2021 - BLANCO Manon, VUAILLAT Benjamin

De Ensiwiki
Aller à : navigation, rechercher
Screenshot from 2021-06-24 12-12-04.png
Titre du projet Le Magicien d'OS
Cadre Projet système

Équipe Manon BLANCO Benjamin VUAILLAT
Encadrants Yves Denneulin , Gregory Mounie, Patrick Reignier

Présentation

Vous trouverez sur cette page des informations concernant le mini système d'exploitation développé par Manon BLANCO et Benjamin VUAILLAT dans le cadre du projet système de 2ème année de la formation en apprentissage de l'ENSIMAG.

Équipe

Manon BLANCO

Benjamin VUAILLAT

Résultat

Voici le binaire de notre OS si vous souhaitez le tester sur un émulateur : kernel.bin

Et nous pouvons ici que les tests fournis passe correctement via une commande shell (voir phase 7)  :

MagicienDOS-TestUser.png

Organisation

Planning prévisionnel

PlanningPrevisionnel-MagicienDOS.png

Planning réel

PlanningReel-MagicienDOS.png

L'écart sur le planning que nous avions imaginé en début de projet peut s'expliquer par la mauvaise estimation du temps nécessaire pour faire la phase 3. Elle fut en effet, bien plus longue que prévu du fait de nombreux problèmes qui nous sont apparus au lancement des tests fournis. Ensuite, la phase 5 a été assez rapide car nous avons pu compter sur l'aide de plusieurs groupes qui avaient déjà passé cette étape. Cela nous a permis de gagner beaucoup de temps de débug.

Développement

Pour le développement, nous nous sommes organisés en pair programming. Avec une personne qui code et l'autre qui regarde la documentation et apporte un regard extérieur. Nous alternions régulièrement afin que nous puissons coder tout les deux régulièrement.

Phases du développement

Phase 1 : Prise en main de l'environnement

100 %

Durant cette phase nous devions implémenter la fonction console_putbytes du kernel pour pouvoir utiliser le printf. Pour cela nous avons suivi la séance 1 de PSE.

Cette première implémentation nous a permis de prendre en main l'environnement de travail et le squelette fourni. Aussi, cette implémentation est importante puisqu'elle nous permettra par la suite de déboguer plus facilement.

Ressource utilisée

Phase 2 : Création et lancement de processus de niveau noyau

100 %

Par la suite, nous avons dû implémenter :

  • le changement de contexte
  • la gestion de l'horloge

Pour le changement de contexte, nous avons suivi le séance 2 de PSE.

Pour la gestion de l'horloge nous avons suivi la séance 3 de PSE. A la fin de la cette séance, il y avait une horloge indiquant depuis combien de temps le système a démarré. Pour l'affichage nous avons repris les fonctions développées lors de la phase 1. Ces nouvelles fonctions d'affichage étaient donc là uniquement pour avoir un retour visuel de l'horloge et étaient à supprimer par la suite.

Ressources utilisées

Phase 3 : Ordonnancement, création dynamique et terminaison de processus de niveau noyau

100 %

Durant la phase précédente, nous avions développé deux grandes fonctionnalités (changement de contexte et horloge) sans les lier. C'est avec la phase 3 que nous avons mis en place le changement de contexte selon l'horloge interne. Pour cela nous avons suivi la séance 4 de PSE.

Puis, nous avons mis en place la gestion du cycle de vie des processus dont :

  • l'endormissement avec la séance 5 de PSE
  • la terminaison avec la séance 6 de PSE
  • la filiation entre les processus en suivant les spécifications

Pour ces dernières séances nous nous sommes un peu éloigné de l'implémantation proposée pour l'adapter à notre code actuel et aux tests attendus.

Nous avons suivi les primitives systèmes des spécifications pour cette phase en implémentant les fonctions :

 int getpid(void);
  • d'initialisation :
 int start(int (*pt_func)(void*), unsigned long ssize, int prio, const char *name, void *arg);
  • de terminaison :
 void exit(int retval);
 int kill(int pid);
  • de priorité :
 int getprio(int pid);
 int chprio(int pid, int newprio);
  • d'attente :
 void wait_clock(unsigned long clock);
 int waitpid(int pid, int *retvalp);
  • de gestion d'horloge que nous n'avions pas fait à la phase 2 :
 void clock_settings(unsigned long *quartz, unsigned long *ticks);
 unsigned long current_clock();

Nous avons aussi supprimé les fonctions qui nous avaient été utiles précédemment mais qui ne servaient plus à présent.

Pour tester notre implémentation nous avons copier/coller les tests utilisateurs dans le dossier kernel en les modifiant pour pouvoir les lancer directement depuis le kernel. A la fin de cette phase les huit premiers tests passaient.

Ressources utilisées

Phase 4 : Gestion des communications et synchronisation de processus de niveau noyau

100 %

Pour cette phase, nous devions implémenter la gestion de file de messages. Nous avons suivi les spécifications et les signature des méthodes à implémenter les fonctions :

  • de création
int32_t pcreate(int32_t count);
  • de suppression
 int32_t pdelete(int32_t qid);
 int32_t preset(int32_t qid);
  • de réception (lecture)
 int32_t preceive(int32_t qid, int32_t *message);
  • d'envoie (écriture)
 int32_t psend(int32_t qid, int32_t message);
  • d'accès
 int32_t pcount(int32_t qid, int32_t *count);

Pour cette phase nous avons mis en place des fonctions internes notamment pour le réveil et endormissement des processus en fonction des actions faites sur les files.

Puisque nous avions mis en place les tests à la fin de la phase précédente, notre développement a donc été principalement guidé par ces derniers. Cela nous a permis de régler plus de bug potentiels en cours de développement et a donc rendu plus facile le deboggage de fin.

C'est une partie assez volumineuse en nombre de ligne de code à écrire mais qui est assez rapide car beaucoup plus algorithmique. Les problèmes de pile et de mémoire ayant été résolu dans la phase 3.

Ressources utilisées

Phase 5 : Séparation des espaces mémoire noyau et utilisateur : gestion de processus utilisateur

100 %

La phase la plus complexe de notre projet. Elle a pour objectif de mettre en place la gestion de la partie utilisateur de l'OS. C'est à dire de pouvoir séparer les processus en 2 catégories indépendantes : Kernel et User. Cette partie est essentiel pour la suite du projet, car pour que l'OS puisse intéragir avec un utilisateur il faut qu'il y ait cette séparation afin de protéger le noyau du système.

Pour cela nous avons procédé en plusieurs étapes :

  • Transformation de la pile kernel et ajout de la pile user
  • Création de l'appel des fonctions systèmes du côté user
  • Lancement de l'interruption 49 avec sauvegarde des registres (comme pour la clock) et ajouts des arguments
  • Création du traitant de l'interuption 49
  • Appel, côté kernel, des fonctions systèmes
  • Réception côté user des valeurs de retours renvoyées via des registres

Après avoir fait toute ces étapes, il a fallu relancer les tests côtés user et corriger les nombreux bugs qui ont été créés par ce changement. C'est une partie qui prend aussi énormement de temps au vu de la complexité du code à ce moment là. En effet, les appels qui circulent entre la partie kernel et user rendent la compréhension totale plus compliquée.

Ressources utilisées

Phase 6 : Gestion du clavier et implémentation d'un pilote de console

100 %

Cette phase a pour objectif d'ajouter la gestion du clavier dans notre OS. Concrètement, cela se résume par l'affichage et la lecture des touches appuyées par l'utilisateur.

Le fonctionnement est assez simple, nous avons développé la gestion de l'interruption du clavier (33).

La lecture et l'écriture se fait à partir d'un tampon circulaire dont nous avons défini la capacité maximale.

Les fonctions suivantes ont été implémentées :

 void cons_echo(uint32_t on);
 unsigned long cons_read(char *string, unsigned long length);
 void cons_write(const char *str, unsigned long size);

Concernant la fonction cons_read, nous avons été obligé de modifier les tests car la signature de ces derniers et des spécifications divergaient. Cela a nécessité un peu de changement pour avoir un affichage des tests corrects.

Ressources utilisées

Phase 7 : Implémentation d'un interprète de commandes

100 %

Cette phase a été assez rapide et développée en parallèle de la finalisation de cette page ensiwiki.

Elle a pour objectif de rajouter un shell et un interpréteur de commandes. Pour faire cela nous avons commencé par créer une fonction shell appeler par le processus principal de user. A l'aide des fonctions écritent dans la phase 5 nous récupérons ce que l'utilisateur vient de taper et nous vérifions que cela correspond à une des commandes que nous avons développé. Après, le fonctionnement est similaire aux appels systèmes déjà effectué à la phase 5.

Nous avons différentes commandes utilisables par l’utilisateur dont voici la liste :

  • run-test : Lance l'interface de test
  • sys-info : Affiche le nombre maximum de processus/file possible et le nombre actuel
  • ps : Affiche l’arbre des processus
  • logo : Affiche le logo de l’OS
  • clear : Efface la console
  • exit / quit : Quitte le shell
  • help : Affiche la liste des commandes avec une courte description

Ressources utilisées

Extensions

Nous n'avons pas eu le temps de développer des extensions pour notre OS.

Journal de bord

Semaine 1

Lundi 7 juin

Phase 1 :

  • Lecture de la documentation
  • Prise en main de l'environnement
  • Développement de la fonction printf pour le kernel

Mardi 8 juin

Phase 2 :

  • Changement des processus (context switch)
  • Début de la gestion du temps pour l'ordonnancement des processus

Mercredi 9 juin

Phase 2:

  • Fin de la gestion du temps pour l'ordonnancement (affichage d'une horloge)

Jeudi 10 juin

Phase 1 et 2:

  • Refactoring du code : utilisation des bons types
  • Amélioration de l'affichage de la console

Vendredi 11 juin

Phase 3:

  • Journée peu productive...

Semaine 2

Lundi 14 juin

Phase 3:

  • Refactoring de la liste d'ordonnancement (pour utiliser les fonctions de queue.h)
  • Fin de l'ordonnancement
  • Début de la terminaison

Mardi 15 juin

Phase 3:

  • Fin de la terminaison
  • Début de la filiation
  • Mise en place des tests
  • Correction des parties précédentes via les tests

Mercredi 16 juin

Phase 3:

  • Fin de la filiation
  • Correction des parties précédentes jusqu'au test 8 (ensuite, il est nécessaire d'avoir fait la phase 4)

Jeudi 17 juin

Phase 4:

  • Développement des files de messages
  • Correction du code pour les premiers tests sur les files de messages (9 à 13)

Vendredi 18 juin

Phase 4:

  • Gros changement pour corriger une erreur de compréhension (preceive et psend, s'exécute immédiatemment)
  • Correction du code pour les tests sur les files de messages (9 à 17), seul le test 16 ne passe pas encore. (les tests 18, 19, 20 concernent la phase 5)

Semaine 3

Lundi 21 juin

Phase 4:

  • Correction de la phase 4 pour que tous les tests possibles à ce stade passe.

Phase 5:

  • Lecture de la documentation et des wiki des anciens élèves
  • Création des 2 piles (user / kernel)
  • Protection de la mémoire
  • Début développement des appels des fonctions systèmes par les processus user

Mardi 22 juin

Phase 5:

  • Fin du développement
  • Lancement des tests via un processus user et correction des bugs sur les tests déjà passé auparavant (1 à 17)
  • Gros debuggage sur le test 17 qui avait des résultats plus ou moins aléatoire (problème de clock)
  • Nettoyage du code et écriture de commentaires

Mercredi 23 juin

Phase 5:

  • Lancement des tests 18 et 20 en mode user
  • Fix d'un bug sur les processus bloqués qui empechait le bon déroulement du test 20.

Phase 6:

  • Début développement de la gestion du clavier dans la console

Jeudi 24 juin

Phase 6:

  • Fin développement et correction par rapport aux tests
  • Debug de l'affichage des tests

Autre :

  • Enrichissement de la page web
  • Création du logo à l'ouverture de l'OS

Apports

Le projet nous a évidemment renforcé notre compréhension du fonctionnement d'un OS et a permis de mettre en pratique plusieurs points vu en cours de Système d'Exploitation. De plus, la pratique du pair programming a permis de niveler le niveau du groupe, le meilleur sur certains sujets entrainait le moins bon. Cela a permis d'améliorer notre niveau individuel.

Difficultés

  • Compréhension / documentation

C'est la principale difficulté que nous avons rencontrée. En effet, pour les phases très orienté sur la configuration du système (gestion de pile/mémoire, création des processus, etc ...) les problèmes et bugs venait d'une mauvaise compréhension de la documentation ou des spécifications. Heureusement que certain anciens élèves ont mis des conseils sur leurs pages wiki qui nous ont permis de nous débloquer plusieurs fois.

  • Débbugage

Une autre difficulté rencontrée fut la partie débuggage du projet, nottament lorsque nous lancions les tests fournis en mode user. En effet, au vu de la complexité du programme après la phase 5, il devenait de plus en plus complexe de trouver l'origine des bugs.