Changes between Version 88 and Version 89 of Archi-1-TP10


Ignore:
Timestamp:
Nov 23, 2021, 6:23:29 PM (3 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP10

    v88 v89  
    170170''
    171171}}}
    172 1. Que se passe-t-il quand le MIPS entre dans le noyau, après l'exécution de l'instruction `syscall`?
    173 {{{#!protected ------------------------------------------------------------------------------------
    174 '''''''''''''''
     1721. Que se passe-t-il quand le MIPS entre dans le noyau, lors de l'exécution de l'instruction `syscall`?
     173{{{#!protected ------------------------------------------------------------------------------------
     174''
     175Cours 10 / slide 13
    175176- L'instruction `syscall` induit beaucoup d'opérations élémentaires dans le MIPS:
    176177  - `EPC` ← `PC` (adresse de l'instruction `syscall`)
     
    178179  - `c0_cause.XCODE` ← `8`
    179180  - `PC` ← `0x80000180`
    180 '''''''''''''''
     181''
    181182}}}
    1821831. Quelle instruction utilise-t-on pour sortir du noyau et entrer dans l'application ? Dîtes précisément ce que fait cette instruction dans le MIPS.
    183184{{{#!protected ------------------------------------------------------------------------------------
    184 '''''''''''''''
    185 - C'est l'instruction `eret` qui permet de sortir du noyau.
     185''
     186Cours 10 / slide 13\\
     187- C'est l'instruction `eret` qui permet de sortir du noyau. C'est la seule instruction permettant de sortir du noyau.
    186188  - `PC` ← `EPC`
    187189  - `c0_SR.EXL` ← `0` (ainsi les bits `c0_SR.UM` et `c0_SR.IE` sont à nouveau utilisés)
    188 '''''''''''''''
     190''
    189191}}}
    190192
     
    192194
    193195== A2. Langage C pour la programmation système
     196
    194197
    195198
     
    201204
    202205
    203 1. En assembleur, vous utilisez les sections prédéfinies `.data` et `.text` pour placer respectivement les data et le code ou alors vous pouvez créer vos propres sections avec la directive `.section` (nous avons utilisé cette possibilité pour la section `.boot`). Il est aussi possible d'imposer ou de créer des sections en langage C avec le mot clé `__attribute__`. Ce mot clé du C permet de demander certains comportements au compilateur. Il y a en a beaucoup  (si cela vous intéresse vous pouvez regarder dans la [https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html doc de GCC sur les attributs]. En cours, nous avons vu un attribut permettant de désigner ou créer une section dans laquelle est mise la fonction concernée. Quelle était la syntaxe de cet attribut (regardez sur le slide 38).
    204 {{{#!protected ------------------------------------------------------------------------------------
    205 '''''''''''''''
     2061. En assembleur, vous utilisez les sections prédéfinies `.data` et `.text` pour placer respectivement les data et le code, mais vous pouvez créer vos propres sections avec la directive `.section` (nous avons utilisé cette possibilité pour la section `.boot`). Il est aussi possible d'imposer ou de créer des sections en langage C avec la directive `__attribute__`. Cette directive du C permet de demander certains comportements au compilateur. Il y a beaucoup d'attributs possibles (si cela vous intéresse vous pouvez regarder dans la [https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html doc de GCC sur les attributs]. En cours, nous avons vu un attribut permettant de désigner ou créer une section dans laquelle est mise la fonction concernée. Quelle est la syntaxe de cet attribut ?
     207{{{#!protected ------------------------------------------------------------------------------------
     208''
     209Cours 10 / slide 38
    206210- `__attribute__ ((section (".start")))`\\Remarquez la syntaxe un peu curieuse avec les doubles underscore et les doubles parenthèses.
    207 '''''''''''''''
    208 }}}
    209 1. En C, vous savez que les variables globales sont toujours initialisées, soit explicitement dans le programme lui-même, soit implicitement à la valeur `0`. Les variables globales initialisées sont placées dans la section `.data` (ou plutôt dans l'une des sections `data` : `.data`, `.sdata`, `.rodata`, etc.) et elles sont présentes dans le fichier objet (`.o`) produit pas le compilateur. En revanche, les variables globales non explicitement initialisées ne sont pas présentes dans le fichier objet. Ces dernières sont placées dans un segment de la famille `.bss`. Le fichier ldscript permet de mapper l'ensemble des segments en mémoire. Pour pouvoir initialiser à `0` les segments `bss` par programme, il nous faut connaître les adresses de début et de fin où ils sont placés en mémoire.\\ \\Le code ci-dessous est le fichier ldscript du kernel `kernel.ld` (nous avons retier les commentaires mais ils sont dans les fichiers).\\Expliquez ce que font les lignes 11, 12 et 15.
     211''
     212}}}
     2131. En C, vous savez que les variables globales sont toujours initialisées, soit explicitement dans le programme lui-même, soit implicitement à la valeur `0`. Les variables globales initialisées sont placées dans la section `.data` (ou plutôt dans l'une des sections `data` : `.data`, `.sdata`, `.rodata`, etc.) et elles sont présentes dans le fichier objet (`.o`) produit pas le compilateur. En revanche, les variables globales non explicitement initialisées ne sont pas présentes dans le fichier objet. Ces dernières sont placées dans un segment de la famille [https://www.wikiwand.com/fr/Segment_BSS `.bss`]. Le fichier ldscript permet de mapper l'ensemble des segments en mémoire. Pour pouvoir initialiser à `0` les segments `bss` par programme, il nous faut connaître les adresses de début et de fin où ils sont placés en mémoire.\\ \\Le code ci-dessous est le fichier ldscript du kernel `kernel.ld` (nous avons retiré les commentaires mais ils sont dans les fichiers).\\Expliquez ce que font les lignes 11, 12 et 15.
    210214{{{#!java
    211215  1 SECTIONS
     
    228232}}}
    229233{{{#!protected ------------------------------------------------------------------------------------
    230 '''''''''''''''
     234''
     235Cours 10 / slide 28
    231236- La ligne 11 contient `. = ALIGN(4)`, c'est équivalent à la directive `.align 4` de l'assembleur.
    232237  Cela permet de déplacer le pointeur de remplissage de la section de sortie courante (c'est-à-dire ici `.kdata`) sur une
     
    236241- La ligne 15 permet de créer la variable `__bss_end` qui sera l'adresse de fin de la zone `bss`
    237242  (en fait c'est la première adresse qui suit juste `bss`.
    238 '''''''''''''''
     243''
    239244}}}
    2402451. Nous connaissons les adresses des registres de périphériques. Ces adresses sont déclarées dans le fichier ldscript `kernel.ld`. Ci-après, nous avons la déclaration de la variable de ldscript `__tty_regs_map`. Cette variable est aussi utilisable dans les programmes C, mais pour être utilisable par le compilateur C, il est nécessaire de lui dire quel type de variable c'est, par exemple une adresse d'entier ou une adresse de tableau d'entiers, Ou encore, une adresse de structure.\\ \\Dans le fichier `kernel.ld`:
     
    255260  À quoi servent les mots clés `extern` et `volatile` ?\\Si `NTTYS` est une macro dont la valeur est `2`, quelle est l'adresse en mémoire `__tty_regs_map[1].read` ?
    256261{{{#!protected ------------------------------------------------------------------------------------
    257 '''''''''''''''
     262''
     263Cours 10 / slide 53
    258264- `extern` : informe le compilateur que la variable définie existe ailleurs. Grâce à son type, le compilateur sait s'en servir.
    259265- `volatile` : informe le compilateur que la variable peut changer de valeur toute seule et que donc il doit toujours accéder en mémoire à chaque fois que le programme le demande. Il ne peut donc pas optimiser les accès mémoire en utilisant les registres.
    260266- `__tty_regs_map` est un tableau à 2 cases (puisque `NTTYS`=`2`). Chaque case est une structure de 4 entiers, donc `0x10` octets.\\`read` est le troisième champ, c'est le troisième entier de la structure, donc en `+8` par rapport au début.\\En conséquence `__tty_regs_map[1].read` est en `0xd0200018`
    261 '''''''''''''''
     267''
    262268}}}
    2632691. Certaines parties du noyau sont en assembleur. Il y a au moins les toutes premières instructions du code de boot (démarrage de l'ordinateur) et l'entrée dans le noyau (kentry) après l'exécution d'un syscall. Le gestionnaire de syscall est écrit en assembleur et il a besoin d'appeler une fonction écrite en langage C. Ce que fait le gestionnaire de syscall est: