Projet système PC : 2014 - BISEGNA Tony, DENNEMONT Fabien et PACALET Xavier

De Ensiwiki
Aller à : navigation, rechercher
InfiniteShell OS
InfiniteShell OS - Screenshot 1.png
Projet Système d'Exploitation 2014

Développeurs BISEGNA Tony
DENNEMONT Fabien
PACALET Xavier


Présentation

Voici la page de présentation de notre OS nommé InfiniteShell OS développé dans le cadre du projet de spécialité de l'Ensimag en 2014.

Equipe

BISEGNA Tony : filière ISI

DENNEMONT Fabien : filière ISI

PACALET Xavier : filière ISI

Fonctionnalités

Toutes les fonctionnalités obligatoires demandées dans les spécifications ont été implémentées, notre système permet donc :

  • De lancer des processus en mode user isolés entre eux et ayant uniquement la possibilité de toucher à leurs propres données (le kernel est protégé)
  • Les processus users peuvent faire des appels au système pour effectuer des actions particulières (affichage, lecture de fichiers, etc.)
  • Tous les processus users sont ordonnancés de sorte que l'utilisateur du système ait l'impression qu'ils s’exécutent simultanément (pour des processus de même priorité).


De nombreuses extensions ont été réalisées et sont présentées plus en détail plus bas sur cette page :


  • Shell amélioré :
    • Possibilité d'ouvrir plusieurs shells et de switcher entre eux lorsqu'une commande s’exécute (commande 'newshell [<nom_nouveau_shell>]' puis F1 et F2 pour naviguer)
    • Auto-complétion et suggestions avec la touche TAB, listant pour le premier mot les commandes disponibles, et pour les suivants les fichiers et les dossiers du répertoire courant
    • Possibilité de récupérer les anciennes commandes entrées avec les flèches haut et bas
    • Possibilité d'effacer les caractères frappés avec la touche Backspace
    • Possibilité de "scroller" dans la console avec les touches PLUS (+) et MOINS (-), la molette de souris PS/2, les touches PG_UP et PG_DOWN (scroll d'un écran entier à la fois), et les touches HOME et END (scroll au maximum)
    • Possibilité de tuer un processus avec CTRL+C
    • Possibilité de nettoyer la console avec CTRL+L


  • Système de fichier FAT32 :
    • Création, suppression de fichiers
    • Ajout de lignes dans des fichiers
    • Création de dossiers
    • Navigation dans l'arborescence des répertoires


  • Lecteur de musique :
    • Lecteur de musique utilisant le haut-parleur interne de la carte mère (fonctionne uniquement sur une machine et pas dans l'émulateur, mais Bochs affiche une trace quand le haut-parleur est mis sur ON ou sur OFF)
    • Le lecteur effectue une analyse syntaxique d'un fichier décrivant une partition musicale au format ABC et applique les règles de lecture d'une partition musicale (tonalité, altérations accidentelles, hauteur, rythme, tempo) pour calculer et jouer les notes de la partition
    • Des partitions de musique au format ABC sont disponibles dans le répertoire 'musics' ; tapez "play" suivi du nom du fichier pour lire une partition


  • Autres extensions :
    • Commande 'ps' pour lister les processus courants (à l'exception des shells par choix), puis 'kill pid' pour tuer le processus voulu
    • Récupération de l'heure du PC au démarrage


Commandes disponibles

  • Commandes liées aux tests
    • autotest : Lance tous les tests
    • testXX : Lance le test n°XX avec XX de 0 à 22
  • Système de fichiers
    • ls : Liste le contenu du dossier courant
    • cd [<path>] : Permet de naviguer entre les dossiers
    • mkdir <dirname> : Nouveau dossier dans le dossier courant
    • touch <filename> : Nouveau fichier dans le dossier courant
    • cat <filename> : Affiche le contenu d'un fichier
    • addl <filename> <ligne> : Ajoute une ligne à un fichier existant
    • rm [filename] : Supprime un fichier
  • Autres commandes
    • newshell [<name>] : Ouvre un nouveau shell en parallèle
    • infiniteshells : Ouvre 1000 shells (stress+perf test)
    • play <musicfile> : Joue une musique (machine réelle seulement)
    • addreveil <heures> <minutes> <fichier> : Ajoute un réveil (joue la partition donnée à l'heure donnée)
    • showreveils : Affiche tous les réveils programmés
    • ps : Affiche les processus lancés et leurs PID (sauf shells par choix)
    • kill [pid] : Tue le processus de PID donné
    • clear : Nettoie la console
    • reboot : Redémarre le systeme
    • help : Affiche les commandes disponibles


Vidéo

Voici une petite vidéo présentant notre OS en action sur une machine réelle (booté sur clef USB) : Présentation InfiniteShell OS sur YouTube

Captures d'écran

  • Création de dossier, de fichiers et ajout de lignes dans les fichiers :

InfiniteShell OS - Screenshot 2.png


  • Lecture d'une musique :

InfiniteShell OS - Screenshot 3.png


  • Commande help :

InfiniteShell OS - Screenshot 4.png


  • Auto-completion :

InfiniteShell OS - Screenshot 6.png


  • Ajout de réveils :

InfiniteShell OS - Screenshot 5.png

Conseils pour les années suivantes

Nous avons eu du mal à trouver toutes les informations nécessaires dans le wiki, il sera parfois utile de vous renseigner sur d'autres sites, voici donc les liens qui nous ont éclairé :


Pour réaliser la phase 5, nous vous conseillons d'y aller petit à petit, voici une progression par étapes dont vous pouvez vous inspirer pour éviter d'avoir plusieurs problèmes à résoudre simultanément :

  • Avant de commencer :
    • Réalisez avant tout un système stable qui gère des processus lancés directement en mode kernel (comme en TP PSE)
    • Soyez sûr que vos interruptions horloge et votre ordonnanceur fonctionnent (tests poussés)


  • La pagination :
    • Commencez par créer une table des pages par processus, et remplissez la de sorte qu'elle soit identique à celle du système (identité de 0 à 256Mo, real_addr == virt_addr).
    • Mettez à jour votre Context Switch pour modifier le registre CR3 du processeur. Une fois que cela fonctionne comme avant, vous savez que votre structure de table des pages et votre Context Switch sont OK. (pour modifier le pointeur vous devez écrire dans le registre %cr3)
    • Maintenant vous pouvez commencer à lancer le code des applications users qui vous est fourni dans la table des symboles, au lieu de placer dans la pile du processus l'adresse d'une fonction qui vous est passée en paramètre. (Pour l'instant ne cherchez pas à le copier puis le mapper à l'adresse 1Go)
    • Vous devez maintenant réutiliser votre propre allocateur (celui du TP SEPC) qui doit allouer les adresses 64Mo à 256Mo :
      • Allouez alors avec cet allocateur l'espace nécessaire pour stocker le code de l'application user.
      • Copiez le code dans le bloc mémoire que vous venez d'allouer.
      • Réglez la pile de votre processus pour qu'il démarre à l'adresse de ce bloc.
    • Maintenant vous pouvez ajouter une entrée dans la table des pages de votre processus pour faire correspondre l'adresse virtuelle 1Go au bloc que vous avez alloué, et faites démarrer votre processus à l'adresse 1Go.
    • Faites de même avec la pile maintenant, vous devez l'allouer entre 64Mo et 256Mo, la mapper à l'adresse de votre choix (par exemple 2Go) et l'utiliser à la place de celle précédemment présente dans la structure du processus. (Attention : le pointeur de pile remonte les adresses durant l'exécution, donc n'oubliez pas de mettre le pointeur de pile à la fin du bloc que vous avez alloué)


  • Les appels système :
    • Avant de vous attaquer au mode user, commencez par gérer les appels systèmes, car comme vous l'aurez remarqué, vos applications utilisateurs ne peuvent pas appeler les fonctions du kernel. Voici comment cela se passe :
      • 1 : L'application user sauvegarde ses registres
      • 2 : L'application user met dans des registres (%edi, %esi, %edx, %ecx, %ebx, et %eax) des valeurs particulières (numéro de l'appel système et ses paramètres)
      • 3 : L'application user lance une interruption "int $49" (ici, si le processus avait été en user mode, il serait passé en kernel mode, car le traitant le spécifie)
      • 4 : Le processeur saute à l'adresse spécifiée dans le traitant d'interruption 49 (que vous devez paramétrer de la même façon que le traitant de l'horloge par exemple)
      • 5 : Le traitant lit les registres qui ont été préparés par l'application user et réalise l'appel système
      • 6 : Le traitant fait un "iret" pour repasser à l'application user (ici, si le processus appelant était en user mode avant le int $49, il y repasse automatiquement)
      • 7 : L'application restaure ses registres et continue son exécution
    • Faites au moins le syscall "cons_write" pour pouvoir printer correctement avant de passer à la suite. Pour les étapes 1 à 3 et 7, regardez le fichier user/lib/weak-syscall-stubs.S pour comprendre. L'étape 4 est similaire à ce que vous avez fait pour l'interruption horloge. Les étapes 5 à 6 sont à réaliser côté kernel également comme le traitant horloge.


  • TRES IMPORTANT, plusieurs problème apparaissent avec le mode user et ne sont a priori pas indiqués sur le Wiki :
    • Pour qu'une page soit utilisable (lecture ou écriture) par le processeur quand il est en mode user, vous devez ajouter un flag supplémentaire à votre table des pages, sinon vous obtiendrez directement un Trap 0E. Il y a un flag USER_PAGE à régler, consultez le lien suivant pour connaître les détails : Paging
    • Il y a également un flag à placer dans la table des traitants d'interruptions. Actuellement vous placez certainement 0x8E00 dans le deuxième octet de votre traitant : ceci interdit les users d’exécuter les interruptions, pour les autoriser vous devez placer le flag 0xEE00 sinon vous aurez un écran bleu dès que vous essayerez de faire un appel système...
    • Info Post-Soutenance : Dans tous vos traitants d'interruptions, vous devez remettre les registres DS, ES, FS, et GS à 0x18 puis de nouveau à 0x4b à la fin du traitant, car l'interruption et le iret gèrent seulement les registres CS et SS.


  • Le mode User
    • Vous n'allez plus pouvoir lancer vos processus simplement en faisant un "ret" comme dans votre Context Switch actuel. Pour changer de niveau de privilège vous devez changer de segment (ils sont déjà définis, il suffit d'indiquer au processeur celui qu'on veut utiliser). Il y a 6 registres de segments à modifier, et c'est très simple : être en mode user équivaut à avoir le registre CS = 0x43, et on met les autres (SS, DS, ES, FS, et GS) à 0x4b.
    • Vous pouvez modifier directement ces registres, à l'exception de CS et SS qui doivent être écrits à l'aide d'une instruction "iret". Cette instruction dépile simplement cinq valeurs depuis le sommet de pile et les stocke dans des registres spéciaux : SS, ESP, EFLAGS, CS, et EIP. Vous devez donc "simuler une fausse interruption" en pushant les valeurs adéquates pour que votre processus soit bien positionné sur son code et sa pile après l’exécution du 'iret' par le processeur.
    • Ainsi si vous pushez dans l'ordre : $0x4b, [pointeur de pile du processus (ESP)], [les flags] (instruction pushf), $0x43, et [Adresse du début du code du processus (EIP)]. L’exécution de l'instruction iret aura pour effet de démarrer votre application en mode user ! En revanche vous devriez essayer de commencer en utilisant $0x10 au lieu de $0x4b et $0x18 au lieu de $0x43, ainsi si vous avez bien pushé vos valeurs avant d'appeler iret, votre processus démarrera comme auparavant en mode kernel. Une fois que cela fonctionne mettez les bonnes valeurs (ie. $0x4b et $0x43).
    • Enfin, lorsque l'application user va lancer une interruption qui réclame un changement de privilège (c'est-à-dire toutes dans notre cas), le processeur va obligatoirement changer de pointeur de pile, c'est pourquoi il faut 2 piles par processus (fonctionnement nécessaire pour des questions de sécurité à mon avis). Le processeur va mettre dans ESP l'adresse qu'il trouve dans la TSS+4 (c'est à dire à l'adresse 0x20004) vous devez donc simplement modifier le contenu de cette zone mémoire à chaque Context Switch. Vous devez également mettre 0x18 à l'adresse 0x20008 car le processeur change également le registre SS en switchant de pile.


J'espère que ces informations auront aidé certains d'entre vous :) Pensez à consulter les liens donnés plus haut pour des infos complètes.

Apports et problèmes rencontrés

Ce projet nous apporté de nombreuses connaissances sur les systèmes d'exploitations en général et sur leur développement. Il nous a permis de mettre directement en application des concepts étudiants en cours durant cette année. Lors de ce projet nous n'avons pas rencontré de problèmes techniques particuliers, cependant il était parfois compliqué de bien répartir le travail entre les membres.

Téléchargez notre kernel.bin

Notre OS est bootable sur machine réelle et sur des émulateurs type Qemu et Bochs, vous pouvez le télécharger pour le tester : Fichier:Infinite-Shell-OS-Kernel.zip