Projet système PC : 2019 - EXERTIER Bastien, FRITZ Anthony, JICQUEL Vincent, LEQUEUX Gautier, LERBOURG Louis, OBERMEYER Emmanuel

De Ensiwiki
Aller à : navigation, rechercher
PCSEA

Ifzee.png

Développeurs EXERTIER Bastien
FRITZ Anthony
JICQUEL Vincent
LEQUEUX Gautier
LERBOURG Louis
OBERMEYER Emmanuel

Présentation

Introduction

Durant ce projet nous avons eu l'occasion d'implémenter notre premier système d'exploitation, en nous basant sur les connaissances que nous avions assimilées durant le cours de PCSEF du semestre dernier. Nous avons pu implémenter des fonctionnalités basique des systèmes d'exploitation telles que les sémaphores, les files de messages ou encore la mémoire virtuelle.

Objectifs

  • Comprendre le fonctionnement des différents composants d'un système d'exploitation
  • Savoir utiliser une documentation technique
  • Identifier et corriger les erreurs à l'aide d'un debugger
  • Travailler en équipe


Journal de bord

Semaine 1 (05/02 et 08/02)

  • Prise en main de l'environnement du projet (Phase 1).

Semaine 2 (13/02 et 15/02)

Découpage des tâches de la phase 2:

  • Récupération de l'horloge du projet PSCEF et adaptation avec les signatures de fonctions imposées
  • Récupération des processus du projet PCSEF et adaptation avec les signatures de fonctions imposées
  • Découverte des tests
  • Prise en main des queues

Semaine 3 (20/02 et 22/02)

Début de la phase 3:

  • Implémentation de la fonction start -> création de processus fonctionnelle
  • Endormissement et réveil des processus fonctionnels
  • Gestion de la terminaison des processus

Semaine 4 (06/03 et 08/03)

Phase 3 :

  • Terminaison des processus
  • Gestion du waitpid

Début de la phase 4: Implémentation des files de message

Semaine 5 (13/03 et 15/03)

Phase 3:

  • Ajout des tests (0 à 4) dans la partie kernel et adaptation.
  • Quelques changements nécessaires au bon fonctionnement des tests.

Phase 4:

  • Files de messages
  • début d'implementation des semaphores

Semaine 6 (20/03 et 22/03)

Phase 3:

  • Ajout des tests (5 à 10) dans la partie kernel et adaptation.
  • Ajout de certaines fonctionnalités pour faire passer les tests (shm côté kernel).

Phase 4:

  • implementation files de messages
  • tests de semaphores

Phase 5:

  • Lecture de la spécification

Semaine 7 (27/03 et 29/03)

Phase 3:

  • Correction du test 6


Phase 4:

  • Debug des files de messages
  • sémaphores terminés

Phase 5:

Semaine 8 (03/04 et 05/03)

Phase 3:

  • Debug des tests
  • Correction de la filiation des processus

Phase 5:

  • compréhension du partage mémoire


Semaine 9 (10/04 et 12/04)

phase 4:

  • écriture appel système en assembleur et test pour les passages de valeurs dans les registres

phase 5:

  • mise en place des structures pour le partage mémoire
  • Écriture des appels système en assembleur
  • Écriture des traitants d'interruptions

phase 6:

  • Debug des interruptions et début d'implémentation de la console

Semaine 10 (17/04 et 19/04)

phase 5:

  • Débug appel systèmes et sauvegarde des bons registres

phase 6:

  • implémentation de la console

Semaine 11 (01/05 et 03/05)

phase 5:

  • écriture appel des système en macro

phase 7:

  • interprète de commande

Etat du projet

Phase 1

100 %

Tâches:

  • Lecture du sujet
  • Récupération du git
  • Prise en main de l'environnement de travail
  • Interface avec les primitives d'affichage


Commentaires:

Cette phase constituait le début de notre projet, il fallait donc prendre en main la documentation, mettre en place le travail de groupe et récupérer une partie du travail effectué en PCSEF. Cette phase n'a pas posé de problèmes particuliers.

