Projet système PC : 2012 – Nils RENAUD, Hamza RIHANI et Sofian SENHAJI

De Ensiwiki
Aller à : navigation, rechercher


CallOS
CallOS.png

Développeurs Nils RENAUD
Hamza RIHANI
Sofian SENHAJI

Présentation

Équipe (Équipe 1)

Notre équipe se compose de trois étudiants :

Notre encadrant est Gregory Mounier.

Motivations

Nous avons choisi ce projet de spécialité (création d'un OS) afin de pratiquer les connaissances que nous avons acquises lors des cours de Systèmes d'exploitation et programmation concurrente, et Conception des Systèmes d'Exploitation. De plus l'idée de développer un noyau pour faire fonctionner une machine nue nous attirait particulièrement.

Déroulement

Le projet s'est déroulé sur quatre semaines, du lundi 21 mai 2012 au vendredi 15 juin 2012 (rendu et soutenance). Les principales phases de développement ont été réalisées à l'ENSIMAG en salle système(D201).

Réalisation

Implémentation du cahier des charges

Préparation

Nous avons suivi les cours de Système au cours des deux semestre de notre année de 2A, nous avions donc nos propres sources des fonctions d'affichage sur l'écran et d’ordonnancement basique de plusieurs processus. Cela nous a permis de démarrer rapidement en sachant à peu près d'où partir.

Phase 1 : Affichage à l'écran

Grâce aux cours de Conception de systèmes d'exploitation que nous avons suivi, nous avions déjà écrit ces premières briques d'un système d'exploitation. Nous n'avons donc pas eu de mal à les réimplanter dans le code qui nous était fourni. Et cela nous a permis d'explorer l'environnement dont nous allions nous servir pendant quatre semaines.

Phase 2 : Gestion de processus

C'est une phase importante car elle introduit des concepts clés pour le projet. Elle consiste à gérer:

  • dans un premier temps, la notion de processus et de changement de contexte entre deux processus ;
  • dans un second temps, le timer et les interruptions, pour obtenir un système à temps partagé.

Encore une fois nous avons pu nous inspirer des codes que nous avions déjà fait pour implémenter cette gestion du temps et des processus. Cependant nous devions voir plus large pour mettre en place une structure de processus adapté pour la partie suivante.

Phase 3 : Ordonnancement

Cette étape est la suite directe de la phase précédente. Elle consiste à gérer tout ce qui concerne le cycle de vie des processus, toujours en mode superviseur. Nous vous conseillons de procéder par étapes, dans l'ordre qui suit:

  • gestion de l'ordonnancement par le scheduler, et de la création dynamique des processus;
  • gestion de la terminaison des processus;
  • gestion de la filiation.

Cette partie est absolument cruciale ! En effet, sans celle ci, il est impossible de commencer les phases 5 et plus. Il faut donc arriver à la sécuriser assez rapidement afin de se reposer sur des bases solides pour la suite.

Phase 4 : Communication entre processus

Cette phase consiste à implémenter les sémaphores de Dijkstra et le cas échéant la gestion de l'endormissement de processus. Nous avons pu réaliser cette étape en parallèle de la précédente, mais nous devions attendre d'avoir fini la phase 3 pour pouvoir tester la communication entre processus efficacement.

Phase 5 : Mode Kernel/User

  • Séparation physique du noyau et de l'application

Le noyau et l'application sont deux programmes indépendants qui ne partagent pas de mémoire. Le noyau met en place une protection qui empêche l'application de lire ou écrire des données du noyau. Il est donc impossible pour l'application d'appeler des fonctions du noyau. C'est pourquoi nous avons été amenés à écrire une bibliothèques des appels noyau.

  • Réalisation d'une bibliothèque des appels noyau

Comme on veut laisser au programmeur la facilité d'écrire dans son code des appels au noyau par appel de fonction, il faut écrire tout un ensemble de fonctions (une par appel noyau) qui auront pour but d'exécuter une instruction int.

  • Écriture du module de récupération de l'int.

L'application déclenche une interruption par int, il faut bien la récupérer dans le noyau. Il est donc nécessaire d'écrire un traitant pour gérer ces interruptions logicielles. Pour retrouver les paramètres de l'appel noyau et les passer à la routine du noyau qui en a besoin, nous avons utilisé les registres du processeur. Cependant cette solution limite le nombre de paramètres à six, mais ce n'est pas un problème.

  • Lancement des processus de l'application en mode esclave.

Une fois le système démarré, la seule possibilité d'executer un processus est de le lancer en mode esclave, c'est à dire dans un mode (proposé par intel) où certaines actions luis sont interdites afin de ne pas perturber le fonctionnement interne du système.

  • Gestion de deux piles par processus.

En effet, la partie kernel de l'application va devoir utiliser des données qui lui sont accessible (à elle uniquement) afin de gérer l’ordonnancement des processus et les appels système que fait le processus en cours. Ce formalisme est quasiment obligatoire pour se conformer aux spécifications du processeur Intel x86 concernant le passage d'un mode à un autre.

  • Protection de l'espace des entrées/sorties

L'espace des registres d'E/S ne doit être accessible qu'en mode maître. Cette protection peut être mise en oeuvre en affectant un iopl de 0 dans les flags de l'application. Pour les besoins des sorties des programmes de test, vous devrez donc créer un appel système cons_write pour gérer l'affichage à l'écran.

Phase 6 : Pilote de console

Il s'agit du premier périphérique que nous avons été amené à utiliser : le clavier. Cette phase nous a permis de comprendre un type de gestion de périphérique, ce qui allait nous être utile pour la suite. De plus nous avons à plusieurs reprises ajouté une reconnaissance de certaines touches spécifiques du clavier (PGUP, PGDOWN, Echap, Ctrl+C)

Phase 7 : Shell

Commande help
Cmd help.png
Affichage de la commande help

Cette partie consiste à implémenter un interprète de commandes, ce shell est un programme utilisateur. La liste des commandes est donnée dans le tableau ci-dessous :

Commande Description

ps

Affiche la liste des processus en cours d'exécution et leurs états respectifs

help

Affiche la liste des commandes disponibles

exit

Quitte la console

clear

Efface l'écran

diapo

Lance le mode graphique et affiche l'écran d'accueil de CallOS

sleep <sec>

Endort la console pendant sec secondes

beep

Emet des bips

date

Affiche la date et l'heure du système

sinfo

Affiche les informations sur les sémaphores

divzero

Lance un test de division par zéro

echo

Active ou désactive l'affichage à l'écran pendant la saisie

philo

Lance le test du dîner des philosophes

toto

Lance un test de processus en boucle active (Ctrl + C pour terminer)

lspci

Affiche la liste des périphériques du bus PCI

lspci <bus> <dev> <fun>

Affiche des informations sur le périphérique sélectionné

shutdown

Arrête le système

De plus, si l'écran effectue un défilement, on peut revenir un écran en arrière avec la touche "page précédente" et retourner sur le dernier écran avec la touche "page suivante" du clavier, ce qui peut être utile pour récupérer une commande plus haut grâce à une extension implémentée.


Extensions

Pilote de Souris

Souris
Souris.png

Copier-coller souris
Souris cc.png

La première extension que nous avons réalisée a été un pilote de souris PS/2. Le déplacement de la souris provoque une interruption, le traitant qui lui est associé permet, en particulier de récupérer deux octets représentant le déplacement de la souris. Nous avons également écrit un module qui permet de gérer le copier-coller de texte sur la console. Cette fonctionnalité est particulièrement utile pour répéter des commandes shell par exemple.



Utilisation des hauts parleurs système

Le second pilote que nous avons implémenté permet d'effectuer un bip d'une fréquence et de durée voulue en utilisant le haut-parleur du PC. L'émission d'un bip peut se faire par la commande beep depuis la console.

Gestion de l'extinction

Il existe plusieurs interfaces qui assure la gestion de la consommation des ordinateur et permette leur extinction en tout sécurité. l'ACPI est l'interface la plus répandue mais très complexe à implémenter. Nous avons donc opté pour l'interface APM (Advanced Power Management) qui passe par le mode réel et effectue des appels BIOS. Pour éteindre CallOS il suffit de taper la commande "shutdown" dans la console. Il existe plusieurs paramètres offert par APM et qui effectuent différentes fonctions (extinction, mise en veille, redémarrage, ... etc) Ces fonctions sont standardisées. Malheureusement plusieurs constructeurs ne respectent pas les standards c'est donc pour cette raison que la commande shutdown peut avoir un comportement différent (durant nos test, "shutdown" éteint le système sur machine virtuelle, le redémarre sur les PC de l'école ou même déconnecte et arrête le système sans éteindre la machine sur nos PC personnels.)

Détection des périphériques

Commande lspci
Cmd lspci.png
Résultat de la commande lspci

Commande lspci détails
Cmd lspci details.png
Résultat de la commande lspci 0 3 0

Le Peripheral Component Interconnect (PCI) est un standard de bus local (interne) permettant de connecter des cartes d'extension sur la carte mère d'un ordinateur. L'un des intérêts du bus PCI est que deux cartes PCI peuvent dialoguer entre elles sans passer par le processeur. Nous avons écrit un pilote de PCI permettant de récupérer des informations sur les périphériques connectés sur ce bus. La commande lspci permet de lister l'ensemble des périphériques disponibles ainsi que le constructeur du périphérique. Pour plus de détails concernant un périphérique, on peut utiliser la commande lspci <bus> <dev> <fun>.



Affichage en VESA

Comme autre extension au projet, nous avons réalisé un driver pour la carte graphique. Nous avons décidé d'implémenter un driver standard : le standard VESA. C'est un standard implémenté sur la plupart des cartes graphiques et qui permet d'avoir une plus grande résolution que le mode texte, il permet de dessiner des pixels de 256 à 16 millions de couleurs. Pour notre système on a utiliser le VBE 2.0. Afin de pouvoir passer en mode VESA, nous avons dû faire des appels en mode réel. La première difficulté qu'on a eu c'était d'adapter nos structure de registre pour que celle-ci tiennent sur un des adresses mémoire inférieures à 1Mo. Nous nous sommes inspiré de l'exemple donné dans la documentation VESA pour implémenter notre code. En premier temps, Nous voulions exploiter les performances de ce mode et adapter les sous-couche de la fonction printf pour avoir une console en grande résolution. Cependant le débogage nous a pris beaucoup de temps et on s'est contenter de faire une commande "diapo" qui affiche un diaporama d'image en différente résolution (par défaut 1024x768 si aucune n'est précisée) et en 32 bits/pixel! Sur une machine virtuelle, on peut sortir de la commande en appuyant sur ESC. En machine réelle le retour en mode VGA fait planter le système (C'est sûrement dû à la non conformité des constructeurs aux standards). Le système devrait afficher un logo avant de donner la main à l'utilisateur. Cette personnalisation à été désactiver pour la version "machine réelle" du kernel. Les images affichées ont été convertit par Gimp un éditeur d'image sous Linux. Celui-ci donne une structure définissant les couleurs des pixels (en 32bits/pixel). Les couleurs sont données dans l'ordre: Bleu, Vert, Rouge, on a dû donc adapter notre fonction d'affichage pour lire les pixels dans l'ordre (Rouge, Vert, Bleu pour le mode RGB de VESA).
Logo CallOS Logo Ensimag


Système de fichier FAT32

Enfin, alors que le projet touchait à sa fin, nous avions trouvé intéressant d'implémenter un système de gestion de fichiers. Notre choix s'est porté sur le système de fichier FAT32. Cependant, en l'absence de pilote de disque dur, nous avons été contraint de réaliser le système de fichier dans la mémoire en allouant une zone particulière inutilisée jusqu'à présent (48Mo à 64Mo). L'implémentation du système de fichier n'est pas terminé à ce jour.

Bilan

Organisation du projet

Nous nous réunissions tous les jours de 8h30 à environ 19h à l'ensimag, dans la salle D201. Lors des Week-ends nous nous rendions dans une salle de travail d'une résidence étudiante.

Difficultés rencontrées

Dès les premières phases de débuggage, nous nous sommes rendu compte de la grande difficulté du projet : la complexité à débugger ! Il fallait parfois des jours pour arriver à faire marcher notre code. La deuxième difficulté est la complexité de compréhension de certaines extensions (VESA par exemple) où, malgré la documentation, il faut creuser pour arriver à faire fonctionner certaines fonctionnalités.

Références

  • Documentation intel: [1]
  • OSDev.org
    • Driver souris PS2: [2]
    • Driver haut parleur système: [3]
    • Bus PCI: [4]
  • Documentation VESA: [5]
  • Appels au BIOS: code emprunté à Simon Nieuviarts.

Outils

  • VirtualBox: outil de virtualisation
  • Mercurial: gestionnaire de versions
  • Vim, Emacs: éditeur de code
  • Planner: éditeur de plannings
  • ddd: débogueur
  • Gimp: Editeur d'image