wiki:SujetTD7

ALMO TD n°7 - Gestionnaire d'Interruptions, Exceptions et Trappes

Préambule

Le but de ce TD est l'analyse du code du Gestionnaire d'Interruptions, Exceptions et Trappes (GIET) utilisé dans l'U.E. ALMO.

Segmentation de l'espace adressable

On rappelle que la plateforme matérielle définit un espace d'adressage de 4 Giga-octets (les adresses sont sur 32 bits), et que 8 segments sont définis dans cet espace, dont les adresses de base sont définies ci-dessous :

  1. le segment du code utilisateur de l'application, à l'adresse 0x00400000
  2. le segment des données de l'application, à l'adresse 0x10000000
  3. le segment de la pile d'exécution, à l'adresse 0x20000000
  4. le segment du code de reset, à l'adresse 0xBFC00000
  5. le segment du code du système, à l'adresse 0x80000000
  6. le segment des données du système, à l'adresse 0x81000000
  7. le segment des données non cachables du système, à l'adresse 0x82000000
  8. le segment des périphériques, à l'adresse 0x90000000

Suivant le nombre de périphériques présents dans la plateforme matérielle, le segment des périphériques est lui-même décomposé en plusieurs sous-segments (un par périphérique).

Les 5 derniers segments ne sont accessibles qu'en mode superviseur (adresses supérieures ou égales à 0x8000000).

Les trois segments contenant du code exécutable sont les suivants :

  • Le segment seg_reset contient le code de d'initialisation (fichier reset.s) qui s'exécute en mode superviseur au démarrage de la machine, ou lors de l'activation du signal nreset. Ses deux missions principales sont le chargement en mémoire du système d'exploitation et la configuration des périphériques. (Dans cette U.E., la phase de chargement de l'OS dans la mémoire n'est pas considérée).
  • Le segment seg_kcode contient le code qui doit s'exécuter en mode superviseur, en cas d'interruption, d'exception, ou d'appel système. Il s'agit donc du code du GIET que nous voulons analyser dans ce TD.
  • Le segment seg_code contient le code qui s'exécute en mode utilisateur, c'est-à-dire : le code de l'application logicielle (fichier main.c), et le code des appels système du côté utilisateur (fichier stdio.c).

Structure du GIET

Lorsque le processeur est en train d'exécuter une application logicielle (en mode utilisateur), il existe trois types d'événements qui peuvent l'amener à passer en mode superviseur pour se brancher au GIET, c'est à dire à l'adresse 0x80000180 :

  • Les exceptions sont généralement des erreurs de programmation, telles qu'une division par 0 ou une adresse mal formée (par exemple, la lecture d'un mot mémoire de 32 bits à une adresse non-alignée sur 4 octets, ou encore la lecture d'un mot à une adresse inexistante - non comprise dans les segments définis). Les exceptions entraînent généralement la fin du programme fautif. Typiquement, le gestionnaire d'exceptions doit déterminer le type de l'exception, et afficher un message permettant au programmeur de localiser et de corriger l'erreur. Cette classe d'événements est traitée par le gestionnaire d'exceptions (fichier exc_handler.c).
  • Les interruptions provenant de périphériques sont imprévisibles du point de vue du logiciel en cours d'exécution sur le processeur, et peuvent donc survenir à tout instant. Si une interruption n'est pas masquée, l'activation d'une ligne d'interruption matérielle déclenche l'exécution d'une routine spécifique (ISR), permettant ainsi au périphérique source de voler quelques cycles au processeur pour effectuer un traitement spécifique. L'application interrompue reprend ensuite son exécution normale. Typiquement, le gestionnaire d'interruptions doit déterminer la source de l'interruption, en interrogeant le composant ICU (concentrateur d'interruptions), afin d'exécuter l'ISR appropriée. Le processeur MIPS32 utilisé dispose de 6 entrées d'interruption matérielle, mais seule l'entrée 0 du processeur est utilisée, et il faut donc systématiquement interroger le composant ICU. Cette classe d'événements est traitée par le gestionnaire d'interruptions (fichier irq_handler.c).
  • Les trappes (ou appels système) sont des requêtes effectuées par une application logicielle utilisateur vers le système d'exploitation (au moyen de l'instruction assembleur syscall) pour demander un service, tel que l'écriture d'un caractère sur le terminal TTY, ou une écriture sur le disque dur. Les trappes s'apparentent à des appels de fonction un peu spéciaux. Il faut récupérer le numéro du service demandé (dans le registre $2), récupérer les valeurs des arguments (situés dans les registres $4, $5, $6 et $7), et enfin appeler la fonction système requise. Au besoin, le GIET peut utiliser la pile d'exécution de l'application ayant effectué l'appel système. Cette classe d'événements est traitée par le gestionnaire d'appels système (fichier sys_handler.c).

