Projet de Systèmes (Master 1 II 2007-2008)

Istérix

L'auteur de cette page est : Jean-Baptiste Yunès

Informations

Le projet est à réaliser par groupe de quatre personnes au plus.

Dernières nouvelles: Les Linuxiens peuvent rencontrer un problème de compilation des outils donnés, notamment en ce qui concerne assembler. Le problème est l'abscence de définition de la fonction yywrap. Pour le corriger, il suffit d'éditer le source assembler.lex et ajouter la directive %option noyywrap.

Introduction

Il est demandé de réaliser en langage C un émulateur de machine/système contenant divers composants comme un gestionnaire de processus avec ordonnanceur préemptif, une communication interprocessus par signaux asynchrones, un moniteur de synchronisation.

La machine/système Istérix devra exécuter des binaires (code machine Istérix) obtenus par assemblage (compilation élémentaire) de programmes sources écrits dans le langage Programmatix dont on trouvera la description plus loin. Istérix est une machine dont les instructions sont de deux types: instructions ordinaires (calculs, contrôle de l'exécution, etc) et instructions système (création de processus, signaux, etc.). La «structure» système qui représente l'exécution d'un binaire s'appelle un processus.

Démarrage d'Istérix

À son démarrage, le système Istérix commence par charger un binaire Istérix donné en entrée standard du processus Unix réalisant l'émulation. Ce programme est alors chargé en mémoire, les diverses initialisations nécessaires au bon fonctionnement du système sont réalisées et l'exécution de la première instruction du programme est lancée. Le régime de croisère est alors atteint.

En régime de croisière

Dans ce régime, l'émulateur se contente d'exécuter les instructions des divers processus en cours d'exécution. Puis, lorsqu'il n'existe plus aucun processus à exécuter la machine s'arrête.

Structure du support de la simulation

L'émulateur sera un simple processus Unix.

Les processus Istérix

Un processus Istérix est une structure entièrement contenue dans la mémoire Istérix (voir plus loin). Elle contient toutes les informations nécessaires à la bonne exécution du programme associé: structure de contrôle, instructions, données et pile.

Les instructions, données et pile constituent l'espace d'adressage du processus: la zone d'instruction est de taille au plus 256 instructions (8 octets pour une instruction), la zone de données est de 256 octets, et la zone de pile d'au plus 256 octets.

La structure de contrôle du processus contient différentes informations que l'on jugera nécessaires d'y mettre et qui doivent permettre une bonne exécution du processus associé, on y trouvera par exemple: l'adresse physique de la zone d'instruction, l'adresse physique de la zone de données, l'adresse physique de la pile, le numéro de l'instruction en cours d'exécution, l'état du processus, son code de retour, masque des signaux, etc.

On notera qu'un binaire Istérix fait toujours des adressages virtuels. Ainsi, dans un processus, une instruction faisant référence au chargement d'une donnée située à l'adresse 10, ne fait pas référence à l'adresse physique 10 mais à la 10ième donnée de la zone de données du processus (idem pour les instructions de contrôle de l'exécution qui font référence à des adresses en zone d'instruction et pour la pile dans la zone de pile...).

La Mémoire Istérix

La mémoire du système Istérix sera constituée d'un unique tableau de caractères du processus Unix réalisant la simulation (voir l'exécuteur de code donné en exemple).

Dans cette mémoire, on trouvera non seulement les programmes binaires, les zones de données et piles mais aussi la liste des structures de contrôle des différents processus.

Le langage Programmatix

