Projet système PC : 2011 - Bachir Kosayyer, Timothé Mermet-Buffet et Philippe Roussille

De Ensiwiki
Aller à : navigation, rechercher


SeriOS
Serious Guru is serious

Développeurs Bachir KOSAYYER
Timothé MERMET-BUFFET
Philippe ROUSSILLE

Présentation

Équipe (Équipe 1)

Nous sommes une équipe de trois étudiants :

Notre encadrant est Franck Rousseau.

Motivations

Nous avons choisi le thème du Projet système comme projet de spécialité, en fin de deuxième année à l'ENSIMAG. Nous avons conçu un noyau de système d'exploitation, "SeriOS", développé à partir des sources minimales fournies.

Il n'est pas commun de participer à la création d'un système d'exploitation, et comme nous avions tous trois suivi les cours de Systèmes d'exploitation et programmation concurrente, Pratique du Système et Conception des Systèmes d'Exploitation. Comme la programmation d'un noyau nous était inconnue, nous avons vu dans ce projet la possibilité d'approfondir et de mettre en pratique les connaissances théoriques vues en cours au travers d'un produit concret.

Cadre du projet

Le développement du projet s'est organisé en deux principales étapes :

  • répondre au cahier des charges (synthétisé ici)
    • multi-tâche : plusieurs processus (programmes) doivent pouvoir s'exécuter « en même temps » sur le système en partageant les ressources;
    • synchronisé : les processus peuvent attendre un ou plusieurs processus en utilisant des sémaphores;
    • mode utilisateur : l'utilisateur du système doit pouvoir utiliser les fonctions du système dans un environnement protégé, séparant les applications et le système.
  • fournir une ou plusieurs extensions conséquentes (pilotes et/ou fonctions avancées du système)

Déroulement

Le projet s'est déroulé sur quatre semaines, du mardi 17 mai 2011 au vendredi 10 juin 2011 (rendu et soutenance). Les principales phases de développement ont été réalisées en salle système (D201).

Réalisation

Cahier des charges minimal

Liminaire

Nous avions tous trois fait le TP de PSE, le code de cette partie a pu être adapté facilement (timer, clavier et écran) pour nous permettre de faciliter le débogage et de surveiller l'état du système.

Création de processus, ordonnancement et changement de contexte

La première étape a été la conception de la structure adaptée aux processus, ainsi que la gestion de leurs piles respectives. L'étape cruciale est la partie de changement de contexte (faite en assembleur), car toutes les autres parties en dépendent. Une fois cette étape terminée, nous avons pu gérer les sémaphores et la filiation de processus, les attentes et blocages des processus. Nous nous sommes concentrés sur la partie noyau uniquement.

Passage au mode noyau et appels systèmes

Une fois notre noyau fonctionnel en mode privilégié (mode kernel), nous avons réalisé le passage en mode utilisateur (userland) pour offrir une couche de protection et d'abstraction à un programmeur d'applications. Nous modifions également l'espace d'adressage et de pile nécessaire à une allocation de mémoire plus importante, tout en empêchant l'écriture dans la zone mémoire privilégiée. Il a ensuite été nécessaire de fournir des fonctions permettant un passage au mode privilégié pour utiliser les fonctionnalités du système.

Shell

Lorsque nos appels systèmes ont été terminés, nous avons réalisé le pilote console nécessaire à la création du shell, ainsi que les commandes permettant de tester et de montrer les fonctionnalités de notre système d'exploitation. Plusieurs commandes sont disponibles (accessibles par la commande 'help' au sein de l'interface en ligne de commande) :

Commande Utilisation Description

about

about

Affiche la banderole de l'équipe.

beep

beep DURÉE FRÉQUENCE

Utilise le haut-parleur système pour produire un bip à la fréquence et la durée données.

clear

clear

Efface l'écran.

chprio

chprio

Utilise le haut-parleur système pour produire un bip à la fréquence et la durée données.

clock_settings

clock_settings

Renvoie les paramètres de l'horloge.

collect

collect PID

Collecte un zombie et le termine.

date

date

Affiche la date actuelle au format UNIX.

