Projet système PC : 2015 - DEFOURNE Maximilien, MIRGHANE Kaizar, FOUASSIER Raphaël

De Ensiwiki
Aller à : navigation, rechercher
New oschar screenshot.png
Titre du projet OS'Char*
Cadre Projet système d'exploitation 2015
Page principale Projet_système

Équipe MIRGHANE Kaizar DEFOURNE Maximilien FOUASSIER Raphaël
Encadrants BENIAMINE David MORIN Gaetan MOUNIE Gregory,


Présentation générale

Objectif

L'objectif de ce projet est la réalisation d'un système d'exploitation pour PC très simplifié. Il permet d'aborder une grande partie des concepts vu en cours de SEPC durant la deuxième année d'apprentissage et de faire quelques rappels sur les cours d'architecture de première année.

Equipe

L'équipe est composé de 3 alternants de la promotion 2016:

  • Kaizar MIRGHANE
  • Raphaël FOUASSIER
  • Maximilien DEFOURNE

Cahier des charges

Spécifications

Le projet dans son ensemble est décrit par plusieurs page sur l'ensiwiki, tout d'abord sa présentation qui regroupe un annuaire de liens utiles pour le projet.

Ensuite vient la page qui regroupe toutes les spécifications du projet, c'est l'ensemble de fonctionnalités minimales à implémenter.

En accord avec ses spécifications, la page concernant les aspects techniques donne de large indications sur la construction du projet.

Roadmap du projet

Le projet est pré-découpé en 7 phases + les extensions :

  • Phase 1 : 100% Environnement de travail + pilote écran pour utiliser printf.
  • Phase 2 : 100% Changement de contexte + interruption horloge.
  • Phase 3 : 100% Terminaison de processus + filiation + ordonnancement selon la priorité.
  • Phase 4 : 100% Files de messages + sleep + tests côté kernel.
  • Phase 5 : 100% Mode kernel/user + appels systèmes côté user + test côté user.
  • Phase 6 : 100% Gestion du clavier.
  • Phase 7 : 100% Implémentation d'un shell minimal.


  • Extensions (optionnel) : 87,5%
    • 100% Taskbar : Gérer par le kernel via le pilote vidéo pour informer l'user de l'uptime et l'occupation du processeur
    • 100% Système de fichier en mémoire : système de fichiers en mémoire (aucune écriture disque), basé sur un arbre n-aire (chaque noeud peut avoir N enfants) dynamique
    • 100% Pilote disque dur IDE : le noyau peut lire et écrire sur le disque dur par blocs de 512 octets. On utilise les ports Programmable Input Output (PIO) du processeur pour accèder aux deux contrôlleurs IDE (une évolution possible serait d'implémenter le DMA pour l'accès à de grandes quantités de données)
    • 100% Sémaphores : conforme à la spécification des sémaphores.
    • 100% Shell enrichit : gestion de la couleur + des commandes avec arguments.
    • 25% Système de fichier ext2 : En cours de développement. Actuellement nous arrivons à lire le superblock ext2 (contenant les informations du système de fichiers). Les objectifs suivants sont la lecture et l'écriture de fichiers et le parcours de l'arborescence des fichiers.

Choix techniques

IDE :

Gestionnaires de version :

Planning

Oschar-gantt.png

Fonctionnalités

Shell

Le shell propose à la fois plusieurs commandes internes mais il peut aussi lancer toute une série de processus externes, tout est résumé dans la commande help du shell :

Shell oscar.png

Appels systèmes

Tous les appels systèmes pour les apprentis ont été implémentés tels que définis dans les spécifications. Cependant, nous avons pris la liberté d'implémenter d'autres appels pour enrichir les possibilités de l'espace user :

  • set_color : Change la couleur du texte (voir écran pour les couleurs)
  • ps : Affiche la liste des processus avec leur PID - Nom - Statut
  • reboot : Redémarre l'OS

