Autor Thema: Disabled Interrupts im User Mode  (Gelesen 15513 mal)

SuperPlus

  • Beiträge: 5
    • Profil anzeigen
Gespeichert
« am: 25. July 2011, 16:14 »
Hallo,

ich möchte Performancemessungen unter Linux im User Mode machen. Optimal wäre es, wenn während dieser Messungen die Interrupts ausgeschaltet wären. Dafür habe ich einen Trap Gate eingefügt.

ENTRY(cli_call)
     cli
     iret
END(cli_call)

Um in den Code zu springen verwende ich im User Mode den Befehl
int 0xe7

Die Interrupts sind aber immer noch aktiviert. Wird das Interrupt Flag beim Rücksprung automatisch gesetzt oder legt der Fehler in meinem Code?

Ich habe schon versucht die Interrupts mit dem VIF Flag zu deaktivieren. Dies hat aber auch nicht funktioniert. Wenn ich das Intel Manual richtig verstanden habe, ist der Interrupt Handler dafür zuständig das VIF Flag zu überprüfen und ich vermute Linux überprüft dieses Flag nicht.

Gibt es eine Möglichkeit im User Mode mit deaktivierten Interrupts zu arbeiten?

Grüße
SuperPlus

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #1 am: 25. July 2011, 16:18 »
Moin,

theoretisch dürfte es nicht funktionieren, sonst wäre Linux ein sehr unsicheres OS.
Wenn Interrupts deaktiviert sind funktioniert kein Multitasking mehr, die Uhr bleibt stehen und ähnliches Zeug.
Das ist der Grund warum cli und hlt im Usermode verboten sind.

Du musst also irgendwie eine andere Variante finden ;)

Grüße,
LittleFox

PS.: Willkommen im Forum :)

SuperPlus

  • Beiträge: 5
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 25. July 2011, 16:22 »
Danke für die schnelle Antwort.

Wenn ich einen Software Interrupt auslöse, dann bin ich doch im Kernel Mode. Dort lösche ich das IF und springe sofort wieder zurück in den User Mode. Dann müssten doch eigentlich die Interrupts deaktiviert sein.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #3 am: 25. July 2011, 16:27 »
Nein, dein Softwareinterrupt wird vom Kernel behandelt, nicht von deinem Programm. Oder schreibst du ein Modul? Wie es da ist weiß ich nicht.
Falls es ein Modul ist, den Rest einfach ignorieren ;)

Was der Kernel mit dem Interrupt macht kannst du im Sourcecode nachgucken.
Wird dein Handler überhaupt aufgerufen?

Grüße

SuperPlus

  • Beiträge: 5
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 25. July 2011, 16:36 »
Ich habe den Quellcode geändert und einen neuen Descriptor erstellt. Es ist so etwas wie ein eigener System Call.

Ich bin mir ziemlich sicher, dass der Code aufgerufen wird. Führe ich den Befehl "int 0xe7" bei einem normalen Linux aus, bekomme ich ein "Segmantaion Fault".

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 25. July 2011, 16:39 »
Hallo SuperPlus,


bei einem Interrupt wird der Status des Interuptflags auf dem Stack gesichert und am Ende wiederhergestellt. Wenn dann muss man nicht cli benutzen sondern den Wert auf dem Stack manipulieren. Ob Linux das überhaupt zulässt und ob dieser Handler nicht auf jeden Fall Teil des Kernels sein muss kann ich nicht wirklich beurteilen (raten würde ich nein und ja).

Und willkommen im Forum.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 25. July 2011, 17:03 »
Reicht für cli/sti nicht iopl() auf Ring 3?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

SuperPlus

  • Beiträge: 5
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 25. July 2011, 17:09 »
Zitat
bei einem Interrupt wird der Status des Interuptflags auf dem Stack gesichert und am Ende wiederhergestellt.

Aha. Habe gerade noch mal ins Manual geguckt. Nach dem Sprung in den Interrupt Handler sieht das Stack Layout folgendermaßen aus:
EFLAGS
CS
EIP
Error Code
Ich habe nicht sehr viel Übung in Assembler. Wenn ich nun die EFLAGS ändern möchte würde ich das folgendermaßen machen:
pop eax ; EIP
pop ebx ; CS
pop ecx ; EFLAGS
or 0x20, eax ; setze IF
push ecx
push ebx
push eax
Könnte das so funktionieren?

