Changes between Version 11 and Version 12 of Archi-1-TP11


Ignore:
Timestamp:
Dec 9, 2021, 11:22:40 AM (3 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP11

    v11 v12  
    1 {{{#!html
    2 <h1><font size=+3 color="lightgreen"> En travaux... prêt dans la semaine du 28 novembre 2021 !
    3 }}}
    41**
    52[ __[wiki:WikiStart Start]__ ]
     
    3229* [wiki:Doc-MIPS-Archi-Asm-kernel Documentation sur le mode kernel du MIPS32] : ''obligatoire''
    3330
     31= A. Travaux dirigés
     32
     33== Rappel de cours
     34
     35Il est fortement recommandé de lire les transparents, toutefois, nous avons ajouté ci-après quelques rappels utiles pour répondre aux questions du TD.
     36
     37Les IRQ (Interrupt !ReQuest)s sont des signaux électriques à 2 états (ON/OFF ou !Actif/Inactif ou encore !Levé/Baissé). Les IRQ sont levés par les contrôleurs de périphériques pour prévenir d'un événement (fin de commande, arrivée d'une donnée, etc.). Les IRQs provoquent l'exécution d'ISR (Interrupt Service Routine) par le noyau. Les ISR sont des fonctions qui reçoivent en argument un identifiant du contrôleur de périphérique qui a levé l'IRQ. Une ISR doit faire deux choses, (1) accéder aux registres du contrôleur de périphérique concerné pour faire ce que le périphérique demande et (2) acquitter l'IRQ, c'est-à-dire demander au contrôleur de périphérique de baisser/désactiver son IRQ (puisque celle-ci a été traitée).
     38
     39Les IRQ sont des signaux d'état qui doivent rester levés/activés tant qu'ils n'ont pas été acquittés par une ISR. Quand une IRQ se lève, la conséquence est que le programme en cours d'exécution sur le processeur recevant l'IRQ est interrompu et qu'il est dérouté vers le noyau pour que ce dernier exécute l'ISR prévue pour l'IRQ. Notez que ce n'est pas le processeur qui est interrompu, c'est bien le programme, car le processeur est seulement dérouté vers le noyau, mais il continue à travailler.
     40
     41[[Image(htdocs:img/Archi_TP11.png,nolink,height=250)]]
     42
     43Sur le schéma de la plateforme des TP, on peut voir que ce sont seulement les composants TTY et TIMER qui peuvent lever des IRQ. Les IRQ de ces contrôleurs de périphériques sont envoyés au composant ICU qui va les combiner pour produire un unique signal IRQ pour le processeur.
     44
     45Une IRQ peut être masquée, c'est-à-dire que le processeur ne va pas interrompre le programme en cours. Le masquage peut être demandé à plusieurs endroits : dans le composant ICU et dans le processeur lui-même. Le masquage est demandé par le noyau, le plus souvent de manière temporaire, quand il doit exécuter un code critique qui ne doit surtout pas être interrompu.
     46
     47[[Image(htdocs:img/IRQ_routage.png,nolink,height=200)]]
     48
     49Sur le schéma ci-dessus, on voit que l'IRQ du TTY0 entre sur l'entrée n°`10` de l'ICU, c'est un choix matériel qui n'est pas modifiable par logiciel. Son état est donc enregistré dans le bit n°10 du registre `ICU_STATE`. Il y a un `AND` avec le bit `10` du registre `ICU_MASK`. Si le bit `10` du registre `ICU_MASK` est à `0`, alors la sortie du `AND` est `0` et l'IRQ est masquée (donc invisible pour le processeur). Le registre `ICU_HIGHEST` contient toujours le numéro de l'IRQ active la plus prioritaire, comme il n'y en a qu'une dans cet exemple, `ICU_HIGHEST` contient `10`. L'IRQ de l'ICU entre sur l'entrée `0` des 6 IRQs possibles du MIPS et sa valeur s'inscrit dans le registre `HWI0` du registre `C0_CAUSE`. Il y a un `AND` avec le bit `HWI0` du registre `C0_STATUS`. Si le bit `HWI0` du registre `C0_STATUS` est à 0, alors la sortie du `AND` est `0` et l'IRQ est aussi masquée. Enfin, il y a encore un `AND` qui permet de masquer globalement les IRQ avec le bit `0` de `C0_STATUS` (ce bit est nommé `IE` pour Interrupt Enable) et le `NOT` du bit `1` de `C0_STATUS`, c'est le bit `EXL`, lequel passe à `1` automatiquement dès l'entrée dans le noyau.
     50
     51[[Image(htdocs:img/IRQ_VECTOR.png,nolink,height=220)]]
     52
     53Dans le schéma précédent, à gauche c'est le matériel et à droite c'est un extrait de la RAM contenant les structures de données utilisées par le noyau.
     54- À gauche, on voit que les IRQ venant des contrôleurs de périphériques sont connectés aux entrées d'IRQ de l'ICU. Il y a 32 entrées possibles. Sur notre plateforme, par exemple l'IRQ du TTY2 est connectée à l'entrée `12` de l'ICU. Ce numéro d'entrée est le numéro qui identifie le contrôleur de périphérique. Notez que le registre `ICU_MASK` est en lecture seul, c'est-à-dire qu'il ne peut pas être écrit directement. Pour modifier le contenu du registre `ICU_MASK`, il faut utiliser deux autres registres de l'`ICU`: `ICU_SET` et `ICU_CLEAR`. `ICU_SET` permet de mettre à `1` les bits de `ICU_MASK`, et `ICU_CLEAR` permet de les mettre à `0`. Pour mettre à `1` le bit `i` du registre `ICU_MASK`, il faut écrire `1` dans le bit `i` du registre `ICU_SET`. Pour mettre à `0` le bit `j` du registre `ICU_MASK`, il faut aussi écrire `1` mais dans le bit `j` du registre `ICU_CLEAR`.\\\\
     55- À droite, il y a les deux tableaux que le noyau utilise pour connaitre l'ISR à exécuter pour chaque numéro IRQ. Ce couple de tableaux se nomme **vecteur d'interruption**. Ici, il est composé des tableaux `IRQ_VECTOR_ISR[]` et `IRQ_VECTOR_DEV[]`. Le vecteur d'interruption est indexé par les numéros d'IRQ. Il contient deux informations: (1) Dans la case n°`i` du tableau `IRQ_VECTOR_ISR[]`, on trouve le pointeur sur la fonction ISR a appeler si l'IRQ n°`i` est levée, et (2) dans la case n°`i` du tableau `IRQ_VECTOR_DEV[]`, on trouve le numéro de l'instance du périphérique. Cette dernière information est nécessaire dans le cas des contrôleurs de périphérique multi-instances comme le TTY afin de savoir quel jeu de registres la fonction ISR doit utiliser. En d'autres termes, Il y a une fonction ISR unique quelque-soit le numéro du TTY, l'adresse de cette fonction est placée dans les cases `10`, `11`, `12`, et `13` du tableau `IRQ_VECTOR_ISR[]` (si on a 4 TTYs) et dans les cases  `10`, `11`, `12`, et `13` du tableau `IRQ_VECTOR_DEV[]`, on a `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs.
     56
     57[[Image(htdocs:img/C0_registers.png,nolink,height=300)]]
     58
     59Sur le schéma précédent, nous vous rappelons les 3 registres du coprocesseur système qui sont utilisés au moment de l'entrée dans le noyau, quelque soit la cause : syscall (vu la semaine dernière), interruption (TD de cette semaine) et exception (dans le cas de problèmes lors de l'exécution du programme comme la division par 0). On voit aussi que les seules instructions qui peuvent manipuler ces registres sont `mtc0` et `mfc0` pour, respectivement, les écrire et les lire.
     60
     61Les bits `HWI0` des registres `C0_STATUS` (aussi nommé `c0_sr`) et `C0_CAUSE` contiennent respectivement le mask et le l'état de l'entrée n°`0` d'interruption du MIPS. Les bits `UM`, `IE` et `EXL` sont liés au mode d'exécution du MIPS: `UM` est le bit de mode du MIPS (`1`=`User Mode`, `0`=`Kernel Mode`), `IE` est le bit de masque général des interruptions (`1`=autorisées, `0`=masquées) et enfin  `EXL` est le bit que le MIPS met à `1` à l'entrée dans le noyau pour informer d'un niveau exceptionnel et dans ce cas les bits `UM` et `IE` ne sont plus significatifs, si `EXL` est à `1` alors le MIPS est en mode kernel, interruptions masquées.
     62
     63== A.1. Questions de cours
     64
     65La majorité des réponses aux questions ci-après sont dans le rappel du cours donné au début de cette page, c'est voulu.
     66
     67= Questions de cours sur les interruptions
     68
     691. Que signifie l'acronyme I.R.Q. ?
     70{{{#!protected ------------------------------------------------------------------------------------
     71''
     72  * Interrupt ReQuest ou, en français, requête d'interruption
     73''
     74}}}
     751. Une IRQ est un signal électrique, combien peut-il avoir d'états ?
     76{{{#!protected ------------------------------------------------------------------------------------
     77''
     78  * C'est un signal à 2 états, c'est binaire. Il y a l'état `ON` (on dit aussi levé ou actif) pour dire que l'interruption est demandée et il y a l'état `OFF` (on dit aussi baissé ou inactif) pour dite que l'interruption n'est pas demandée).
     79''
     80}}}
     811. Qu'est-ce qui provoque une IRQ ?
     82{{{#!protected ------------------------------------------------------------------------------------
     83''
     84  * c'est un événement matériel sur le contrôleur de périphérique, comme la fin d'une commande ou l'arrivée d'une donnée.
     85''
     86}}}
     871. Les IRQ relient des composants source et des composants destinataires, quels sont ces composants ? Donnez un exemple.
     88{{{#!protected ------------------------------------------------------------------------------------
     89''
     90  * Les composants source sont les contrôleurs de périphériques par exemple le `TTY` et les composants destinataires sont les processeurs (ici le MIPS).
     91''
     92}}}
     931. Que signifie masquer une IRQ ?
     94{{{#!protected ------------------------------------------------------------------------------------
     95''
     96  * Cela signifie que l'on bloque le signal entre sa source et sa destination. Si une IRQ est levée par un contrôleur de périphérique et que l'on masque cette IRQ, alors l'IRQ est toujours levée à sa source mais le MIPS destinaire ne le voit pas. L'information, le signal, a été masqué sur le chemin entre la source et la destination. Cette IRQ devient invisible pour le MIPS.
     97''
     98}}}
     991. Quels composants peuvent masquer une IRQ ?
     100{{{#!protected ------------------------------------------------------------------------------------
     101''
     102  * Ici, c'est le composant ICU et le MIPS lui-même.
     103''
     104}}}
     1051. Est-ce qu'une application utilisateur peut demander le masquage d'une IRQ ?
     106{{{#!protected ------------------------------------------------------------------------------------
     107''
     108  * Non, puisque que pour masquer une interruption, il faut écrire dans les registres de l'ICU ou dans les registres système du processeur. Or, les registres de configuration de l'ICU sont mappés dans le partie de l'espace d'adressage inaccessible en mode user et que les instructions `mfc0` et `mtc0` sont interdites en mode user, leur usage provoque une exception de type violation de privilège.
     109''
     110}}}
     1111. Que signifie l'acronyme I.S.R. ?
     112{{{#!protected ------------------------------------------------------------------------------------
     113''
     114  * Interrupt Service Routine ou, en français, routine d'interruption. En fait, c'est une fonction C normale.
     115''
     116}}}
     1171. Dans la plateforme des TPs, sur quelles entrées de l'ICU sont branchées les IRQ venant des TTYs et du TIMER ?
     118{{{#!protected ------------------------------------------------------------------------------------
     119''
     120  * Les 4 IRQ de TTYs sont branchés sur les entrées `10`, `11`, `12` et `13` de l'ICU et l'IRQ du TIMER est sur l'entrée `0`.
     121''
     122}}}
     1231. Quelle valeur mettre dans le registre `ICU_MASK` si on veut recevoir seulement les IRQ venant des 4 TTYs, dans le cas de la plateforme utilisée en TP ? Donnez le nombre en binaire et en hexadécimal.
     124{{{#!protected ------------------------------------------------------------------------------------
     125''
     126  * Il faut que les bits `10`, `11`, `12` et `13` de ICU_MASK soit à 1 donc `0b00000000.00000000.00111100.00000000` donc `0x00003C00`.
     127''
     128}}}
     1291. L'écriture dans `ICU_MASK` n'est pas possible, comment modifier ce registre pour mettre à 1 le bit `0` ?
     130{{{#!protected ------------------------------------------------------------------------------------
     131''
     132  * Il faut écrire `1` dans le bit `0` de `ICU_SET`.
     133''
     134}}}
     1351. Dans quel mode est le processeur quand il traite une IRQ ?
     136{{{#!protected ------------------------------------------------------------------------------------
     137''
     138  * Le MIPS est dans le mode kernel.
     139''
     140}}}
     1411. Que fait le processeur lorsqu'il reçoit une IRQ masquée ?
     142{{{#!protected ------------------------------------------------------------------------------------
     143''
     144  * Il ne fait rien puisqu'il ne la voit pas.
     145''
     146}}}
     1471. Que signifie acquiter une IRQ et qui le demande à qui ?
     148{{{#!protected ------------------------------------------------------------------------------------
     149''
     150  * Cela signifie baisser ou désactiver le signal IRQ et c'est l'ISR qui fait cette demande au contrôleur de périphérique concerné.
     151''
     152}}}
     1531. Est-ce qu'une IRQ peut se désactiver sans intervention du processeur ?
     154{{{#!protected ------------------------------------------------------------------------------------
     155''
     156  * Non, quand une IRQ est levée, elle ne peut être désactivée que par le code de l'ISR concernée. Le contrôleur de périphérique n'a pas le droit de la désactiver tout seul.
     157''
     158}}}
     1591. Est-ce qu'une IRQ peut ne pas être attendue par le noyau ?
     160{{{#!protected ------------------------------------------------------------------------------------
     161''
     162  * Non, le noyau ne doit pas surpris par une IRQ, il doit avoir une ISR prévue. S'il doit traiter une IRQ non prévue, il affiche un message d'erreur, puis il masque cette IRQ dans l'ICU. Cela ne devrait jamais arriver.
     163''
     164}}}
     1651. Quelle est la valeur du champ `XCODE` du registre `c0_cause` à l'entrée dans le noyau en cas d'interruption ?
     166{{{#!protected ------------------------------------------------------------------------------------
     167''
     168  * Il y a `0`.
     169''
     170}}}
     1711. Quelle est la valeur écrite dans le registre `c0_EPC` à l'entrée dans le noyau en cas d'interruption ?
     172{{{#!protected ------------------------------------------------------------------------------------
     173''
     174  * C'est l'adresse de retour dans le programme interrompu.
     175''
     176}}}
     1771. Que se passe-t-il dans le registre `c0_sr` à l'entrée dans le noyau en cas d'interruption et quelle est la conséquence ?
     178{{{#!protected ------------------------------------------------------------------------------------
     179''
     180  * Le bit `EXL` passe à 1 et la conséquence est que le MIPS passe en mode kernel, toutes les sont interruptions masquées.
     181''
     182}}}
     1831. Le routine `kentry` (entrée du kernel à l'adresse `0x80000180`) appelle le gestionnaire d'interruption quand le MIPS reçoit une IRQ non masquée, que fait ce gestionnaire d'interruption ?
     184{{{#!protected ------------------------------------------------------------------------------------
     185''
     186  * Le gestionnaire d'interruption doit déterminer le numéro de l'IRQ en lisant dans le registre `ICU_HIGHEST` de l'ICU et il doit appeler la fonction ISR trouvée dans le tableau `IRQ_VECTOR_ISR[]` du vecteur d'interruption à la case du numéro de l'IRQ, en lui donnant en argument le numéro du device trouvé dans le tableau `IRQ_VECTOR_DEV[]` à la case du numéro de l'IRQ.
     187''
     188}}}
     1891. À l'entrée dans le noyau, `kentry` analyse le champ `XCODE` du registre de `c0_cause` et si c'est `0` alors il saut au code donné ci-après (ce n'est pas exactement le code que vous pouvez voir dans les fichiers source pour que ce soit plus facile à comprendre).
     190{{{#!c
     191cause_irq:
     192    addiu   $29,    $29,    -21*4       // 21 registers to save (18 temp regs + HI + LO + $31)
     193    sw      $31,    20*4($29)           // $31 because, it is lost by jal irq_handler
     194    sw      $1,     1*4($29)            // save all temporary registers including HI and LO
     195    sw      $2,     2*4($29)           
     196    [etc.]                             
     197
     198    jal     irq_handler                 // call the irq handler fontion écrite en C
     199
     200    lw      $1,     1*4($29)            // restore all temporary registers including HI and LO
     201    lw      $2,     2*4($29)
     202    [etc.]                             
     203    lw      $31,    20*4($29)           // restore also $31
     204    addiu   $29,    $29, 21*4           // restore the stack pointer
     205    eret                                // jr C0_EPC AND C0_SR.EXL <= 0
     206}}}
     207 Pourquoi, ne sauvez que les registres temporaires ?
     208{{{#!protected ------------------------------------------------------------------------------------
     209''
     210 * On doit sauver les registres temporaires parce que l'IRQ peut interrompre le programme n'importe quand et qu'il faudra revenir à l'application interrompue dans le même état donc sans perte d'information dans les registres. On ne sauve pas les registres persistants parce que ce sera à la fonction `irq_handler()` de s'en charger, si c'est nécessaire.
     211''
     212}}}
     2131. La fonction `irq_handler()` a pour mission d'appeler la bonne ISR. Dans le code qui suit (extrait du fichier `kernel/harch.c`), on voit d'abord la déclaration de la structure qui décrit les registres présents dans l'ICU. En fait c'est un tableau de structure parce qu'il y a autant d'instance d'ICU que de processeurs (donné par NCPUS), ici, il y a un seul processeur MIPS, donc NCPUS=1.
     214{{{#!c
     215struct icu_s {
     216    int state;          // state of all IRQ signals
     217    int mask;           // IRQ mask to chose what we need for this ICU
     218    int set;            // IRQ set   --> enable specific IRQs for this ICU
     219    int clear;          // IRQ clear --> disable specific IRQs for this ICU
     220    int highest;        // highest pritority IRQ number for this ICU
     221    int unused[3];      // these 3 registers are not used
     222};
     223extern volatile struct icu_s __icu_regs_map[NCPUS];
     224
     225static int icu_get_highest (int icu) {
     226    return __icu_regs_map[icu].highest;
     227}
     228
     229void irq_handler (void) {
     230    int irq = icu_get_highest (cpuid());       
     231    irq_vector_isr[irq] (irq_vector_dev[irq]);
     232}
     233
     234static void icu_set_mask (int icu, int irq) {
     235    __icu_regs_map[icu].set = 1 << irq;
     236}
     237}}}
     238 `extern volatile struct icu_s __icu_regs_map[NCPUS];` informe le compilateur que le symbole `__icu_regs_map` est défini ailleurs et que c'est un tableau de structures de type `struct icu_s`. Ainsi, `gcc` sait comment utiliser cette variable `__icu_regs_map`.
     2391. Dans quel fichier est défini `__icu_regs_map` ?
     240{{{#!protected ------------------------------------------------------------------------------------
     241''
     242  * Ce symbole est défini dans le fichier ldscript du kernel `kernel/kernel.ld`
     243''
     244}}}
     2451. Que fait la fonction `icu_get_highest` ?
     246{{{#!protected ------------------------------------------------------------------------------------
     247''
     248  * Elle lit le registre `ICU_HIGHEST` de l'ICU et rend donc le numéro de l'IRQ la plus prioritaire.
     249''
     250}}}
     2511. Si `ICU_HIGHEST` contient 10 (dans le cas de notre plateforme) que doit faire la fonction `irq_handler()`
     252{{{#!protected ------------------------------------------------------------------------------------
     253''
     254  * Si `ICU_HIGHEST` contient 10, c'est que c'est une IRQ du TTY0 et donc il faut appeler l'isr du TTY en lui passant 0 en argument.
     255''
     256}}}
     2571. Que fait la fonction `icu_set_mask (int icu, int irq)` ?
     258{{{#!protected ------------------------------------------------------------------------------------
     259''
     260  * Elle met à `1` le bit `irq` du registre `ICU_MASK` de l'ICU n°`icu` (ici `0`).
     261''
     262}}}
     263
     264
     265
     266= Exercices
     267
     268
     2691. Comment configurer l'ICU pur masquer l'IRQ connectée sur son entrée n°5 ?
     270{{{#!protected ------------------------------------------------------------------------------------
     271''
     272''
     273}}}
     274[...]
     275
     276{{{#!comment
     277
     2781. Le TIMER est le composant qui produit périodiquement des IRQ, (mettre la structure) écrivez le code d'une fonction qui active une IRQ tous les 1000 cycles.
     279{{{#!protected ------------------------------------------------------------------------------------
     280''
     281''
     282}}}
     2831. Comment configurer le noyau pour qu'il exécute une ISR nommée `x_isr()` pour un périphérique `x` dont l'IRQ est connectée à l'entrée 3 ?
     284{{{#!protected ------------------------------------------------------------------------------------
     285''
     286''
     287}}}
     2881. Pourquoi est-ce plus simple d'exécuter le traitement des interruptions en mode in-interruptible ?
     289{{{#!protected ------------------------------------------------------------------------------------
     290''
     291''
     292}}}
     2931. On a vu qu'un syscall est comme un appel de fonction, il ne garantie pas que les registres temporaires sont conservés, mais il garantit que les registres persistants le sont. est-ce que c'est pareil pour les interruptions ?
     294{{{#!protected ------------------------------------------------------------------------------------
     295''
     296''
     297}}}
     298
     299}}}
     300
     301= TME sur les interruptions.
     302
     303dans le premier TME, vous avez réalisé un petit jeux dans lequel vous deviez deviner un nombre tirer au hasard.
     304Ce jeu avait été mis dans kinit parce qu'a ce moment, il n'y avait pas encore d'application utilisateur.
     305Nous avons mis le jeu dans l'application.
     306
     307Nous vous proposons de limiter le temps pendant lequel vous pouvez jouer ?
     308
     309[...]
     310
     311