Plusieurs appels sont liés au système de fichier en mémoire :

  • mfs_touch : crée un fichier en mémoire. Il faut lui donner le chemin vers le dossier dans lequel va être créé le fichier et le nom du fichier.
  • mfs_mkdir : crée un répertoire en mémoire. Ici aussi il faut lui donner un chemin vers le dossier contenant.
  • mfs_init : initialise le système de fichiers en mémoire et crée le dossier racine '/'
  • mfs_info : récupère la taille du fichier (dont le chemin est passé en paramètres).
  • mfs_read : lit N octets du fichier précisé en paramètres
  • mfs_write : écrit N octets dans le fichier précisé (attention: supprime les anciennes données présentes)
  • mfs_ls : liste le contenu du répertoire passé en paramètre (si on lui passe false, rien ne sera écrit à l'écran) et renvoie le nombre d'éléments contenu dans ce dossier
  • mfs_exist : test si un le nom d'un chemin de fichier correspond à un fichier existant
  • mfs_is_dir : test si le chemin correspond à un répertoire
Oscar fs.png

Barre d'état système

La taskbar est une fonctionnalité propre au kernel et au pilote d'affichage, son rôle est d'afficher :

  • l'uptime du système. Pour cela on prend la fréquence de l'horloge par exemple 50Hz, donc toutes les 50 interruptions on augmente l'uptime d'une seconde.
  • l'occupation du processeur. Pour cela on créé un compteur qui compte le nombre d'interruptions horloge faite depuis le processus idle. Ainsi à chaque rafraîchissement de la taskbar on regarde le ratio nb_tick_idle/nb_tick_taskbar, en oubliant pas de réinitialiser les compteurs après.
Oschar taskbar.png

Bilan

Difficultés rencontrées

  • Phase 4 : les files de messages ont été une fonctionnalité compliquée à appréhender. La spécification peut donner lieu à plusieurs interprétations. En conséquence, lors de la validation des tests en fin de phase 4, notre implémentations du système de producteurs/consommateurs pour les files de messages été fausse.
  • Phase 5 : concernant la séparation du mode kernel et du mode user. Cela ne demande finalement pas beaucoup de code, mais plutôt beaucoup de compréhension. Or les informations sont dures à trouver sur le wiki, il a fallu se tourner vers la page projet d'anciens élèves qui expliquent cette phase de manière plus exhaustive.
  • Phase 6 : la spécification du cons_read est tout sauf simple à comprendre. De plus le test concernant cet appel système ne marchait pas, il a fallu attendre un correctif pour le valider.
  • Debug : il est impossible de débugger avec GDB le code écrit en espace user. Si cela est possible, il est alors très dure d'accéder à la documentation qui explique comment faire.

Conseils pour les suivants

  • Debug ASM kernel : par défaut le Makefile du kernel ne génère pas le débug pour les fichiers assembleurs .S. Pour cela il faut ajouter l'option -g dans la variable ASFLAGS du Makefile kernel. Sinon, on peut utiliser stepi et nexti dans gdb à la place de step et next.
  • Files de messages :
    • Les files de messages respectent le schéma du producteur/consommateur. Cependant il y a un aspect à bien comprendre, lorsqu'un psend() ou preceive() se met en attente, le processus qui le réveillera court-circuitera le tableau de message ! En effet, il doit communiquer directement avec sans passer par le stockage du message dans la file !
    • Exemple : on fait un preceive() qui se bloque. Ensuite un psend() arrive, il voit qu'un processus preceive() est en attente, il lui passe directement son message sans stocker son message dans la file. Puis il repasse le processus preceive() en READY. A contrario, si psend() voit qu'aucun preceive attend, il stocke alors son message dans la file.


  • cons_read : le cons_read a une spécification assez compliquée à comprendre. Il faut bien saisir qu'aucun \n n'est transmit ! Il est en effet écrit dans le buffer du clavier mais on transmet uniquement les caractères précédents. Voici 4 exemples :
    • Exemple cons_read(ptr, 5) : le buffer du clavier contient a|b|c|\n, je transmets alors a,b,c et j'efface \n car je n'ai pas transmis 5 char.
    • Exemple cons_read(ptr, 5) : le buffer du clavier contient a|b|c|d|e|\n, je transmets alors a,b,c,d,e et je n'efface pas \n car j'ai transmis mes 5 char. Le buffer contient alors juste \n.
    • Exemple cons_read(ptr, 5) : le buffer du clavier contient \n, je ne transmets aucun caractère (ligne vide) et j'efface \n du buffer car je n'ai pas transmis 5 char.
    • Exemple cons_read(ptr, 5) : le buffer du clavier contient a|b|c|d|e|f|g\n je transmets alors a,b,c,d,e et je n'efface pas \n car j'ai transmis mes 5 char. Le buffer contient alors f|g|\n.

Dans tous les cas l'appel à cons_read est bloquant, seul une interruption clavier \n peut le débloquer.


  • Fonction de terminaison : lors de l'initialisation de la pile user, il faut préciser une adresse de retour sur laquelle le processus va jump lorsqu'il fera 'return'. Cependant cette initialisation de la pile se fait côté kernel et la fonction sur laquelle jump se trouve côté user. Problème le kernel ne connait pas les fonctions user sauf pour user_start ; la compilation va donc échouer. Pour contourner cela, une des solutions possibles consiste à écrire la fonction de terminaison côté kernel en assembleur en l'entourant par deux labels : un au début et un à la fin. Ainsi dans l'initialisation du kernel, il faudra calculer l'espace que prend la fonction en faisant l'opération label_de_fin - label_de_debut. Ensuite il faudra faire un user_mem_alloc de la taille calculée, enfin il suffit de faire un memcpy du code côté kernel vers l'espace alloué côté user via user_mem_alloc, d'ailleurs le pointeur renvoyé par user_mem_alloc sera votre pointeur de fonction côté user vers votre fonction de terminaison, il n'y a plus qu'à la copier dans la stack user.

Liens utiles