<-Précédent Retour à l'accueil Contact : etienne"point"sauvage"at"gmail.com Suivant->
  1. Au fait, pourquoi a-t-on inventé les interruptions ?
  2. Et une interruption, c'est quoi ?
  3. Comment j'en fais ?
  4. Du PIC
    1. Du port d'entrée/sortie
    2. ICW1
    3. ICW2
    4. ICW3
    5. ICW4
    6. OCW1
    7. Fin de traitement d'interruption

    Assembleur : mode protégé - Retrouver ses interruptions

    Parce que quand même, ce n'est pas chic, c'était bien pratique, les interruptions.

  1. Au fait, pourquoi a-t-on inventé les interruptions ?
  2. C'est vrai, ça, pourquoi les interruptions ? La raison en est toute baignée de considérations calculatoires. Si le processeur devait regarder régulièrement si, par exemple, un caractère est en train d'être entré au clavier, mes pauvres enfants, on ne s'en sortirait pas et on aurait encore bien du mal à faire fonctionner un simulateur de calculette. Pour gagner énormément de temps et pour qu'aucun programmeur n'oublie de vérifier l'entrée clavier, c'est l'inverse que l'on fait : c'est le contrôleur clavier qui interrompt le processeur en lui disant : "Je ne sais pas si cela vous intéresse, mon bon ami, mais j'ai ici une touche qui vient d'être frappée." Ca, c'était pour la poésie. Dans la vraie vie, ça se passe plutôt comme "Touche. -6ème procédure. -STOP ! 6ème procédure. -6ème procédure faite. -OK, j'y retourne." Et la 6ème procédure en question, c'est l'interruption clavier. Et si un contrôleur de clavier peut appeler une interruption, alors un programme aussi. C'est ce détournement que nous avons utilisé précédemment, et c'est même prévu pour être utilisé à outrance.

  3. Et une interruption, c'est quoi ?
  4. C'est un programme, sous-programme ou routine, peu importe le nom, dont l'exécution interrompt le cours normal d'un autre programme. Un peu comme quand l'exécution automatique d'un CD se déclenche quand vous êtes en train de rédiger votre site, par exemple. On est interrompu. Cette routine a ceci de particulier qu'elle se termine par l'instruction IRET, comme Interrupt RETurn, instruction qu'on ne trouve qu'en langage assembleur (ou alors d'autres langages parfaitement exotiques). Voici donc notre première routine de gestion d'interruption : entreeInterruption : IRET. Donc, pour appeler une routine définie comme interruption, on ne peut pas utiliser CALL. Ce sera INT.

  5. Comment j'en fais ?
  6. Comme d'habitude chez nous, on va faire dans le simple, quitte à bulldozer un brin. Alors, en premier, on doit pratiquer la même chose que pour le passage en mode protégé. C'est-à-dire que l'on doit créer un IDT (Interrupt Descriptor Table), tableau de descripteurs d'interruptions, contenant, comme c'est étrange, des descripteurs d'interruption. L'instruction INT prend un opérande de 8 bits, on peut donc avoir 256 descripteurs d'interruption. Voici comment je fais :

    	mov eax, IDTBASE 				; Adresse de l'IDT
    	mov ebx, interruptionParDefaut 	; On va remplir toute la table avec l'interruption par défaut : bx contient les bits de poids faible
    	mov ecx, IDTSIZE				; Nombre de vecteurs d'interruption
    	call metInterruptionNFois
    
    	lidt [idtptr]	; charge l'idt
    	sti
    
    ;;Met l'interruption n fois dans l'idt
    metInterruptionNFois:
    	mov edx, ebx
    	shr edx, 16
    	mov [descripteurInterruption], bx	;bx contient les bits de poids faible
    	mov [descripteurInterruption + 6], dx; et dx ceux de poids fort
    	mov edi, eax
    .remplitIDTPIC:
    	mov esi, descripteurInterruption
    	movsd
    	movsd
    	loop .remplitIDTPIC
    	ret
    
    interruptionParDefaut:
    	iret
    
    idtptr:
    	dw	IDTSIZE << 3			; limite
    	dd	IDTBASE					; base
    
    descripteurInterruption:
    	dw 0, 1 * 8, INTGATE, 0
    	

    Notez l'instruction LIDT qui fait exactement la même chose que LGDT mais pour l'IDT, et le rétablissement des interruptions l'instant d'après. Notez aussi que nous travaillons en 32 bits, gloria alleluia.

  7. Du PIC
  8. Les périphériques d'un ordinateur compatible PC ne sont pas branchés directement sur le processeur. Ils sont branchés sur un élément qu'on appelle le PIC (Programmable Interruption Controller), le contrôleur d'interruptions programmable. Il y en a deux, l'un piloté par l'autre. Le pilote s'appelle le maître, l'autre l'esclave. La raison d'être du PIc est donc de déclencher des interruptions. Or, il se trouve que dans son nom, il y a "Programable", ce qui doit signifier qu'on peut faire quelques configurations. Le PIC n'étant ni la mémoire ni le processeur, pour y accéder, on va parler :

    1. Du port d'entrée/sortie
    2. Notre ordinateur ne fait pas qu'écrire et lire de la mémoire. Il interagit aussi avec des choses, qui sont des appareils électroniques. Cette interaction se fait au travers de 8 fils qui relient tous ces appareils. Le processeur peut écrire et lire sur ce port par les instructions OUT et IN. Et il écrit et lit un octet. L'adresse de l'appareil connecté est donnée en premier paramètre : il faut la connaître. Pour le PIC, il s'agit de 0x20 et 0x21 pour le maître et 0xA0 et 0xA1 pour l'esclave.

    3. ICW1
    4. C'est la première valeur à envoyer au PIC pour le configurer, notamment pour qu'il pointe vers nos interruptions. Première signifie ici le numéro d'ordre dans la séquence. C'est obligatoirement celle-là. ICW signifie Initialisation Command Word, mot de la commande d'initialisation. Voici sa structure :

      Bit76543210
      ValeurA5-A71LTIMADISNGLIC4

      Le PIC occupe deux adresses de port, ICW1 est sur la première.

      Source : http://www.thesatya.com/8259.html

      Ca va nous donner : 00010001b pour le maître, et 00010001b pour l'esclave.

      mov al, 0x11 ; Initialisation de ICW1
      out 0x20, al ; maître
      out 0xA0, al ; esclave

    5. ICW2
    6. ICW2 est sur la seconde adresse, et correspond à l'index de la première interruption dédiée au PIC dans l'IDT. Il est indiqué nécessairement après ICW1.

      %define INTERRUPTION_PIC_MAITRE 0x20
      %define INTERRUPTION_PIC_ESCLAVE 0x70
      mov al, INTERRUPTION_PIC_MAITRE ; Initialisation de ICW2
      out 0x21, al ; maître, vecteur de départ = 32
      mov al, INTERRUPTION_PIC_ESCLAVE
      out 0xA1, al ; esclave, vecteur de départ = 96

    7. ICW3
    8. Pour le PIC maître, chaque bit x mis à 1 indique que l'IRQx est utilisée par un PIC esclave. Pour l'esclave, cela indique le numéro de l'IRQ qu'il utilise chez son maître. ICW3 est sur la seconde adresse. Le standard est de mettre l'esclave sur l'IRQ2.

      mov al, 0x04 ; initialisation de ICW3
      out 0x21, al
      mov al, 0x02 ; esclave
      out 0xA1, al

    9. ICW4
    10. ICW4 est sur la seconde adresse.

      Bit76543210
      Valeur0SFNMBUFM/SAEOIMode

      Dans notre cas, ce sera donc 5 pour le maître et 1 pour l'esclave.

      mov al, 0x05 ; initialisation de ICW4
      out 0x21, al
      mov al, 0x01 ; esclave
      out 0xA1, al

    11. OCW1
    12. Notons que c'est l'ordre des opérations qui permet au PIC de comprendre de quoi on cause. Une fois l'initiation faite, on peut envoyer des OCW, Operational Command Word, mot de commande opérationelle. OCW1 est sur la seconde adresse, et détermine quelles sont les interruptions masquées. Pour utiliser toutes les interruptions :

      xor al, al ; masquage des interruptions
      out 0x21, al
      out 0xA1, al

    13. Fin de traitement d'interruption
    14. Lorsqu'un PIC déclenche une interruption, il faut lui dire qu'elle s'est bien passée. Il y a 8 interruptions par PIC, que l'on va traiter ainsi : interruptionPICParDefaut:
      mov al,0x20 ; EOI (End Of Interrupt)
      out 0x20,al ; qu'on envoie au PIC
      iret
      Avant de quitter l'interruption, si elle a été déclenchée par un PIC, on écrit sur le port 0x20 l'octet 0x20, qui signifie "fin de l'interruption" et qui s'appelle EOI.

    Une fois tout ceci fait, on a des interruptions que l'on peut utiliser. Malheureusement, il n'y a rien dedans.