Projet système PC : 2014 - LHORTOLAT Romain, MATHIEU Chloé, RUARO Thibault

De Ensiwiki
Aller à : navigation, rechercher
Project schedule.png
Titre du projet AlbinOS
Cadre Projet Système d'Exploitation 2014
Page principale Projet_système

Équipe Romain Lhortolat Chloé Mathieu Thibault Ruaro
Encadrants Damien Dejean Gaëtan Morin Grégory Mounié


Présentation générale

Les projets de spécialité système permettent de mettre en oeuvre des concepts associés aux systèmes d'exploitation : synchronisation, concurrence, partage de tâche, temps réel, pilotes matériels, ... En d'autres termes, l'objectif est de concevoir un système d'exploitation sur machine nue.

Le système d'exploitation sur l'architecture Intel IA32 permettant l'exécution de programmes applicatifs simples. Les applications sont écrites en termes de processus parallèles se partageant le temps d'exécution sur le processeur avec des priorités différentes. Le noyau est bien sûr très petit, mais cependant réaliste car il offre un ensemble de services permettant d'exécuter des programmes significatifs.

Cahier des charges

Spécifications techniques

Les fonctionnalités à implémenter et les spécifications du projet ont été définies de manière claire. Elles sont détaillées sur le lien suivant : Spécifications du projet

Différentes phases

Le projet se découpe en 7 phases :

  • Prise en main de l'environnement de travail et affichage à l'écran
  • Gestion des processus et changement de contexte entre deux processus
  • Gestion de l'ordonnancement, de la création dynamique et de la filiation des processus
  • Gestion de la communication et de l'endormissement des processus
  • Séparation des modes noyau et utilisateur
  • Développement d'un pilote de console
  • Développement d'un interprète de commandes

Planning prévisionnel

GANTT previsionnel LHORTOLAT MATHIEU RUARO.jpg

Choix techniques

Gestionnaire de versions

L'utilisation de Git en tant que gestionnaire de versions est imposée. Cela nous a permis de conserver les différentes versions de nos fichiers tout au long du projet ainsi que de travailler tous les trois en parallèle sur des tâches différentes. Nous avons créé une branche "dev" pour les développements.

Réalisation

Execution AlbinOS Projet Systeme.png

Prise en main de l'environnement de travail et affichage à l'écran

Avancement

100 %

Points d'attention

Dans cette phase, il n'y a pas particulièrement de points bloquants. Cette phase s'appuie sur le PSE, qui est bien guidé. Attention tout de même a qemu, qui ne sait pas gérer le bit de clignotement, et qui permet d'avoir 16 couleurs de fond différentes (au lieu de 8).

Gestion des processus et changement de contexte entre deux processus

Avancement

100 %

Points d'attention

Cette phase était bien guidé par le PSE encore une fois. Le point un peu plus compliqué était de savoir comment initialiser la pile pour pouvoir effectuer le changement de contexte.

La gestion de l'horloge était elle aussi guidée. Pas de difficultés particulières.

Gestion de l'ordonnancement, de la création dynamique et de la filiation des processus

Avancement

100 %

Points d'attention

Cette phase était plus compliquée que les précédentes. Il fallait bien comprendre les specs pour que l'implémentation soit correcte. Gérer la terminaison normal nous a posé des problèmes. Comment exécuter la fonction de terminaison, et comment récupérer la valeur de retour ont été également des points complexes.

Pour la valeur de retour, pour éviter de faire de l'assembleur en récupérant une valeur de retour dans %eax qui est un registre scratch, nous avons décidés de passer par l'appel d'une fonction en C qui est le point d'entrée de notre processus. Cette fonction appelle la "vraie" fonction du processus, et récupère sa valeur de retour comme un simple appel de fonction : retval = pt_func(arg);

Pour la terminaison, nous avons empilé dans la pile la fonction qui sera appelée lors de la terminaison normale.

Gestion de la communication et de l'endormissement des processus

Avancement

100 %

Points d'attention

La création des sémaphores était bien détaillée dans les specs. La difficulté a été de savoir la raison de libération d'un processus bloqué par un sémaphore : Lors du reset d'un sémaphore, le processus doit renvoyer -4, delete : -3, normal : 0. Nous avons choisi de mettre la valeur de retour au sein de la structure des processus, car nous n'avons pas trouvé le moyen de gérer cela uniquement dans les sémaphores.

Aucun souci pour l'endormissement. Nous mettons les processus endormis dans une liste qui contient uniquement les processus endormis. Cela permet à l'ordonnanceur de gérer uniquement une liste de processus activables.

Séparation des modes noyau et utilisateur

Avancement

100 %

Points d'attention

C'est la partie la plus délicate du projet. Il fallait bien comprendre ce qu'était censé faire cette transition de mode pour pouvoir l'implémenter correctement, et ce fut le point le plus compliqué.

Pour notre part, même si le wiki expliquait tous les problèmes et pourquoi il fallait faire 2 modes, c'est difficile à comprendre car à première vue on n'en voit pas l’intérêt.

Le principe est donc de séparer le kernel du user, pour que le user s'exécute dans une partie de la mémoire qui lui est réservée. Cela permet de séparer la mémoire kernel de la mémoire user, et donc de mettre des privilèges pour savoir qui a accès à quoi. Et concrètement, le user ne doit pas accéder à la mémoire du kernel.