echo

echo on|off ou echo [-n] [texte]

Active/désactive l'écho ou affiche du texte.

exception

exception

Provoque une exception mémoire (écriture en zone noyau).

exit

exit

Termine le shell et met fin à la session en cours.

getprio

getprio PID

Renvoie la priorité du processus PID.

kill

kill PID

Tue le processus PID. Il n'est pas possible de tuer un processus système.

help

help [commande]

Affiche la liste des commandes disponibles, ou une aide sur la commande spécifiée.

ps

ps

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

sleep

sleep TEMPS

Attend TEMPS millisecondes.

sinfo

sinfo

Affiche les informations disponibles sur les sémaphores utilisés.

startx

startx

Lance une démonstration de l'interface graphique (appel ne retournant pas).

tests

tests

Lance la suite de tests fournie par les encadrants.

utime

utime

Renvoie le temps d'utilisation du système (en millisecondes).

write

write FICHIER [TEXTE]

Crée le fichier FICHIER et écrit TEXTE dans ce fichier.

Les commandes de gestion du système de fichiers sont disponibles dans le répertoire /bin.

Extensions réalisées

Fonctionnalités systèmes

Mémoire virtuelle

La mise en place d'un système de gestion de mémoire virtuelle se subdivise en deux parties :

Pagination

La pagination consiste à découper la mémoire en zones de 4ko, dites pages. Celle-ci est réalisé sur deux niveaux :

= Pagination noyau =

On mappe à l'identique les 64Mo de la mémoire dédié au noyau. De ce fait aucun réel changement n'est perçu par le système. En particulier les allocations mémoires se font toujours à l'aide de mem_alloc.

= Pagination utilisateur =

Physiquement la mémoire de la partie utilisateur s'étend à partir de 64Mo jusqu'à la fin de la mémoire disponible. Virtuellement, la mémoire commencera à 1Go pour chaque processus. L'association entre adresse physique et adresse virtuelle est réalisée à l'aide de la fonction pgalloc. Celle-ci renvoie l'adresse d'une page libre et la marque comme utilisée. Elle remplace donc la fonction mem_alloc.

Pour gérer correctement la mémoire utilisateur, une segmentation est nécessaire.

Segmentation

La segmentation a pour but de séparer la mémoire d'un processus en trois parties

  • le segment de code (zone mémoire contenant le code exécutable)
  • le segment de pile (zone dédiée à la pile)
  • le segment du tas (zone réservé au tas)


Application

Lors de la mise en place de la mémoire virtuelle d'un processus, on procédera en trois étapes :

  • On associera l'adresse 1Go (virtuelle) à l'adresse physique de début de l’exécutable du processus.

Cette association s'étendra sur une zone de taille correspondante à celle en mémoire du binaire de l’exécutable. La détermination de cette taille, connue seulement après compilation, pourra avoir lieu manuellement ou automatiquement à l'aide d'un script. Cette taille sera aligné sur une page vu qu'on alloue uniquement des zones de taille 4ko.

  • À 1Go plus le nombre de pages nécessaire pour le segment de code (adresse virtuelle) on place la pile du processus.
  • Et à la suite de la pile, on référence le tas. Les allocations pour ce processus se feront donc uniquement dans cette zone.


Pagination et Segmentation

L'intérêt de ce découpage est multiple :

  • Il n'est plus nécessaire de copier le binaire de l'user dans le kernel. Il nous suffit de bien associer l'adresse virtuelle à l'adresse physique où commence l'exécutable du processus. En particulier il y aura un seul binaire même pour plusieurs instances d'un même processus.
  • Chaque processus se croit le seul à être exécuté sur la machine.
  • Un partage de ressource est dès lors simple à mettre en place : deux processus pourront aisément partager la même pile ou le même tas.
  • Si la gestion du disque dur est active, la mémoire d'un processus pourra être étendue.



Dans notre système d'exploitation, la pagination kernel est opérationnelle.
Toutefois, la pagination user n'est pas encore fonctionnelle.

  • Le segment de code est bien initialisé;
  • Par contre, le segment de pile génère des problèmes...
