Autor Thema: GPF ohne Subsystems, Double Fault mit Subsystems  (Gelesen 5113 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 26. February 2011, 00:13 »
Hi zusammen,

ich habe gerade ein Problem mit meinem Kernel. Es ist mir aufgefallen, als ich Interrupts aktiviert habe und der Kernel mit einem Double Fault aussteigt. Dann habe ich erst einmal alle Subsysteme (Memory, scheduler, process-manager, etc.) auskommentiert und an sich nur noch den Code drin, der meine Konsole leert, eine Ausgabe macht und die Interrupts aktiviert. Dann taucht in einer Endlosschleife ein GPF auf. Kann mir nicht erklaeren wo der herkommt, da alle Subsysteme starten, solange die Interrupts deaktiviert sind.
Mein IDT und mein GDT sollten nicht das Problem sein, da es auch einen Double Fault gibt, wenn nur die abgeschaltet sind.

Habt ihr Ideen, die ich mal probieren kann?
Ach ja, Bochs und Qemu geben keine Aufaelligkeiten von sich.

rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 26. February 2011, 09:24 »
Hallo,


also ich würde probieren direkt als ersten Befehl im Double-Fault-Handler ein HLT zu haben und dann Bochs und Qemu auf maximale extrem Geschwätzigkeit zu stellen, das letzte was Du dort dann siehst sollte die Ursache für den Double-Fault sein oder zumindest einen Hinweis geben.


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

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 26. February 2011, 11:02 »
Das Qemu und Bochs schweigen liegt wohl daran, dass du die exceptions selbst abfängst.

Lass dir in deinem exceptionhändler (r/e)IP und Fehlercode ausgeben (auch wenn letzteres vermutlich 0 ist und dann nicht viel hilft). Und guck dir deinen Kernel an der entsprechen stelle mal an.

objdump -d kernel.elf

„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 26. February 2011, 11:54 »
Also, ich habe mir das mal angeschaut und dabei ist mir was aufgefallen, dass der Stack komisch aussehen muss (also die Registersicherung).

Hier mal mein Code:
struct cpu_dump
{
uint16_t gs __attribute__((aligned(4)));
uint16_t fs __attribute__((aligned(4)));
uint16_t es __attribute__((aligned(4)));
uint16_t ds __attribute__((aligned(4)));
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp_task;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t intr_no;
uint32_t err_code;
uint32_t eip;
uint32_t cs;
uint32_t eflags;
/* is set, if the task is a user task */
uint32_t esp_user;
uint32_t ss;
};
Bei der Ausgabe des Error-Codes gibt er mir den EIP aus und bei EIP die Interrupt-Nummer.
Der Aufruf der Registeroperationen ist aber richtig.

Der Interrupt wird in der Endlosschleife ausgeloest.
Qemu und Bochs geben keine Informationen von sich.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 26. February 2011, 14:35 »
Bei der Ausgabe des Error-Codes gibt er mir den EIP aus und bei EIP die Interrupt-Nummer.
Der Aufruf der Registeroperationen ist aber richtig.

Das ist relativ unwahrscheinlich, das das derart verdreht ist. Ist EIP eventuell nicht Int-Nr. sonder CS oder der Error-Code nicht EIP sondern EAX.

Du kannst ja mal den Registern bestimmte Werte zuweisen und dann eine Exception provozieren(jmp 0x0000 oder 0xdeadbeef oder so). und gucken ob dein wie dein stack frame verschoben ist.

Ob deine struct so funktioniert wie sie soll bin ich mir nicht 100%ig sicher. Ich hätte die segmentregister auch 32bit breit gemacht und dann alles packed(tyndur)

Aber ohne das passende gegenstück zu dem struct -- dem asm code der das stackframe erzeugt -- ist jede Aussage über die Korrektheit Glaskugellei.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 26. February 2011, 18:25 »
so, ich habe mir das mal ein wenig naeher angeschaut und dabei ist mir aufgefallen, dass es Probleme mit meinem dump gab (hatte das packed Attribut vergessen). der sieht jetzt gut aus und alle veraenderten Register werden auch richtig uebernommen. Ich provoziere nun einen Interrupt indem ich an NULL springe, leider gibt es direkt einen double fault, anstatt des page faults.
Ich habe keine Ahnung woran das liegen kann, aber mein EIP steht an 0x8, was an sich nicht vorkommen darf...
Wo kann der denn ueberall veraendert werden? Er muesste doch eigentlich den Wert des ungueltigen Sprungs haben, oder?

Edit:
Ich habe eben gesehen, dass Qemu meldet, dass ich eine DF bekomme und der EIP zeigt auf 0x0. Aber wieso ueberspringt der einen PF?

Edit die zweite:
Ich habe mal mit dem GDB versucht den Fehler zu finden, aber wenn ich den Code im Single-Step Modus ablaufe, funktioniert es einwandfrei und der richtige Interrupt kommt an.
« Letzte Änderung: 26. February 2011, 20:32 von rizor »
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 27. February 2011, 14:49 »
was mir gerade eingefallen ist...
Kann es sein, dass der PIC mir die Interrupts weiterleitet oder sind die initial alle maskiert?
Ich habe das mal versucht und alle Interrupts maskiert, dann erhalte ich eine Debug-Exception.

Gibt es eine Moeglichkeit in Bochs, dass er mir ausgibt, warum ein Interrupt ausgeloest wurde?
Habe alles auf Report gestellt und ich sehe nur ein paar Informationen ueber den PIT.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 27. February 2011, 17:21 »
Ich habe mal das Interrupt-Handling deaktiviert um zu schauen, was bochs ohne behandelte Interrupts dazu sagt.
Bochs steigt mit folgender Meldung aus:
(0).[41596453] [0x00101987] 0008:0000000000101987 (unk. ctxt): jmp .+0xfffffffe (0x00101987) ; ebfe
Next at t=41596457

Das einzige, was ich verstehe ist, dass 0x00101987 die Exception ausloest.
Das ist meine Endlosschleife am Ende der Initialisierung des Systems.
Wenn ich direkt hinter die Aktivierung der Interrupts ein int 0x80 lege, loest dieser Befehl den DF aus.
Sagt euch der Fehler noch mehr als mir?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 28. February 2011, 21:17 »
Mir sind jetzt noch ein paar Dinge aufgefallen.
Im Single-Step laeuft alles und sonst gibt mir Qemu jetzt aus, dass es eine DF gibt, der dann einen Page Fault auslaest, weil der Kernel auf Adresse 0x40 zugreifen moechte. Danach gibt es einen PF, der auf 0x70, da der Kernel auf 0x70 zugreifen will.
Das ganze macht wenig Sinn.

Hier ist der Code, der bei Interrupts angesprungen wird:
http://rizor-kernel.git.sourceforge.net/git/gitweb.cgi?p=rizor-kernel/rizor-kernel;a=blob;f=arch/i386/asm/i386_int.S;h=2382217bdf733cd971ca5d03c40f1db73af74085;hb=HEAD

Die Adressen, die in die IDT eingetragen werden sind korrekt.

Hier mein IDT-Code:
http://rizor-kernel.git.sourceforge.net/git/gitweb.cgi?p=rizor-kernel/rizor-kernel;a=blob;f=arch/i386/descriptors/idt.c;h=a68cf3c29c02f8fc835be17c8d267531587e67c6;hb=HEAD

Hier ist noch mein CPU-Dump:
http://rizor-kernel.git.sourceforge.net/git/gitweb.cgi?p=rizor-kernel/rizor-kernel;a=blob;f=arch/i386/include/i386_cpu.h;h=dc9ad0c8c6b228dd323abfd211f7f2e61efd7fd4;hb=HEAD

Seht ihr da einen Fehler?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 28. February 2011, 21:53 »
Das add $4 , %esp in i386_int.S ist falsch. Wenn dann gehört es direkt hinter den Aufruf von int_handler, aber dort ist der Befehl auch überflüssig, weil es direkt danach vom mov %eax, %esp mit dem Wert, den das Push auf dem Stack gelegt hat, überschrieben wird.

Das ist übrigens der Wert von esp vor dem push, also keine Korrektur nötig, falls das der Gedanke war.
« Letzte Änderung: 28. February 2011, 21:56 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 02. March 2011, 17:36 »
Stimmt, das loest das Problem leider nicht.
Wird ein DF nur ausgeloest, wenn vorher ein Interrupt nicht behandelt werden konnte?
Vorher wird definitiv kein anderer Interrupt ausgeloest.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 02. March 2011, 19:18 »
Ja, Double Fault passiert nur nach einer anderen Exception. Bist du ganz sicher, dass da nichts war? (qemu -d int zum Überprüfen, bochs müsste was ähnliches können) Wenn ja, dann kann es auch kein echter Double Fault sein (müsste dann auch in der Log zu erkennen sein).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 02. March 2011, 19:34 »
Es kommt nur ein Interrupt mit der ID v=0x8 (Bochs und QEMU melden das auch).
Es kann auch nur eine Exception sein, oder?
Der PIC ist doch solange deaktiviert, bis ich ihn konfiguriere, oder?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 02. March 2011, 20:28 »
PIC hat gar keinen definierten Zustand bis du ihn initialisierst. Wenn du IF=0 hast (das ist bei Multiboot vor dem ersten sti so), dann kommen keine IRQs an, sonst schon.

Interrupt 8 wäre beim Standardmapping IRQ 0, also der Timer. Gar nicht so unwahrscheinlich.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 02. March 2011, 21:47 »
Muss ich den PIC initialisieren, bevor ich die Interrupts maskieren kann?
Momentan maskiere ich alle Interrupts und bekomme jetzt den Interrupt 0xf, anstatt eines DF.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

 

Einloggen