Première étape : la création de la pile user et la changement de mode. En effet, pour pouvoir exécuter un code user, il faut créer une pile qui se trouve dans la mémoire user. Il faut donc séparer la pie kernel de la pile user. Chaque pile étant utilisé dans son contexte : pile user quand on exécute des fonctions user, pile kernel quand on exécute des fonctions kernel. Il fallait donc savoir comment créer la pile user, et quelles seront les nouvelles valeurs de la pile kernel. Le sommet de la pile kernel contient l'adresse de la fonction à exécuter pour passer en mode user. Pour passer du user au kernel, il faut faire l'instruction : int $49. C'est une interruption qui permet au user de réaliser un appel système. Pour passer du kernel au user, il faut faire l'instruction : iret. Ces 2 instructions vont de paire. Lorsqu'on fait une interruption, il faut toujours rendre la main avec iret. La première question que l'on se pose est alors : comment passer en mode user la première fois ? Il faut simuler une interruption 49. Comment la simuler ? l'instruction iret dépile les 5 premiers éléments de la pile. il faut push dans l'ordre : - ss (pushl 0x4b) - la pile user - 0x202 (pushl 0x202) - cs (pushl 0x43) - prochaine instruction a exécuter. Enfin, il faut changer les registres de segment : %ds, %es, %fs, %gs (mettre tous ces registres à la valeur 0x4b). Une fois cela fait, il faut faire iret, et vous voila basculer en mode user.

Il est alors important de comprendre que dès que vous faîtes le iret, vous n'avez plus accès au kernel et à sa mémoire. Si vous essayez d'exécuter une fonction du kernel, vous serez jeté par une exception.

Deuxième étape : les appels systèmes Le appels systèmes permettent à l'utilisateur d'appeler des fonctions qui sont dans le kernel et dont il a besoin (car il n'y a plus accès). Pour appeler une fonction kernel, il faut mettre dans les registres : %edi, %esi, %edx, ecx, %ebx et %eax les différentes valeurs des paramètres et la numéro de la fonction a exécuté. Une fois les valeurs placées, faire : int $49, et hop, vous êtes dans le kernel. Il faut donc que le kernel ait créé un traitant pour cette interruption. Une fois que le kernel a finit, il fait le iret, et hop, vous êtes en user. Point clé : l'instruction int $49 bascule en mode kernel, il faut donc utiliser la pile kernel. Pour que le système la retrouve, il faut stocker la pile kernel du prochain processus actif dans la TSS + 4 (0x20004). Il faut y stocker le sommet de pile. ATTENTION : sommet ne signifie pas la prochaine case où l'on va push, mais bel et bien le sommet de la pile, c'est à dire la plus grande adresse de la pile.

Développement d'un pilote de console

Avancement

100 %

Points d'attention

Pour développer le pilote de console, il n'y a pas eu de grosses difficultés. La spec était bien détaillée, et à cette phase, on a bien saisit le fonctionnement des interruptions. Ce qui a été plus compliqué, c'est la gestion du buffer clavier. Mais rien d'affolant.

Développement d'un interprète de commandes

Avancement

90 %

Points d'attention

Cette phase n'est pas compliqué non plus. Il faut lancer le shell. Ce dernier doit écouter l'appuie sur la touche entrée, et une fois détecté, il va lancer le traitement de l'entrée utilisateur. Ce qui est fastidieux, c'est de devoir créer une fonction pour chaque commandes disponible du shell.

Nous avons mis en place une fonction pour analyser la ligne rentrée par l'utilisateur, et qui permet de séparer le nom du script des paramètres, et de savoir si l'utilisateur souhaite lancer son processus en tache de fond.

Améliorations

  • Gestion d'un historique des 25 dernières commandes entrées par l'utilisateur : navigation grâce aux flèches haut et bas
  • Gestion du raccourci "Ctrl+C" afin de terminer le processus courant
  • Possibilité de supprimer des caractères du buffer avec la touche "backspace"
  • Gestion jusqu'a 1 script et 10 paramètres par ligne (script 1 2 3 4 5 6 7 8 9 10) qui sont ensuite stockés dans une structure de commande pour être facilement exploitable (passage en paramètre de la fonction start)
  • Possibilité de lancer les processus en tache de fond. Il faut faire : script 1 2 3 ... &. Si la ligne termine par &, alors le processus ne sera pas attendu.
Commande Description

ps

Liste des informations sur l'ensemble des processus en utilisation

sinfo

Liste des informations sur l'ensemble des sémaphores en utilisation

echo <on>

Permet de masquer ou démasquer les touches lorsqu'elles sont envoyés dans le buffer. (on = 1 : echo, on = 0 : pas echo)

sys_info

Permet de lister les informations sur le noyau (processus et sémaphores y sont listés)

run_test [<num1> <num2> ... <num10>]

Permet de lancer les tests. Si des paramètres sont passés à l'appel de la fonction, seuls les tests identifiés par les paramètres seront exécutés. Sinon, s'il n'y a pas de paramètre, ils sont tous lancés

clear

Efface l'écran

kill <pid>

Tue le processus ayant pour pid le pid passé en paramètre

exit [<retval>]

Permet de quitter le shell

process_zombie

Permet de créer un processus. Si lancé avec l'option '&', ce processus devient un zombie

kill_zombies

Permet de tuer tous les processus zombies

history

Affiche les 25 dernières commandes qui ont été entrées par l'utilisateur

'!' <num_commande>

Permet de lancer la commande qui correspond au numéro <num_commande> dans l'historique des commandes

sleep <nb_clocks>

Permet d'endormir un processus pendant nb_clocks

Binaire de l'application

Vous trouverez ici le binaire de l'application que vous pouvez lancer avec qemu. Bon courage :) Fichier:Kernel.tar.gz