Phase 2

100 %

Tâches:

  • Gestion des processus
  • Gestion du temps et des interruptions systèmes

Commentaires:

De la même façon que pour la phase 1, cette phase reprenais pour beaucoup le travail de PCSEF, que nous avons cependant du un peu adapté car certains appels systèmes avaient des signatures différentes mais il n'y a pas eu de grandes difficultés rencontrées.

Phase 3

100 %

Tâches:

  • Ordonnancement des processus
  • Endormissement des processus
  • Terminaison des processus
  • Test de ce qui précède (phase 2 et 3) au niveau kernel


Commentaires: Nous avons crée une filiation entre les processus pour que le père puisse attendre et éventuellement récupérer les valeurs de ses fils. Cette phase est la première phase sur laquelle nous avons du passer plus de temps. En effet, nous avons souhaité avoir une partie noyau qui soit la plus fonctionnelle possible avant de passer à la suite, et surtout avant de passer à la mise en place du côté utilisateur. Nous avons donc adapté tous les tests fournis dans la partie utilisateur au noyau afin de pouvoir tester celui-ci. Cela a demandé pas mal de travail car la plupart des tests ne passait pas directement et nous devions donc trouver le problème avant de passer au suivant. De plus, l'une des difficultés rencontrées a été la gestion des processus mourant et les tests nous ont permis de nous rendre compte que certains points concernant leur gestion n'avait pas été compris correctement et nous avons donc pu les corriger.

Phase 4

100 %

Tâches:

  • Implémentation des files de messages
  • Gestion de l'endormissement de processus

Commentaires:

  • Files de messages : nous avons créé une structure file de message qui est un buffer circulaire stockant les messages envoyés. Des primitives permettent d'agir sur cette structure (fm_is_full, fm_ecrire_file(file, message)). Nous avons aussi créé des primitives permettant à un processus appelant de se bloquer en lecture ou en écriture sur une file. Pour une file de message, ce blocage est représenté par deux queue stockant la structure des processus bloqués en écriture pour l'une et en lecture pour l'autre. Chaque processus possède un champ buffer_ecriture stockant le message à envoyé si la file est pleine, ou le message reçu après blocage si la file était vide.

Phase 5

80 %

Tâches:

  • Séparation des espaces mémoires
  • Mode utilisateur
  • Gestion des appels systèmes

Commentaires:

La phase 5 est la phase qui nous a posé le plus de problèmes. C'est une grosse phase qui nécessite beaucoup de lecture avant de commencer, et sa compréhension n'est pas aisée.

Nous allons donc essayer de faire le tour des différents problèmes que nous avons pu rencontrer.


Pour la gestion des appels systèmes, nous avons eu des difficultés à comprendre le découpage nécessaire entre le côté utilisateur et le côté noyau et l'endroit où il était nécessaire de sauvegarder les registres. De plus, au moment où nous sommes arrivés sur ce problème, la mémoire n'était pas encore terminé. Nous pensons après coup qu'il est plus intéressant de bien finir la mémoire avant de passer à cette phase car il est très compliqué de tester. Ainsi, nous avons décidé de faire nos appels systèmes côté utilisateur en assembleur, à l'aide de macro et de récupérer l'interruption côté noyau en assembleur avec appel d'un handler en C qui récupère les paramètres et fait l'appel système. L'une des difficultés rencontrées a été le changement dans la TSS que nous avons donc effectué dans traitant noyau en assembleur.

De plus, il est très important de bien comprendre comment ESP0 (pile kernel) est stocké dans TSS+4 pour permettre de retrouver la bonne pile lors d'une interruption. Il faut donc bien stocker la valeur de ESP0 du prochain processus lors d'un context switch dans TSS + 4.

Le traitement des défauts de pages se fait de la même manière que les interruptions programmées/matérielles.