Ich denke ich werden den Kernel mogen kompilieren und das mal testen.

Zitat
Reicht für cli/sti nicht iopl() auf Ring 3?
Nein, dadurch wird nur das virtuelle IF gelöscht und das hat bei mir nicht funktioniert. Unter einem Echtzeitlinux wie RTAI oder Xenomai könnte das aber vielleicht funktionieren. Dies wäre mein nächster Versuch.
« Letzte Änderung: 25. July 2011, 17:12 von SuperPlus »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 25. July 2011, 17:27 »
Du hast da eine 0 vergessen und die Operation muss auf ECX ausgeführt werden. Dann könnte es funktionieren.
pop %eax ; EIP
pop %ebx ; CS
pop %ecx ; EFLAGS
or $0x200, %ecx ; setze IF
push %ecx
push %ebx
push %eax

Ich würde es übrigens einfach so machen:
orl $0x200, 8(%esp)
« Letzte Änderung: 25. July 2011, 17:42 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 25. July 2011, 20:38 »
Hallo,

bist du sicher, dass der Kernel - bei gelöschtem Interruptflag im Usermode - noch soweit funktioniert, dass ein Rücksprung möglich ist und er nicht abstürzt?

Ansonsten würde ich dir für Performancemessungen empfehlen, den betreffenden Usermodus-Task in der Priorität zu erhöhen (Echtzeitpriorität und "nice -20" für den Task) und für die Zeitstempel den TSC, soweit zuverlässig, zu benutzen. RDTSC geht auch im Usermodus.

Gruß,
Svenska

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 25. July 2011, 20:55 »
Nein, dadurch wird nur das virtuelle IF gelöscht
Auf die Gefahr hin, eine blöde Frage zu stellen: Was ist denn ein virtuelles IF?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 25. July 2011, 21:29 »
Auf die Gefahr hin, eine blöde Frage zu stellen: Was ist denn ein virtuelles IF?
Auf die Gefahr hin, eine blöde Antwort zu geben: RTFM!
SCNR

Ne, im Ernst, damit wird das IE-Flag virtualisiert so das die Programme denken sie manipulieren das tun es aber nicht in Wirklichkeit. Der Vorteil ist das man somit einige Exceptions sparen kann und bei wirklich kritischen Operationen muss dann eben der Kernel ein Bit im auf dem Stack gesicherten EFlag-Register prüfen. Aber sicherheitshalber trotzdem RTFM.
Reality is that which, when you stop believing in it, doesn't go away.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 25. July 2011, 21:38 »
Ich dachte, VIF ist das Interruptflag im VM86...

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 25. July 2011, 21:46 »
VIF kenne ich auch, aber das ist ja offensichtlich nicht gemeint.

Ich würde auch sehr gern RTFM machen, aber dazu müsste ich halt wissen, wo nachschauen. Kapitelangabe oder so wäre hilfreich.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 25. July 2011, 22:06 »
Hallo,


