[Kos-dev] Double fault : ca continue

Christophe Avoinne kos-dev@enix.org
Sun, 17 Jun 2001 21:20:56 +0200


Désolé les gars, je ne vous ai plus donné signe de vie en raison du fait que
je ne puis plus relever du courrier chez moi puisque mon ordinateur me fait
des misères : j'ai beau installé Windows 98 SE, Me ou 2K ou même Linux, ma
machine a des problèmes récurrents d'accès aux fichiers ou d'écriture qui
font que je ne parviens pas à installer une version "clean" d'un OS. Bref...
la haine...

Si bien que j'ai fini pas squatter depuis ce soir l'ordinateur de mon père
pour relever mon courrier qui n'a pas cessé de grossir depuis plusieurs
semaines. Il était temps...

Voilà, voilà...

Je vois que vous avez continué sur le #DF et les problèmes liés aux IRQs.

Dans le TSS système, vous trouverez toujours le EIP et ESP du code
interrompu (que ce soit de celui de l'IRQ ou non).

Pluisieurs cas possibles:

1) Sans qu'il y ait d'IRQ, le code a provoqué un #DF en raison d'un #PF dans
la pile : on a le ESP et EIP dans le TSS système -> OK.

2) La pile est arrivée à sa limite de sorte qu'un IRQ provoque un #DF car il
ne peut empiler dans la pile le CS:EIP, l'EFLAGS ni le SS:ESP (cas d'un code
CPL3 interrompu) : a-t-on le ESP et EIP du code interrompu dans le TSS
système et non celui de l'IRQ ? je gage que oui et c'est tant mieux car dans
le cas contraire on ne saurait pas en mesure de revenir après l'IRQ au code
interrompu. [Je vois que Thomas vient de nous confirmer ce point et c'est
tant mieux !]

3) Même situation qu'en 2) sauf que l'IRQ n'a pu empilé qu'une partie du
CS:EIP, EFLAGS du code interrompu : même remarque qu'en 2). Toutefois, qu'en
est-il de la valeur exact de cet ESP sauvegardé ? contient-il la valeur
AVANT ou APRES l'empilade avortée ? évidemment, il serait bien que ce soit
AVANT car on n'aura pas d'incertitude lié au nombre d'empilade impliicte
réussie ou non par l'IRQ. [Thomas, peux-tu me confirmer ça ? en faisant
pointer l'ESP juste quelques mots avant la limite conduisant au #DF si ce
n'est pas déjà fait ? en tout cas juste assez pour que CS:EIP soient
empilable et pas EFLAGS].

4) L'IRQ prend effet mais provoque finalement un #DF : même situation que
dans la cas 1), pas de besoin d'émuler quoi que ce soit. Ce cas est donc
aussi simple que pour le cas 1).

Une remarque : pour le passage du CPL3 en CPL0, il n'est pas envisageable
qu'un IRQ fasse un #DF. Pourquoi ? parce que lorsque l'on passe du CPL0 à
CPL3, la pile CPL0 devrait avoir suffisamment de la place pour permettre au
moins plusieurs niveaux d'imbrication d'appel de fonctions. Par ailleurs, le
passage CPL3->CPL0 utilise le champs ESP0 de la TSS système qui est fixe et
qui devrait laisser une marge confortable. Donc pour un peu que le IRQ ne
soit pas trop gourmand en pile, vous ne devriez jamais avoir le cas 2) ni le
cas 3). Ma conclusion est donc qu'il devrait être impossible lors d'un
passage CPL3 à CPL0 d'avoir un #DF :

- le ESP0 du champs TSS système doit fournir une pile ayant au moins le
nombre de mots nécessaires pour permettre l'empilade implicite des CS:EIP,
EFLAGS et SS:ESP par un IRQ. Cette condition nous assure de ne jamais avoir
les cas 2) et 3) quand le code interrompu est en CPL3.
- Pour un code interrompu en CPL3, seul un SYSCALL pourrait être l'auteur
d'un #DF. Mais c'est la valeur d'ESP0 une fois en CPL0 qui sera prise pour
l'ESP du SYSCALL. Or si on applique les mêmes conditions que pour les IRQ,
la cas 1) est impossible.
- A-t-on des IRQ en CPL3 ? non ? alors le cas 4) n'existe pas pour un code
interrompu en CPL3.


