Dois-je extraire le code d'erreur envoyé à la pile par certaines exceptions avant de revenir du gestionnaire d'interruptions?

StackOverflow https://stackoverflow.com/questions/491613

Question

J'ai chargé une table IDT avec 256 entrées, pointant toutes vers des gestionnaires similaires:

  • pour les exceptions 8 et 10-14, indiquez le numéro de l'exception (ces exceptions transmettent automatiquement un code d'erreur)
  • pour les autres, poussez un & "; factice &"; code d'erreur et numéro d'exception;
  • puis passez à un gestionnaire commun

Ainsi, lorsque le gestionnaire commun est entré, la pile est correctement alignée et contient le numéro d'exception / interruption, le code d'erreur (qui peut n'être qu'un factice), eflags, cs et eip.

Ma question concerne le retour du gestionnaire d'interruptions. J'utilise iret pour revenir après avoir retiré le numéro d'exception et le code d'erreur de la pile, mais cela ne fonctionne pas pour l'exception n ° 8; si je laisse le code d'erreur sur la pile, cela retourne bien!

Questions:

  • dois-je laisser le code d'erreur sur la pile pour les exceptions qui y placent le code d'erreur? Si oui, comment <=> détermine-t-il s'il doit ou non afficher un code d'erreur?
  • dès que j'active les interruptions, j'obtiens toujours une exception 8 (double faute), mais ensuite tout se passe bien (je développe un système d'exploitation hobby). Est-ce un comportement normal ou ai-je un bogue quelque part?
Était-ce utile?

La solution

Si la CPU envoie automatiquement un code d'erreur, le gestionnaire doit le faire apparaître avant le iret. L’instruction <=> ne sait pas d’où vous venez, s’il s’agit d’une faute, d’un piège ou d’une interruption externe. Il fait toujours la même chose et suppose qu’il n’ya pas de code d’erreur sur la pile.

Citations tirées du document SDM (Manuel du développeur de logiciels), volume 3, chapitre 5, section 5.13 intitulé Code d'erreur:

  

Le code d'erreur est poussé sur la pile   comme double mot ou mot (selon   l'interruption, l'interruption ou la tâche par défaut   taille de la porte). Pour garder la pile alignée   pour les doubles mots, la moitié supérieure   du code d'erreur est réservé. Remarque   que le code d'erreur n'est pas sauté quand   l'instruction IRET est exécutée pour   revenir d'un gestionnaire d'exception, donc   le gestionnaire doit supprimer le code d'erreur   avant d'exécuter un retour.

Vous pouvez trouver le Manuel du développeur de logiciels IA-32 ici : http://www.intel.com/products/processor/manuals/

Le volume 3, partie 1, chapitre 5, décrit la gestion des exceptions et des interruptions. Le volume 2, partie 1 contient les spécifications de l'instruction <=>.

Autres conseils

J'ai écrit un petit système d'exploitation x86 il y a quelque temps. Consultez le fichier isr. asm dans le référentiel cvs.

Remarquez comment nous avons configuré les gestionnaires, la plupart insérant un mot fictif factice sur la pile afin de prendre en compte les quelques gestionnaires qui obtiennent automatiquement un code d'erreur. Ensuite, lorsque nous revenons via un iret, nous pouvons toujours supposer 2 mots sur la pile, quelle que soit l’interruption, et effectuer un add esp, 8 avant le mot iret pour nettoyer les choses correctement.

Cela devrait répondre à votre première question.

En ce qui concerne votre deuxième question: une double faute lorsque vous activez les interruptions, ... hmmm peut être un problème de pagination si vous ne l’avez pas configurée correctement. Pourrait être un million d'autre chose aussi:)

J'ai eu un problème similaire avec & "; doubles fautes &"; dès que j'ai activé les interruptions. Eh bien, ils avaient l'air comme des doubles fautes, mais c'étaient vraiment des interruptions de la minuterie!

Les doubles fautes sont le numéro d'interruption 8.

Malheureusement, une configuration PIC par défaut signale des interruptions de la minuterie en tant que numéro d'interruption (DEFAULT_PIC_BASE + TIMER_OFFSET) = (8 + 0) = <=>.

Le masquage de toutes mes interruptions PIC (jusqu'à ce que je sois prêt à configurer correctement le PIC) a désactivé ces interruptions de minuterie ressemblant à deux défaillances.

(Les PIC exigent que le processeur accuse réception des interruptions avant de produire la suivante. Puisque votre code n’a pas accusé réception de l’interruption initiale du minuteur, le PIC ne vous en a jamais donné plus! aurait pu s'attendre.)

  

Dois-je laisser le code d'erreur sur la pile pour les exceptions qui y placent le code d'erreur?

Comme d'autres l'ont mentionné, vous devez soit:

pop %eax
/* Do something with %eax */
iret

Ou si vous souhaitez ignorer le code d'erreur:

add $4, %esp
iret

Si vous ne le faites pas, iret interprétera le code d'erreur comme le nouveau CS et vous risquez d'obtenir une erreur de protection générale, comme indiqué à l'adresse: Pourquoi iret d'un gestionnaire d'erreurs de page génère-t-il l'interruption 13 (erreur de protection générale) et le code d'erreur 0x18 ?

qui ne fait pas apparaître la pile.

Notez que si vous faites simplement int $14, aucun octet supplémentaire n'est poussé: cela ne se produit que sur l'exception réelle.

Manuel Intel, volume 3, Guide de programmation - 325384-056FR Septembre 2015 Tableau 6-1. " Exceptions et interruptions en mode protégé " colonne " code d'erreur " contient la liste des interruptions qui transmettent ou non le code d'erreur.

38.9.2.2 " Codes d’erreur de page " explique la signification de l'erreur.

Une bonne solution consiste à insérer un code d'erreur factice 0 sur la pile pour éviter les interruptions qui ne le font pas pour uniformiser les choses. Le tutoriel de James Molloy, arch / x86 / entry / entry64 .S , il modélise les interruptions avec has_error_code:

trace_idtentry page_fault do_page_fault has_error_code=1

et l'utilise ensuite sur le même fichier que:

.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif

qui fait le push quand has_error_code=0.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top