Système de fichier virtuel

Particularités :

  • Enregistrement de système de fichier auprès du VFS.
  • Montage/Démontage de système de fichier.
  • Primitives communes respectant en partie la norme POSIX.
  • Création/Renomage/Suppression de fichiers et de répertoires.
  • Écriture/Lecture dans un fichier.
  • Exécution de fichier (format spécial pour notre OS).

Le VFS se constitue en 3 parties :

    • Les primitives
    • Les systèmes de fichiers.
    • Les descripteurs de fichiers.
Les primitives

Les primitives du VFS correspondent aux appels systèmes qui peuvent être exécuté depuis l’espace utilisateur pour utiliser un système de fichier. Ces primitives sont :

  • Système de fichier :
    • int vfs_mount(char *type, char *path, void *options);
    • int vfs_unmount(char *path);
  • Gestion des répertoires :
    • int mkdir(char *path);
    • DIR *opendir(char *path);
    • struct dirent *readdir(DIR *dir);
    • int closedir(DIR *dir);
  • Gestion des fichiers :
    • int open(char* file, int flag);
    • int write(int fd, const void* buf, size_t length);
    • size_t read(int fd, void* buf, size_t length);
    • int close(int fd);
    • int rename(const char* oldpath, const char* newpath);
    • int unlink(const char* pathname);
  • Création d’un fichier exécutable :
    • int mkbin(char *path, ptr_bin program);
Le système de fichier : memfs

Afin de pouvoir utiliser le VFS, nous avons nous avons réalisé est un système de fichier en mémoire, basé sur une structure simple. Ce qui nous permet de simuler un vrai système de fichier sur un périphérique.

Les descripteurs de fichiers
Amélioration du shell

Le shell supporte les variables d'environnement (PATH, PWD, ?...), la séparation des commandes internes et processus, ainsi que l'exécution des commandes depuis le système de fichiers.

Pilotes d'accès aux périphériques

Nous avons réalisé trois principaux pilotes.

Pilote de souris

Nous avons choisi d'implémenter un pilote de souris PS/2. Le pilote est chargé au démarrage du système avec les pilotes nécessaires (souris, haut-parleur, console...). La souris bascule automatiquement dans le mode le mieux adapté (deux boutons, activation de la roulette...). Nous fournissons un appel système pour accéder à l'état de la souris, ainsi qu'un gestionnaire d'événements accessible en mode utilisateur. Il est possible de redéfinir l'espace tri-dimensionnel dans lequel évolue la souris à tout moment.

Pilote de haut-parleur

Le second pilote implémenté permet d'effectuer un bip d'une fréquence et durée choisie en utilisant le haut-parleur PC. Un bip à une fréquence par défaut est également disponible par l'appel beep().

Pilote de carte graphique VESA

Le troisième pilote permet de fournir à l'utilisateur une abstraction de la carte graphique, garantissant un accès direct à la mémoire vidéo avec les primitives graphiques nécessaires (affichage d'un pixel, tracé de rectangles...). Le pilote permet à l'utilisateur de spécifier une résolution et une profondeur de couleur, et choisit le mode graphique le mieux adapté à ces contraintes.

Couche d'abstraction graphique

Afin de permettre une gestion simple et claire de la mémoire vidéo, nous fournissons une couche d'abstraction graphique optimisée, permettant l'utilisation de surfaces et de rect inspirées librement de la librairie SDL (gestion du clipping automatique et fusion alpha). Pour permettre à l'utilisateur d'écrire du texte, nous avons rendu disponible la création dynamique de polices à partir de surfaces - fonction qui peut être aisément supplanté au pilote de console pour fournir un environnement graphique complet. Le gestionnaire de fenêtre minimal utilise la police libre de droit Unispace. L'ajout de ressources graphiques au projet est facilité par l'utilisation du script Python fourni.

Captures d'écran

Le shell TinySH Utilisation du système de fichiers Interface graphique minimaliste

Binaires

Notre noyau est disponible ici, le script de transformation des images est disponible ici (nécessite PIL). Le noyau peut tourner sur machine virtuelle VirtualBox à condition de réserver au moins 128 Mo (mémoire paginée).