Un point qui nous a bloqué est l'implémentation des fonctions shm_create, shm_acquire, shm_delete en mode user. Nous utilisons des chaînes de caractère comme clé pour table de hashage. Ces chaînes sont contenues dans la mémoire user. Lorsqu'on appelle shm_acquire depuis un second processus, la clé donnée va être comparée avec la clef du premier processus, qui n'est donc plus accessible. Il faut donc allouer les clefs lors de shm_create dans l'espace kernel.

Structure de la mémoire virtuelle:

Voici comment est structurée la mémoire virtuelle de nos processus. Nous avons placé arbitrairement le code user à 1G, la pile user à 2G, le code de la fonction exit de user à 3G et la dernière entrée de la table des pages comme mémoire mémoire partagée.

                    +--------------+ [4Gio] = 0xFFFFFFFF
                    |              |
  1 table des pages +- SHARED MEM -+  
                    |              |   
                    +--------------+            
                    |              |             
                    |              |
                    |   EXIT_CODE  |
                    +--------------+ [3Gio]
                    |       .      |
                    |       .      |
                    +--------------+
                    |       .      |
                    |  USER STACK  |                  
                    |       .      |
                    +--------------+ [2Gio] = 0x80000000
                    |       .      |
                    |       .      |
                    |       .      |
                    |   USER CODE  |
                    +--------------+ [1Gio] = 0x40000000
                    |              |
                    | KERNEL MEMORY|
                    |              |
                    +--------------+ [0Gio] = 0x0


Fonctionnalités restantes à implémenter

  • Libération de la mémoire user
  • Protection de l'espace user avec iopl à 0
  • Tests de sauvegarde de registre et se sécurité de code

Phase 6

100 %

Tâches:

  • Implémentation du pilote de clavier par interruptions

Commentaires:

  • La gestion du clavier a demandé une partie de compréhension quant au fonctionnement du code fournit (keyboard_glue).
  • La gestion du clavier est géré par une structure de tampon contenant une string, une taille et un indicateur de validité de la string (si un processus a déjà utilisé la string alors elle n'est plus valide).
  • Quand un processus demande une entrée utilisateur, il se bloque sur une file de message de façon à laisser l'utilisateur taper son message. Cependant, si aucun processus ne demande d'entrée mais que l'utilisateur réalise des frappes clavier, il ne faut pas remplir la file de message, car ce qui est tapé ne doit pas être utilisé par un processus. Pour réaliser ce fonctionnement, on n'ajoute pas de message après une frappe sur la touche entrée mais on reset la file. De cette façon tous les processus en attente sur une entrée utilisateur se réveillent, le plus prioritaire lit le message et l'invalide, et tous les autres se rendorment.
  • Deux primitives afficher_char et supprimer_char ont été ajoutées pour afficher et supprimer les caractère spéciaux.

Phase 7

100 %

Tâches:

  • Implémentation du shell

Commandes disponibles :

  • ps : Affiche les processus
  • sh : lance un nouveau shell
  • exit : ferme le shell lancé par la commande sh
  • start-user : lance les tests user
  • clear : Efface l'écran
  • finfo : Affiche les ids des files de messages
  • help : affiche les commandes disponibles.

Commentaire :

Nous n'avons pas rencontré de difficultés particulières concernant cette phase.


Extension

25 %
  • Semaphores : Mécanisme codé mais non terminé de déboguer. les premiers tests passent pour des processus en mode kernel. Les primitives système sont cependant non fonctionnelles en mode User (Ce n'était pas la partie la plus prioritaire).

Conclusion

En conclusion, nous pouvons dire que nous avons réussi à implémenter une grande partie des fonctionnalités demandées malgré les quelques erreurs restantes que nous aurions aimé pouvoir résoudre avant la fin du projet. Ce projet nous a également permis d'appliquer les connaissances théoriques que nous avons pu voir en cours et de comprendre comment sont implémentés les différents concepts se basant sur la matériel sous-jacent comme la représentation d'un processus en mémoire.