Ce langage rudimentaire permet d'écrire plus simplement des programmes à exécuter par la machine Istérix. Le programme source peut être assemblé (en utilisant la commande assembler fournie) pour obtenir un binaire Istérix. Pour faciliter la tâche il est conseillé de nommer les binaires en utlisant une seule lettre (éventuellement agrémentée d'une «extension»), comme par exemple f.ist ou simplement f (pour comprendre pourquoi, consultez le description de l'instruction EXEC plus loin).

La conception d'un assembleur dépassant le cadre de ce cours, cet outil vous est fourni (avec ses sources). Nous déconseillons vivement aux étudiants de s'attacher à en comprendre le fonctionnement dans l'immédiat. Faites ce qui est demandé, si le coeur vous en dit, vous pourrez toujours l'examiner par la suite.. Par contre il est vivement conseillé de consulter le code du desassembler qui lui vous donnera d'excellentes indications sur la structure du code machine. Une autre excellente idée est aussi d'observer le code du processeur (de nom processor) qui permet d'exécuter un binaire Istérix (seulement les instructions ordinaires évidemment!).

Le langage est constitué de deux types d'instructions:

Dans le tableau suivant, on trouvera la liste des instructions, la liste de leurs arguments et leur correspondance (approximative) en langage C. Les arguments sont de trois types:

Mnémonique Arguments instruction C/Unix
ASSIGN réf,réf_ou_cste réf = réf_ou_cste;
ASSIGN+ réf,réf_ou_cste réf += réf_ou_cste;
ASSIGN- réf,réf_ou_cste réf -= réf_ou_cste;
ASSIGN* réf,réf_ou_cste réf *= réf_ou_cste;
IF réf_ou_cste,réf_ou_cste,étiquette if (réf_ou_cste==réf_ou_cste) goto étiquette;
JUMP étiquette goto étiquette;
CALL étiquette étiquette();
RET return;
FORK réf réf = fork();
EXEC réf_ou_cste exec(réf_ou_cste);
EXIT réf_ou_cste exit(réf_ou_cste);
WAIT réf,réf réf = wait(réf);
SIGNAL réf_ou_sig,étiquette signal(réf_ou_cste,étiquette);
KILL réf_ou_sig,réf kill(réf_ou_cste,réf);
READ réf read(STDIN_FILENO,réf,1);
WRITE réf_ou_cste write(STDOUT_FILENO,réf_ou_cste,1);
GETPPID réf réf = getppid();
LCK cste semop() avec semop = -1;
UNLCK cste semop() avec semop = +1;

Les arguments sont de quatre types:

On notera la possibilité de commenter du code Programmatix en commençant une ligne par le caractère /.

Un assembleur Programmatix est fourni. Il ne permet d'écrire qu'une seule instruction par ligne de texte, et une instruction n'est jamais située en début de ligne, mais est toujours précédée d'au moins un espace ou une tabulation.

IMPORTANT: un programme Programmatix doît obligatoirement contenir une instruction étiquetée par debut et permettant d'indiquer le point d'entrée du programme (équivalent du main() du C).

Ce qui suit est un exemple de programme source U:

/ On commence par compter jusqu'a 10
debut:
	ASSIGN	13,#0
incr:
	ASSIGN+ 13,#1
	IF	13,#10,fin_incr
	JUMP	incr
/ On essaye d'appeler une fonction
fin_incr:
	CALL	remise_a_zero
/ On tente de capturer SIGUSER
	SIGNAL	U_SIGUSER,sig_handler
/ Et un petit fork/exec/wait
	FORK	1
	IF	1,#0,fils
/ Le pere attend
	WAIT	2,3
/ Il ecrit 'b'
	WRITE	#65
	EXIT	#0
remise_a_zero:
	ASSIGN	13,#0
	RET
/ Le code du fils!
fils:
/ Il envoie un SIGUSER a son pere
	GETPPID 5
	KILL    U_SIGUSER,5
/ Il exec sur 'a'
	EXEC	#64
	EXIT	#1
sig_handler:
	WRITE	#64
	RET

Matériel fourni

Vous trouverez dans le ficher isterix.tar.gz l'ensemble des sources utiles pour démarrer le projet.

Nous insistons: ll est formellement déconseillé de modifier quoi que ce soit dans les programmes fournis, vous y perdriez un temps considérable pour un gain nul ou presque.

Le seul fichier à modifier (éventuellement) est le Makefile pour paramétrer la compilation sur votre système. Les seuls programmes intéressants à étudier sont: desassembler.c et processor.c.

L'assembleur a pour syntaxe d'appel: assembler source.u objet.

Le désassembleur a pour syntaxe d'appel: desassembler < objet.

Le processeur a pour syntaxe d'appel: processor < objet. Note: le processeur n'est qu'une base de travail...

Le projet

Il est demandé d'écrire un programme en langage C permettant de simuler des exécutions de programmes binaires Istérix. Dans le système Istérix, il s'agira de processus qui seront ordonnancés en partageant le temps par préemption (sur une base atomique simple comme par exemple quatre instructions/processus).

Le système Istérix devra utiliser un adressage virtuel pour les processus. Adressage qui pourra permettre de partager le code lorsque différents processus exécuteront le même code.

Particularités

L'instruction EXEC qui permet de recouvrir le code du processus courant par un nouveau code obtient le nouveau code à charger en effectuant des lectures sur le fichier (du système Unix) dont le nom est donnée par le paramètre. Ce dernier est toujours un entier (obtenu éventuellement par référence) utilisé comme code ascii pour obtenir le nom du fichier à charger. Ainsi une instruction comme EXEC #65 permettra de charger le programme contenu dans le fichier A (avec une extension prédéfinie si nécessaire).

L'instruction WAIT prend deux arguments, le premier sera l'adresse où sera rangée l'identité du fils terminé et la seconde celle contenant le code de retour.

Les instructions READ ou WRITE ne permettent de lire ou d'écrire qu'un seul caractère à la fois et dont le code ASCII est donné en argument (écrire) ou renvoyé par le système (lire). Si l'écriture est immédiate (par exemple affichage d'un message: le processus numéro 87 a écrit le caractère ASCII 64 'A'), la lecture provoque le blocage du processus en cours tant qu'aucune donnée ne lui a été fournie par l'interface (on peut envisager un tampon de lecture).

Le quantum de temps alloué à un processus est de 4 instructions. Au-delà un processus est préempté par l'ordonnanceur.

Pour le reste...

Consignes

Les soutenances auront lieu les vendredi 18 janvier 2008 et lundi 21 janvier 2008. Pour vous inscrire, rendez-vous au secrétariat, dans le bureau de Mme Maguy Eguienta. Les rapports seront rendus le jour de la soutenance. La soutenance durera une demi-heure. Tous les étudiants d'un groupe donné doivent être présents.