Bilan

Organisation du projet

Nous avons travaillé dans les locaux de l'Ensimag, du lundi au samedi, par journées complètes (9h-13h et 14h-20h). Dans le cas où une partie de l'équipe n'était pas disponible, nous utilisions GTalk et Skype pour coordonner les actions de l'équipe.

Nous avons séparé le travail en tâches minimales, réalisables par chacun des membres du groupes, afin d'optimiser la répartition et la réalisation du projet.

Difficultés rencontrées

Les problèmes les plus sérieux sont apparus au moment de la mise en place des extensions.
Nous étions alors moins encadrés dans notre travail et nous devions la plupart du temps parvenir à surmonter les difficultés seuls. Qui plus est, certains bugs "dormants" surgissaient à ce moment, ce qui compliquait davantage la tâche.
Et si, tant bien que mal, l'extension fonctionnait, un "merge" avec le travail des autres provoquaient parfois des bugs très persistants et délicats à corriger.
Lors de la création des pilotes, et notamment le pilote VESA, il nous a fallu un temps conséquent pour comprendre les appels BIOS et le passage entre les modes réel et protégé, ainsi que le choix d'une zone mémoire correcte, ce qui nous a ralenti en conséquence et a rendu plus chaotique la correction de bugs à ce niveau.

Points positifs

Le projet système se distingue des autres projets de spécialités en de nombreux points :

  • Il est unique en son genre puisqu'on programme à un très niveau bas (de plus, il est d'ailleurs rare qu'on développe plus d'un système d'exploitation dans sa vie);
  • C'est un projet assez difficile à déboguer car on manipule les piles, la mémoire, les registres, etc;
  • Il est délicat à mettre en place à cause de nombreuses parties critiques (changement de contexte, appels système, ...).

Malgré tout cela, nous conserverons de ce projet un très bon souvenir.
Ce fut une expérience riche et intéressante qui vaut la peine de vivre au moins une fois dans sa vie.
Réaliser ce système nous a permis de cerner de nombreuses notions qui peuvent paraître floues si on les abordent uniquement par la théorie. Mieux encore, des notions plus pointues sont maintenant moins obscures.
Qui plus est, certaines critiques très vulgarisées comparant les performances entre Windows, Mac OS et Linux nous paraissent à présent très nuancées.

Points négatifs

Pour un projet de cette ampleur, les 3 semaines et quelques jours dont nous disposions paraissaient ridicules.
Certes, la partie minimale a nécessité une dizaine de jours pour être fonctionnelle, mais les extensions demandent bien plus de temps. À titre d'exemple, la pagination kernel fut opérationnelle au bout de 5 jours, mais la pagination user est incomplète. Et une extension en appelle une autre : une fois la mémoire virtuelle en place, beaucoup d'autres extensions annexes étaient possibles : partage des ressources, gestion du disque dur...
Comme dit précédemment, ce projet est une expérience qui en valait la peine, sans réels désagréments, et nous regrettons uniquement de ne pas avoir eu assez de temps pour avoir un résultat plus complet.

Références

Sources initiales

Les sources initiales du projet sont les sources fournies en pratique du système, disponibles ici.

Documentation

  • Les structures utilisées pour le pilote graphique sont inspirées du noyau Linux (voir arch/x86/boot/vesa.h), les surfaces inspirées de la librairie SDL (pseudocode disponible ici).
  • Les pilotes gérant la souris, le haut parleur interne, la RTC, la carte graphique, le clavier, le gestionnaire d'interruptions et le minuteur, ont été faits grâce à la documentation fournie sur OSdev.

Adresses utiles

Outils utilisés

  • mercurial, un gestionnaire de versions décentralisé
  • VirtualBox, une machine virtuelle
  • NetBeans, un EDI complet
  • gedit et SCiTE, des éditeurs de texte
  • planner, un gestionnaire de diagramme de Gantt
  • gcc, un compilateur c
  • gas, un assembleur
  • ddd, gdb et Nemiver, des débugueurs