ich dachte immer dass das VIF im Zusammenhang mit Bit 1 vom CR4 mehr kann als nur den VM86-Mode.
Aber falls ich da vorhin völligen Quatsch geschrieben hab dann tut mir das echt Leid, offensichtlich schätze ich meine x86-Kenntnisse für besser ein als sie tatsächlich sind. :(
Für RTFM bin ich aber Heute auch zu müde.


zum eigentlichen Thema:
Die Interrupts komplett zu deaktivieren müsste zwar theoretisch gehen und Linux sollte dabei eigentlich auch nicht abstürzen o.ä. aber die feine Art ist das IMHO trotzdem nicht. Was auch immer das eigentliche Problem ist, es sollte sich doch sicher auch eine andere Lösung finden lassen.


Grüße
Erik
« Letzte Änderung: 25. July 2011, 22:09 von erik.vikinger »
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 25. July 2011, 22:34 »
Zitat
The processor only recognizes the VIF flag when either the VME flag or the PVI flag in control register CR4 is set and the IOPL is less than 3. (The VME flag enables the virtual-8086 mode extensions; the PVI flag enables the protected-mode virtual interrupts.)
IOPL hatte ich ja vorgeschlagen auf 3 zu setzen, die andere Variante geht also auch nicht.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

SuperPlus

  • Beiträge: 5
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 26. July 2011, 10:44 »
Hallo,

Zitat
Ich würde es übrigens einfach so machen:
orl $0x200, 8(%esp)
Danke für den Tipp. So habe ich es nun auch gemacht. Ich habe zwei Traps erstellt, einer löscht das IF und der andere setzt es wieder.
ENTRY(cli_call)
andl $0xFFFFFDFF, 8(%esp)
INTERRUPT_RETURN
END(cli_call)

ENTRY(sti_call)
orl $0x200, 8(%esp)
INTERRUPT_RETURN
END(sti_call)

Es scheint zu funktionieren. Zwischen den beiden Aufrufen ist jedenfalls das IF gelöscht und Linux reagiert nicht mehr. Allerdings tritt ein komischer Effekt in der Konsole auf. Diese produziert eine Menge Zeilenvorschübe.

Zitat
Ansonsten würde ich dir für Performancemessungen empfehlen, den betreffenden Usermodus-Task in der Priorität zu erhöhen
Bis jetzt habe ich das auch so gemacht. Ich habe dem Prozess einfach die höchste Priorität (99) gegeben und den Scheduler auf FIFO umgestellt. Um so länger der zu testende Code, um größer ist dann aber auch die Wahrscheinlichkeit, dass ein Interrupt auftritt. Ich möchte einfach sehen, wie groß der Unterschied zwischen den beiden Messmethoden ist.

Zitat
Ich würde auch sehr gern RTFM machen, aber dazu müsste ich halt wissen, wo nachschauen. Kapitelangabe oder so wäre hilfreich.
Im Intel Manual wird auf Kapitel "17.4 PROTECTED-MODE VIRTUAL INTERRUPTS" verwiesen. Aber wie gesagt, ich glaube es ist die Aufgabe des Interrupt Handler das VIF zu überprüfen.

Dank für eure Hilfe.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 26. July 2011, 10:58 »
Hallo,


also ob der Trap-Handler das IE-Flag löscht oder ob er dem User-Mode-Prozess das Recht gibt und dieser es selbst tut sollte in etwa auf das selbe Ergebnis hinaus laufen (wobei der zweite Weg mehr Risiken birgt da IOPL noch für andere Dinge ein Rolle spielt). Das der Linux-Kernel den EFlag-Wert auf dem Stack nicht prüft würrde ich persönlich Bug einstufen.

Trotzdem halte ich dieses Vorgehen für ungeschickt, auch wenn IMHO nichts dagegen spricht dass das zuverlässig funktionieren kann.
Von den zu erwartenden Nebenwirkungen wie stehen bleibende Uhr und Mauszeiger oder eventuellen Pufferüberläufen bei irgendwelchen HW-Komponenten (weil kein IRQ-Handler kommt um Daten abzuholen, hier sollte SMP helfen) mal abgesehen. So lange es sich nur um ein privates Experiment handelt ist das aber wohl schon in Ordnung.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 26. July 2011, 11:04 »
Im Intel Manual wird auf Kapitel "17.4 PROTECTED-MODE VIRTUAL INTERRUPTS" verwiesen. Aber wie gesagt, ich glaube es ist die Aufgabe des Interrupt Handler das VIF zu überprüfen.
Ich habe keine Ahnung, ob Linux das überhaupt benutzt, aber mit IOPL=3 spielt es jedenfalls keine Rolle.

Der Vorteil wäre halt, dass es iopl() schon gibt und man dafür den Kernel nicht patchen muss...
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 27. July 2011, 21:44 »
Ich habe den Thread gerade nur ueberflogen, aber was genau moechtest du denn messen?
Ist es ein MultiCore Rechner?
Falls ja, kannst du das Mapping der IRQs aendern.
Du kannst die CPU-Affinitaet deiner Messung auf eine CPU legen, die keine IRQs behandelt.
Dann sollte das funktieneren.
Der einzige IRQ, der dann noch kommt ist der IRQ vom Timer.
Aber du kannst dem Scheduler sagen, dass alle Threads auf die CPU mit den IRQs gebunden werden und dein Messungsthread wird auf die andere CPU gebunden. Dann hast du schon echt gute Werte.
Oder du laesst dir vom Kernel einfach die reale CPU-Zeit geben.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

 

Einloggen