----- Original Message -----
From: Thomas Petazzoni <thomas.petazzoni@meridon.com>
To: <kos-dev@enix.org>
Sent: Friday, June 15, 2001 10:24 AM
Subject: [Kos-dev] Double fault : ca continue


> - Lorsque le double fault a lieu pendant les push implicites servant
> <E0>
> lancer le handler d'IRQ incrimine, les valeurs sauvegardees dans le TSS
> sont celles de la tache interrompue. Le EIP correspond donc a
> l'instruction qui a ete interrompue, et le ESP correspond a l'adresse de
> la pile, avant que le premier push implicite soit effectue. Dans ce cas,
> au niveau du handler de double fault, on a (irr_master != 0 || irr_slave
> != 0, avec irr le registre qu'on peut lire sur le port 0x20 ou 0xA0, et
> qui donne les IRQ en cours) et get_hw_isr_nested_level=0.

Parfait, c'est une bonne nouvelle : je craignais que les ports 0x20 et 0xA0
ne donnaient pas les masques des interruptions en attente AVANT l'exécution
de leur handlers. Finalement, c'est logique qu'ils le fasse avant car le PIC
est toujours le premier au courrant d'un événement par rapport au CPU :-).

> Et l'action a
> realiser est de modifier le TSS pour que le retour a la fin du DF se
> fasse dans le handler d'IRQ, et de modifier la pile pour que le IRET de
> fin du handler d'IRQ fasse retourner dans la tache interrompue. C'est
> bricolage, mais c'est le seul moyen pour ne pas rater des IRQ :)

Si on est dans le cas 2) ou 3), on réalise quelque chose dans ce genre (pas
sûr de l'ordre !) :

  *(tss_system->esp--) = tss_system->eflags;
  *(tss_system->esp--) = tss_system->cs;
  *(tss_system->esp--) = tss_system->eip;
  tss_system->eip = irq_handler[irq_num];
  tss_system->eflags &= <le masque qu'il faut>;

  etc.

Je pars du principe que je m'assure les conditions nécessaires pour qu'un
#DF avec un code CPL3 interrompu (donc pas SS:ESP à empiler) soit
impossible. Quant à irq_num, il se détermine par l'interruption la plus
prioritaire dont le bit est à 1 dans irr_master ou irr_slave.

le cas 1) et 4) n'ont strictement rien à faire.

>
> - Lorsque le double fault a lieu pendant l'execution du handler d'IRQ,
> et bien les valeurs du TSS pointent vers une adresse dans le handler,
> donc il suffit de corriger la pile, et de faire Iret pour revenir a
> l'execution du handler. Ce cas est detectable par (irr_master != 0 ||
> irr_slave != 0) avec get_hw_isr_nested_level=1.
>

Tout à fait exact ! c'est le cas 4)

>  Comment ca va se passer quand les IRQ commenceront a s'imbriquer, les
> regles get_hw_isr_nested_level=0 ou 1, faudra changer de facon de faire.
> Il faudra a mon avis comparer le nombre de bits a 1 dans les deux
> registres IRR et le get_hw_isr_nested_level.

Tant que vous ne changez pas la priorité des IRQ, vous n'aurez qu'a faire un
"bsf" sur l'irr_master pour obtenir le plus prioritaire. Si c'est le bit 2,
ben faîtes un "bsf" sur l'irr_slave et vous obtenez le plus prioritaire.

Est-il possible qu'un autre IRQ ait lieu dans un IRQ ? c'est à vous de voir
!

Si c'est le cas, ne faîtes pas de EOI de type 0x20 (tous les IRQ sont
libérés) mais de type 0x60+(irq_num%8) pour libérer l'IRQ irq_num seulement
! sinon vous aurez un irr_master et irr_slave qui ne rendront pas compte.

D'ailleurs, vous pouvez avoir des IRQ dans votre TSS_DF ???

> > Quand au probleme que tu m'avais soumis d2, concernant la chronologie
> des interruptions, il est normal que l'irq 0 soit executee avant l'irq 2
> (etant donne les priorites). Donc je pense qu'il n'y a pas de probleme
> (cf notre discussion icq de jeudi matin, vers 11h30-12h).
>

A la prochaine