Changes between Version 9 and Version 10 of Archi-1-TD11


Ignore:
Timestamp:
Nov 17, 2023, 2:11:55 PM (19 months ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TD11

    v9 v10  
    2222
    2323
     24
    2425= Rappel de cours
    2526
    26 Il est fortement recommandé de lire les transparents, toutefois, mais nous avons mis ci-après quelques rappels utiles pour répondre aux questions du TD.
    27 
    28 Dans cette séance, nous allons manipuler 3 contrôleurs de périphériques: Le TTY que vous connaissez déjà et deux autres, l'ICU et le TIMER. Ces trois contrôleurs s'utilisent grâce à des registres mappés (placés) dans l'espace d'adressage du MIPS. Les registres du TTY sont placés à partir de l'adresse `0xd0200000`, ceux de l'ICU à partir de l'adresse `0xd2200000` et enfin ceux du TIMER à partir de l'adresse `0xd3200000`. Le rôle de ces registres est rappelé en partie dans ce texte et pour plus de détails, vous devez revoir le cours.
    29 Le choix des adresses de ces contrôleurs est fait par le créateur du matériel, elles ne peuvent pas être changées par le logiciel. Ces adresses sont données dans le fichier ldscript du kernel (`kernel.ld`) parce qu'elles ne sont utilisables que si le MIPS est en mode kernel (adresses > `0x80000000`).
     27
     28
     29Il est fortement recommandé de lire les transparents, toutefois, nous avons mis ci-après quelques rappels utiles pour répondre aux questions du TD.
     30
     31== Contrôleurs de périphériques
     32
     33- Dans cette séance, nous allons manipuler 3 contrôleurs de périphériques: le TTY que vous connaissez déjà et deux autres, l'ICU et le TIMER.
     34- Ces trois contrôleurs s'utilisent grâce à des registres mappés (c.-à-d. placés) dans l'espace d'adressage du MIPS.
     35  - Les registres du TTY sont placés à partir de l'adresse `0xd0200000`,
     36  - ceux de l'ICU à partir de l'adresse `0xd2200000`
     37  - et enfin ceux du TIMER à partir de l'adresse `0xd3200000`.
     38- Le rôle de ces registres est rappelé en partie dans ce texte et pour plus de détails, vous devez revoir le cours.
     39- Le choix des adresses de ces contrôleurs est fait par le créateur du matériel, elles ne peuvent pas être changées par le logiciel.
     40- Ces adresses sont données dans le fichier ldscript du kernel (`kernel.ld`) parce qu'elles ne sont utilisables que si le MIPS est en mode kernel (adresses > `0x80000000`).
    3041
    3142[[Image(htdocs:img/device_registers.png,nolink,center,height=140)]]
    3243
    33 Les 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). La demande d'acquittement est spécifique à chaque contrôleur de périphérique. Pour le TTY, il faut lire le registre `TTY_READ`. Pour le TIMER, il faut écrire dans le registre `TIMER_RSTIRQ`.
    34 
    35 Les 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.
    36 
    37 Sur le schéma de la plateforme des TP, on peut voir que seuls les composants TTY et TIMER 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== IRQ et ISR
     45
     46- Les IRQ (Interrupt !ReQuest)s sont des signaux électriques à 2 états (ON/OFF ou !Actif/Inactif ou encore !Levé/Baissé).
     47- 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.).
     48- 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.
     49- Les IRQ provoquent donc l'exécution d'ISR (Interrupt Service Routine) par le noyau.
     50- Les 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.
     51- Les ISR sont des fonctions qui reçoivent en argument un identifiant du contrôleur de périphérique qui a levé l'IRQ.
     52- 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.
     53- Une ISR doit faire deux choses,
     54  1. accéder aux registres du contrôleur de périphérique concerné pour faire ce que le périphérique demande
     55  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).
     56- La demande d'acquittement est spécifique à chaque contrôleur de périphérique.
     57  - Pour le TTY, il faut lire le registre `TTY_READ`.
     58  - Pour le TIMER, il faut écrire dans le registre `TIMER_RSTIRQ`.
     59
     60== Routage et masquage des IRQ
     61
     62- Sur le schéma de la plateforme des TP, on peut voir que seuls les composants TTY et TIMER peuvent lever des IRQ.
     63- 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.
    3864
    3965[[Image(htdocs:img/Archi_TP11.png,nolink,center,height=230)]]
    4066
    41 Une 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.
     67- Une IRQ peut être masquée, c'est-à-dire que le processeur ne va pas interrompre le programme en cours.
     68- Le masquage peut être demandé à plusieurs endroits : dans le composant ICU et dans le processeur lui-même.
     69- 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.
    4270
    4371[[Image(htdocs:img/IRQ_routage.png,nolink,center,height=200)]]
    4472
    45 Sur le schéma ci-dessus, on voit que l'IRQ du TTY0 est reliée à 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 prioritaire, pour cette ICU, est l'IRQ active dont le numéro est le plus petit). L'IRQ de l'ICU est reliée à 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 un dernier `AND` avec le bit `0` de `c0_status` (correspondant au bit `IE` pour Interrupt Enable) qui permet de masquer globalement les IRQ et avec le `NOT` du bit `1` de `c0_status` (correspondant au bit `EXL` EXception Level).
     73- Sur le schéma ci-dessus, on voit que l'IRQ du TTY0 est reliée à 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`.
     74- 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).
     75- 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 prioritaire, pour cette ICU, est l'IRQ active dont le numéro est le plus petit).
     76- La sortie IRQ de l'ICU est reliée à l'entrée `0` des 6 IRQs possibles du MIPS et sa valeur s'inscrit dans le registre `HWI0` du registre `c0_cause`.
     77- 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.
     78- Enfin, il y a un dernier `AND` avec le bit `0` de `c0_status` (correspondant au bit `IE` pour Interrupt Enable) qui permet de masquer globalement les IRQ et avec le `NOT` du bit `1` de `c0_status` (correspondant au bit `EXL` EXception Level).
    4679
    4780Quand le signal IRQ vue par le MIPS s'active (passe à 1), c'est que l'IRQ levée par le contrôleur de périphérique doit être prise en charge. Le programme en cours d'exécution est interrompu et dérouté vers `kentry` à l'adresse `0x80000180` et __en même temps__ `C0_EPC ← PC+4`, `c0_cause.XCODE ← 0`, `c0_status.EXL ← 1`. Notez que le nom officiel de `c0_status` est `C0_SR`, mais dans ce document, on utilise `c0_status` pour plus de clarté.
    4881
    49 Dans le schéma ci-après, à 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 pour la gestion des IRQ.
    50 
    51 - À 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`.\\\\
    52 - À droite, il y a les deux tableaux que le noyau utilise pour connaitre l'ISR à exécuter pour chaque numéro d'IRQ. Ce couple de tableaux se nomme **vecteur d'interruption** et comme il y a 32 entrées d'IRQ dans l'ICU, ces tableaux ont 32 cases chacun. Ici, le vecteur d'interruption 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 à 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 effet, il y a une fonction ISR unique à exécuter quel que 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 les valeurs `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs.
     82== Conséquence dans le noyau
     83
     84- Dans le schéma ci-après, à 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 pour la gestion des IRQ.
    5385
    5486[[Image(htdocs:img/IRQ_VECTOR.png,nolink,center,height=200)]]
    5587
    56 Enfin, nous rappelons les 3 registres du coprocesseur système (`c0`) qui sont utilisés au moment de l'entrée dans le noyau, quelle que 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 rappelle aussi que les seules instructions qui peuvent manipuler ces registres sont `mtc0` et `mfc0` pour, respectivement, les écrire et les lire.
     88- À 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.
     89  - 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.
     90  - Notez que le registre `ICU_MASK` est en lecture seule, 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` dans le bit `j` du registre `ICU_CLEAR`.
     91
     92- À droite, il y a les deux tableaux que le noyau utilise pour connaitre l'ISR à exécuter pour chaque numéro d'IRQ.
     93  - Ce couple de tableaux se nomme **vecteur d'interruption** et comme il y a 32 entrées d'IRQ dans l'ICU, ces tableaux ont 32 cases chacun.
     94  - Ici, le vecteur d'interruption est composé des tableaux `IRQ_VECTOR_ISR[]` et `IRQ_VECTOR_DEV[]`.
     95  - Le vecteur d'interruption est indexé par les numéros d'IRQ. Il contient deux informations:
     96    1. dans la case n°`i` du tableau `IRQ_VECTOR_ISR[]`, on trouve le pointeur sur la fonction ISR à appeler si l'IRQ n°`i` est levée
     97    2. dans la case n°`i` du tableau `IRQ_VECTOR_DEV[]`, on trouve le numéro de l'instance du périphérique.
     98  - 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.
     99  - En effet, il y a une fonction ISR unique à exécuter quel que 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 les valeurs `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs.
     100
     101== Rappel sur les 3 registres du coprocesseur 0 impliqués
     102
     103- Nous rappelons ci-après les 3 registres du coprocesseur `0` utilisés au moment de l'entrée dans le noyau, quelle que 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).
     104- On rappelle aussi que les seules instructions qui peuvent manipuler ces registres sont `mtc0` et `mfc0` pour, respectivement, les écrire et les lire.
    57105
    58106[[Image(htdocs:img/C0_registers.png,nolink,center,height=250)]]
    59107
    60 Les 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, et les interruptions sont masquées.
     108- Les 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.
     109- Les bits `UM`, `IE` et `EXL` sont liés au mode d'exécution du MIPS:
     110  - `UM` est le bit de mode du MIPS (`1`=`User Mode`, `0`=`Kernel Mode`),
     111  - `IE` est le bit de masque général des interruptions (`1`=autorisées, `0`=masquées)
     112  - 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, et les interruptions sont masquées.
    61113
    62114