Changes between Version 53 and Version 54 of Archi-1-TP10


Ignore:
Timestamp:
Jan 3, 2021, 2:24:43 PM (4 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP10

    v53 v54  
    573573
    574574
    575 {{{#xml
     575{{{#!xml
    5765761_klibc/
    577577├── kinit.c         : fichier contenant la fonction de démarrage du noyau
     
    614614
    615615
    616 * Le numéro du processeur est dans les 12 bits de poids faible du registre $15 (`c0_cpuid`) du coprocesseur système (à côté des registres `c0_epc`, `c0_sr`, etc.). Ajoutez la fonction `int cpuid(void)` qui lit le registre `c0_cpuid` et qui rend un entier contenant juste les 12 bits de poids faible.\\Vous pouvez vous inspirez fortement de la fonction `int clock(void)`. Comme il n'y a qu'un seul processeur dans cette architecture, `cpuid` rend `0`.\\Ecrivez un programme de test.
     616* Le numéro du processeur est dans les 12 bits de poids faible du registre $15 (`c0_cpuid`) du coprocesseur système (à côté des registres `c0_epc`, `c0_sr`, etc.). Ajoutez la fonction `int cpuid(void)` qui lit le registre `c0_cpuid` et qui rend un entier contenant juste les 12 bits de poids faible.\\Vous pouvez vous inspirez fortement de la fonction `int clock(void)`. Comme il n'y a qu'un seul processeur dans cette architecture, `cpuid` rend toujours `0`.\\Ecrivez un programme de test (vous devrez modifier les fichiers `hcpu.h`, `hcpu.S` et `kinit.c`)
    617617
    618618
     
    622622**Objectifs de l'étape**
    623623
    624 Nous allons désormais avoir deux exécutables: le noyau et l'application. Dans cette étape, nous allons voir comment le noyau fait pour appeler l'application, alors que celle-ci n'est pas compilée en même temps que le noyau. Nous allons passer du noyau à l'application à la fin de la fonction `kinit()`.
    625 
    626 En revanche, dans cette étape, nous n'allons pas mettre en place la gestion des syscalls. C'est-a-dire qu'il ne sera pas possible de revenir dans le noyau depuis l'application. C'est bien entendu une étape intermédiaire, parce qu'il faut normalement absolument pouvoir invoquer le noyau depuis l'application pour accéder aux périphériques.
    627 Toutefois, pour pouvoir quand même accéder aux registres de périphériques, nous allons exceptionnellement exécuter l'application en mode kernel. Ainsi, l'application pourra accéder aux adresses de l'espace d'adressage réservées aux mode `kernel`.
     624Nous allons désormais avoir deux exécutables: le noyau et l'application. Dans cette étape, nous allons voir comment le noyau fait pour appeler l'application, alors même que celle-ci n'est pas compilée en même temps que le noyau. Nous allons passer du noyau à l'application à la fin de la fonction `kinit()`.
     625
     626Nous allons donc entrer dans l'application, en revanche, dans cette étape, nous n'allons pas mettre en place la gestion des syscalls. C'est-a-dire qu'il ne sera pas possible de revenir dans le noyau depuis l'application. C'est bien entendu une étape intermédiaire, parce qu'il faut absolument pouvoir invoquer le noyau depuis l'application pour accéder aux périphériques.
     627Pour pouvoir quand même accéder aux registres de périphériques, nous allons **exceptionnellement** exécuter l'application en mode kernel. Ainsi, l'application pourra accéder aux adresses de l'espace d'adressage réservées aux mode `kernel`.
    628628
    629629Nous avons deux exécutables à compiler et donc deux `Makefile`s de compilation. Nous avons aussi un `Makefile` qui invoque récursivement les `Makefile`s de compilation.
     
    657657{{{#!protected ------------------------------------------------------------------------------------
    658658'''''''''''''''
    659 - Il en faut deux, un pour le kernel `kernel/kernel.ld` et un pour l'application `user/user.d'
     659- Il en faut deux, un pour le kernel `kernel/kernel.ld` et un pour l'application `user/user.ld`
    660660'''''''''''''''
    661661}}}
     
    663663{{{#!protected ------------------------------------------------------------------------------------
    664664'''''''''''''''
    665 - Dans le fichier `user/crt0.c`, c'est la fonction `_start()`
    666 '''''''''''''''
    667 }}}
    668 1. Quelle est la fonction du noyau qui appelle cette fonction et dans quel ?
    669 {{{#!protected ------------------------------------------------------------------------------------
    670 '''''''''''''''
    671 - Dans le fichier `kernel/kinit.c` et c'est la fonction `kinit()`.
     665- Dans le fichier `user/crt0.c`, c'est la fonction `_start()`.
     666'''''''''''''''
     667}}}
     6681. Quelle est la fonction du noyau qui appelle cette fonction et dans quel fichier?
     669{{{#!protected ------------------------------------------------------------------------------------
     670'''''''''''''''
     671- C'est la fonction `kinit()`, dans le fichier `kernel/kinit.c`.
    672672'''''''''''''''
    673673}}}
     
    702702Le programme utilisateur doit absolument s'exécuter en mode user et il doit passer par des appels système pour accéder aux services du noyau. Les services, ici, sont limités (l'accès au TTY, exit et clock), il n'empêche que pour gérer ces appels, il faut l'analyseur des causes d'appels à l'entrée du noyau et un gestionnaire de `syscall`. Il faut aussi le gestionnaire d'exceptions, parce que s'il y a une erreur de programmation, le noyau doit afficher quelque chose pour aider le programmeur.
    703703
    704 Le passage de l'application au noyau par le biais de l'instruction `syscall` impose que les numéros de services soient identiques pour le noyau et pour l'application. Ces numéros de service (comme `SYSCALL_TTY_WRITE`, `SYSCALL_EXIT` sont définis dans un `.h` communs aux noyau et à l'application. Ce fichier est mis dans un répertoire à part nommé `common`. Il n'y a qu'un seul fichier ici, mais dans un système plus élaborés il y en a d'autres.
     704Le passage de l'application au noyau par le biais de l'instruction `syscall` impose que les numéros de services soient identiques pour le noyau et pour l'application. Ces numéros de service (comme `SYSCALL_TTY_WRITE`, `SYSCALL_EXIT` sont définis dans le fichier `syscall.h` communs au noyau et à l'application. Ce fichier est mis dans un répertoire à part nommé `common`. Il n'y a qu'un seul fichier ici, mais dans un système plus élaboré, il y en a d'autres.
    705705
    706706
    707707**Fichiers**
     708
    708709
    709710{{{#!xml
     
    732733}}}
    733734
     735
    734736**Questions**
    735737
     738
    7367391. Dans quel fichier se trouve la définition des numéros de services tels que `SYSCALL_EXIT` ?
    737740{{{#!protected ------------------------------------------------------------------------------------
    738741'''''''''''''''
    739 -
     742- Ils sont dans le fichier `common/syscall.h`.
    740743'''''''''''''''
    741744}}}
     
    743746{{{#!protected ------------------------------------------------------------------------------------
    744747'''''''''''''''
    745 -
     748- Il est dans le fichier `kernel/ksyscall.c`.
    746749'''''''''''''''
    747750}}}
     
    749752{{{#!protected ------------------------------------------------------------------------------------
    750753'''''''''''''''
    751 -
     754- Il est dans le fichier `kernel/hcpu.S`.
    752755'''''''''''''''
    753756}}}
     
    756759**Exercice**
    757760
    758 - Vous allez ajouter un appel système nommé `SYSCALL_CPUID` qui rend le numéro du processeur. Nous allons lui attribuer le numéro 4 (notez que ces numéros de services n'ont rien à voir avec les numéros utilisés pour le simulateur MARS). Pour ajouter un appel système, vous devez modifier les fichiers :
    759   - `common/syscalls.h` : pour ajouter le numéro de service
    760   - `kernel/ksyscall.c` : pour modifier le vecteur de syscall
    761   - `kernel/hcpu.S`     : pour ajouter la fonction `int cpuid(void)` (la même que celle demandé en **B.1**)
    762   - `kernel/hcpu.h`     : pour déclarer le prototype de `int cpuid(void)` (comme pour **B.1**)
    763  
    764 
    765 
    766 == B4.  Ajout de la librairie C
     761
     762- Vous allez ajouter un appel système nommé `SYSCALL_CPUID` qui rend le numéro du processeur. Nous allons lui attribuer le numéro 4 (notez que ces numéros de services n'ont rien à voir avec les numéros utilisés pour le simulateur MARS). Pour ajouter un appel système, vous devez modifier les fichiers : `common/syscalls.h`, `kernel/ksyscall.c`, `kernel/hcpu.S` et `kernel/hcpu.h`.cpuid(void)`.
     763
     764
     765
     766== B4.  Ajout de la librairie C pour l'utilisateur
    767767
    768768
     
    771771
    772772
    773 L'application utilisateur n'est pas censée utiliser directement les appels système. Elle utilise une librairie de fonctions standards (la libc POSIX, mais pas seulement) et ce sont ces fonctions qui réalisent les appels système. Toutes les fonctions de la libc n'utilisent pas les appels système. Par exemple, les fonctions `int rand(void)` ou `int strlen(char *)` (rendent, respectivement, un nombre pseudo-aléatoire et la longueur d'une chaîne de caractères) n'ont pas besoin du noyau. Les librairies font partie du système d'exploitation mais elles ne sont pas dans le noyau.
    774 
    775 Le terme « librairie » vient de l'anglais « library » qui signifie bibliothèque. On utilise souvent le mot librairie même si le sens en français n'est pas le même que celui en anglais. Disons que, dans notre contexte, les deux mots sont synonymes.
    776 
    777 Normalement, les librairies système sont des « vraies » librairies au sens `gcc` du terme. C'est-à-dire des archives de fichiers objet (`.o`). Ici, nous allons simplifier et ne pas créer de librairie, mais seulement un fichier objet `libc.o` contenant toutes les fonctions. Ce fichier objets doit être lié avec le code de l'application.
    778 
    779 L'exécutable de l'application utilisateur est donc composé de deux parties : le code de l'application et le code de la librairie et nous allons répartir le code dans deux répertoire `uapp` pour les fichiers de l'application et `ulib` pour les fichiers qui ne sont pas l'application, c'est-à-dire la libc, mais aussi le fichier `ldscript` et le fichier `crt0.c`.
     773L'application utilisateur n'est pas censée utiliser directement les appels système. Elle utilise une librairie de fonctions standards (la `libc` POSIX, mais pas seulement) et ce sont ces fonctions qui réalisent les appels système. Toutes les fonctions de la `libc` n'utilisent pas les appels système. Par exemple, les fonctions `int rand(void)` ou `int strlen(char *)` (rendent, respectivement, un nombre pseudo-aléatoire et la longueur d'une chaîne de caractères) n'ont pas besoin du noyau. Les librairies font partie du système d'exploitation mais elles ne sont pas dans le noyau.
     774
     775 ''Le terme « librairie » vient de l'anglais « library » qui signifie bibliothèque. On utilise souvent le mot librairie même si le sens en français n'est pas le même que celui en anglais. Disons que, dans notre contexte, les deux mots sont synonymes.''
     776
     777Normalement, les librairies système sont des « vraies » librairies au sens `gcc` du terme. C'est-à-dire des archives de fichiers objet (`.o`). Ici, nous allons simplifier et ne pas créer une ''vraie'' librairie, mais seulement un fichier objet `libc.o` contenant toutes les fonctions. Ce fichier objets doit être lié avec le code de l'application.
     778
     779L'exécutable de l'application utilisateur est donc composé de deux parties : d'un côté, le code de l'application et, de l'autre, le code de la librairie `libc` (+ `crt0`). Nous allons répartir le code dans deux répertoires `uapp` pour les fichiers de l'application et `ulib` pour les fichiers qui ne sont pas l'application, c'est-à-dire la `libc`, le fichier `crt0.c` mais aussi le fichier ldscript `user.ld`.
    780780
    781781 
    782782**Fichiers**
     783
    783784
    784785{{{#!xml
     
    825826
    826827
    827 - Vous allez juste ajouter la fonction `int cpuid()` dans la librairie
     828- Vous allez juste ajouter la fonction `int cpuid()` dans la librairie `libc`.
     829- Vous pouvez