Assembleur Intel avec NASM


précédentsommairesuivant

IX. Assembleur : mode protégé - Retrouver ses interruptions

49 commentaires Donner une note à l'article (5)

Relu par ClaudeLELOUP.

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

IX.1. Au fait, pourquoi a-t-on inventé les interruptions ?

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. -6e procédure. -STOP ! 6e procédure. -6e procédure faite. -OK, j'y retourne." Et la 6e 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.

IX.2. Et une interruption, c'est quoi ?

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.

IX.3. Comment j'en fais ?

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'interruption, 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 :

 
Sélectionnez

				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.

IX.4. Du PIC

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 (Programable Interruption Controller), le contrôleur d'interruption 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 :

IX.4.a. Du port d'entrée/sortie

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.

IX.4.b. ICW1

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 :

Bit 7 6 5 4 3 2 1 0
Valeur A5-A7 1 LTIM ADI SNGL IC4
  • IC4: 0 = Pas de ICW4, 1 = ICW4 requis.
  • SNGL: 1 = Un seul PIC, 0 = D'autres PIC sont montés en cascade.
  • ADI: Intervalle d'adressage. Utilisé uniquement dans les 8085, pas dans les 8086 (donc pas pour nous).
  • LTIM: Mode de déclenchement des interruptions: 1 = toutes les lignes de requête d'interruption sont déclenchées par niveau. 0 = elles sont déclenchées par front. Pour nous, 0 c'est bien.
  • A5-A7: Utilisé uniquement dans les 8085.

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.

 
Sélectionnez

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

IX.4.c. ICW2

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.

 
Sélectionnez

			?fine INTERRUPTION_PIC_MAITRE 0x20
			?fine 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
			

IX.4.d. ICW3

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.

 
Sélectionnez

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

IX.4.e. ICW4

ICW4 est sur la seconde adresse.

Bit 7 6 5 4 3 2 1 0
Valeur 0 SFNM BUF M/S AEOI Mode
  • SFNM: 1 = Special Fully Nested Mode, 0 = Fully Nested Mode. Pas de spécial pour moi, merci.
  • M/S: 1 = Maître, 0 = eSclave
  • AEOI: 1 = Auto End of Interrupt (fin automatique d'interruption), 0 = Normal.
  • Mode: 0 = 8085, 1 = 8086

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

 
Sélectionnez

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

IX.4.f. OCW1

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érationnelle. OCW1 est sur la seconde adresse, et détermine quelles sont les interruptions masquées. Pour utiliser toutes les interruptions :

 
Sélectionnez

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

IX.4.g. Fin de traitement d'interruption

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 :

 
Sélectionnez

			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.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2011 Etienne Sauvage. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.