Construire en langage C une machine virtuelle contenant des
composants orientés systèmes comme : un gestionnaire
de processus avec ordonnanceur préemptif, un
mécanisme d'interruption logicielle par signaux
asynchrones, un moniteur de synchronisation.
assembler
donné). La machine/système Hypnotix devra permettre
l'exécution de binaires; une telle exécution s'appelle
un processus.À son démarrage, le système Hypnotix initialise toutes les structures nécessaires à son bon fonctionnement puis se met en attente de commandes.
Dans ce régime, la machine Hypnotix exécute les
divers processus (s'il en existe) et réagit aux commandes
utilisateurs. Ces deux comportements doivent cohabiter sans
être interbloquants. L'exécution des processus doit
s'effectuer en mode temps partagé : chaque processus
reçoit un quantum
de temps (pour simplifier ce quantum
correspond à un nombre d'instructions à
exécuter) à la suite duquel l'ordonnanceur choisira
un nouveau processus à exécuter (le nouveau pouvent
être le même que l'ancien!). Les commandes
utilisateurs sont transmises au système via une file de messages (un
message incarnant une commande). Le système est
prévenu qu'une commande est à traiter en
réceptionnant un signal Unix. Le système se doit de
réagir au plus vite aux commandes utilisateurs.
Un processus Hypnotix sera une structure entièrement contenue dans la mémoire Hypnotix (voir plus loin). Cette structure devra contient toutes les informations nécessaires à la bonne exécution du programme associé : structure de contrôle, pointeur vers les instructions, données et pile.
L'ensemble constitué des instructions, données et
pile d'un processus constituent son espace d'adressage :
On notera que la machine/système Hypnotix ne manipule
qu'un seul type de données.
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 Hypnotix 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 machine Hypnotix 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 du système Hypnotix sera
nécessairement constituée d'une unique zone d'octets
de la machine hôte (voir l'exécuteur de code processor
donné en exemple).
Dans cette mémoire on trouvera donc les instructions les
données et piles des processus qui s'exécutent
à un moment donné.
(Projet en mode avancé) On pourra envisager :
Ce langage assez rudimentaire permet d'écrire plus
simplement des programmes à exécuter par la machine
Hypnotix. Le programme source peut être assemblé (en
utilisant la commande assembler
fournie et qui prend
deux paramètres : le premier est le nom du fichier
contenant le code source et le second le nom du fichier qui
contiendra le code objet) pour obtenir un binaire Hypnotix.
Pour faciliter la tâche il est conseillé de nommer
les binaires en utilisant 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 cœur 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 et sur la façon d'interpréter ce code.
Une autre excellente idée est aussi d'observer le code du
processeur (de nom processor
) qui permet
d'exécuter un binaire Hypnotix (seulement les instructions
ordinaires évidemment!).
Le langage est constitué de deux types d'instructions:
Dans le tableau suivant, on trouvera la description de toutes les
instructions et leur correspondance (approximative) dans l'API
POSIX en langage C.
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; |
SETPRIO |
cste | nice(cste) ou setpriority(cste...) |
Les arguments sont de quatre types (attention, dans ce qui suit les valeurs seront toujours exprimées relativement à l'espace d'adresse du processus) :
*
(le nombre est le numéro d'une case mémoire dont
le contenu est le numéro de la case mémoire
à consulter);#
nombre;U_SIGILL
, U_SIGMEM
, U_SIGUSER
ou U_SIGKILL
;:
) et
permettre au programmeur d'utiliser des symboles pour ses sauts
ou appels de fonctions.On notera la possibilité de commenter du code Hypnotix en
commençant une ligne par le caractère /
.
Un assembleur Hypnotix 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 Hypnotix 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 Hypnotix. Cet exemple comme ceux fournis ne sont que des exemples rien de plus, il vaut mieux les étudier de près afin de se faire une idée de la programmation de la machine/système Hypnotix. Une fois cette tâche accomplie, il est plus que fortement conseillé d'en écrire par vous-même!
/ 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
show procs
qui permettra d'obtenir un
équivalent de ps,
show proc n
pour obtenir tous
les détails du processus de numéro n
(contenu mémoire, etc),pause
afin de mettre en pause le système.
Celui-ci s'interdit alors d'exécuter une quelconque
instruction et ne fait plus que répondre aux commandes,continue
pour reprendre l'exécution des
processus après une pauseadd fichier
pour forcer Hypnotix
à créer un processus dont le code est contenu dans
le fichier,terminate
pour arrêter le système
brutalement,quantum n
afin de modifier la valeur
du quantum,send n "chaine"
ou send
'c'
afin de transmettre le ou les
caractères donnés en argument en entrée du
processus n,freeze
pour stopper
le système en prenant soin de sauvegarder l'état
complet du système, de sorte qu'à son prochain
lancement, il reprenne exactement dans le même
état,Vous trouverez dans le ficher hypnotix.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 en particulier dans l'assembleur, 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
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.
Il est demandé d'écrire deux programmes en langage C : Hypnotix et son contrôleur.
Le système Hypnotix 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.
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).
Pour le reste...