Le code du GIET contient une toute petite partie en assembleur, mais la majeure partie du code (les trois gestionnaires d'événements définis ci-dessus) est écrite en C.

La partie en assembleur est dans le fichier giet.s. Ce fichier contient le code d'analyse de la cause de l'appel GIET, et d'aiguillage vers l'un des trois gestionnaires d'événements. Il contient également la fonction de changement de contexte, _ctx_switch, utilisée quand le processeur est utilisé en mode multi-tâches. Cette fonctionnalité ne sera utilisée qu'à la fin de l'U.E. ALMO, et ne sera pas analysée dans ce TD.

1. Analyse de la cause de l'appel au GIET : fichier giet.s

Il y a 16 causes possibles, qui sont définies par les 16 valeurs possibles du champs XCODE du registre CR (Cause Register : registre 13 du coprocesseur 0).

  • Dans quelle section se trouve le code d'entrée du GIET ? Quelle est la directive qui permet de définir le nom de la section ? Comment peut-on imposer le placement de cette section dans le segment seg_kcode ?
  • Que contient le tableau_cause_vector ? Quelle taille fait-il ? Où sont définies les étiquettes qu'il contient ?

Fichier giet.s :

  • À quoi sert la directive .space 0x180 spécifiée au commencement de la section .giet et avant le début de la fonction _giet ?
  • Expliquez ce que fait chacune des 6 instructions assembleur qui composent la fonction _giet. Comment pourrait-on l'écrire en une ligne de pseudo-code ?
  • Quels registres utilise-t-on dans ce code assembleur ? Comment expliquez-vous qu'on les utilise sans sauvegarder leur contenu au préalable ?
  • Pourquoi les interruptions sont-elles automatiquement masquées par le processeur quand celui-ci se branche à la première instruction du GIET ?

2. Analyse du gestionnaire des appels systèmes : fichier sys_handler.c

  • Rappelez comment une application logicielle utilisateur fait un appel système.

Fichier giet.s :

  • La fonction _sys_handler définie dans le fichier giet.s sert à aiguiller le programme vers l'appel système approprié, en fonction du numéro de service contenu dans le registre $2. Expliquez ce que font les 6 premières instructions de cette fonction (de addiu jusqu'à sw).
  • Analysez les 5 instructions suivantes (de andi à lw) pour déterminer le nombre maximum d'appels systèmes acceptés par le GIET. Comment est obtenue l'adresse de la fonction système à exécuter pour traiter l'appel système requis ?

La compréhension des 6 instructions suivantes (de li à mtc0) nécessite une lecture attentive de la section E/6 du document MIPS32 : Architecture Externe afin de bien comprendre la signification des différents bits du registre de contrôle SR. Ces instructions notamment ont pour effet :

  • de passer le processeur en mode noyau de manière stable : bit UM à 0, bit EXL à 0.
  • de démasquer les interruptions : bit IE à 1.
  • d'appeler la fonction système demandée (instruction jal)
  • de remasquer les interruptions lorsqu'on a terminé l'exécution de l'appel système.
  • Pourquoi veut-on autoriser les interruptions pendant l'exécution d'un appel système ?
  • Que font les 6 dernières instructions (de lw à eret) ?
  • À quoi sert le registre de contrôle EPC ? Pourquoi faut-il le sauver dans la pile ?

On analyse maintenant le fichier sys_handler.c.

  • Quelle est l'utilité de la routine _sys_ukn ?
  • Où sont définies les fonctions du tableau _syscall_vector ? Quel est le point commun de toutes ces routines ?

3. Analyse du gestionnaire de traitement des interruptions : fichier irq_handler.c

  • La fonction _int_handler (définie dans le fichier giet.s), et la fonction _int_demux (définie dans le fichier int_handler.c) permettent de se brancher vers l'ISR correspondant au numéro de l'interruption. Que veut dire ISR ?
  • Que fait la fonction assembleur _int_handler ?
  • Que fait la fonction _int_demux (fichier irq_handler.c).
  • La fonction _int_demux utilise aussi une table de saut. Quel nom donne-t-on habituellement à cette table de saut ? À quel moment cette table doit-elle être initialisée ?
  • Pourquoi le gestionnaire d'interruption, _int_handler, sauve-t-il le registre $31 dans la pile ?
  • Pourquoi le gestionnaire d'interruption ne démasque-t-il pas les interruptions ?
  • La routine _isr_default est l'action par défaut appelée par le gestionnaire d'interruptions. Pourquoi faut-il définir cette ISR par défaut ?

4. Analyse du gestionnaire de traitement des exceptions : Fichier exc_handler.c

  • En quoi consiste le traitement des exceptions ?
  • Sur quel point important le traitement des exceptions diffère-t-il du traitement des interruptions ou des appels systèmes ?
Last modified 6 years ago Last modified on Nov 22, 2017, 2:38:36 PM