Autor Thema: Fehler bei GDT: Triple fault  (Gelesen 4441 mal)

errorM

  • Beiträge: 2
    • Profil anzeigen
Gespeichert
« am: 02. October 2008, 16:00 »
Hallo,
ich bin gerade dabei, die GDT zu initialisieren (verwende GRUB, bin also schon im 32bit-Modus). Compiler/Linker meldet auch keinen Fehler. Wenn ich den Kernel dann aber in QEMU starte, bekomme ich einen Triple Fault gemeldet und das Programm beendet sich. Die exakte Fehlermeldung sieht folgendermaßen aus:
qemu: fatal: triple fault
EAX=001f0010 EBX=0002cfe0 ECX=0000000f EDX=001fffae
ESI=0002d147 EDI=0002d14c EBP=001fff68 ESP=001fff5c
EIP=0010066b EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300
CS =0008 00000000 ffffffff 00cf9a00
SS =0010 00000000 ffffffff 00cf9300
DS =0010 00000000 ffffffff 00cf9300
FS =0010 00000000 ffffffff 00cf9300
GS =0010 00000000 ffffffff 00cf9300
LDT=0000 00000000 0000ffff 00008000
TR =0000 00000000 0000ffff 00008000
GDT=     f200ffff 00000027
IDT=     00000000 000003ff
CR0=60000011 CR2=00000000 CR3=00000000 CR4=00000000
CCS=00000028 CCD=001fffd6 CCO=ADDL   
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
Aborted

Ich vermute stark, dass es daran liegt, dass ich die von GRUB bereitgestellte GDT irgendwie falsch überschreibe. Irgendwo habe ich mal gelesen, dass man dann einen Triple Fault gemeldet bekommt und der Kernel abstürzt. Leider stand da nicht, wie man es beheben kann.

Die Funktion zum Laden der GDT sieht so aus:
global setup_gdt

setup_gdt:
mov eax,[esp + 4]
lgdt [eax]

mov ax,0x10
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
jmp 0x08:.ret

.ret
ret
(Als Sprache benutze ich aber C++, diese Funktion wird nur aus einem C++-Programm aufgerufen.) Compiler ist gcc/g++, Assembler nasm und Linker ld.

Der Code für die Struktur eines GDT-Eintrages:
struct gdt_entry_t
{
u_word base_1;
u_word size_1;
byte base_2;
byte access;
byte size_2;
byte base_3;
}__attribute__((packed));
und für den GDT pointer:
struct gdt_pointer_t
{
u_word limit;
u_dword base;
}__attribute__((packed));
« Letzte Änderung: 02. October 2008, 16:14 von errorM »

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #1 am: 02. October 2008, 19:02 »
Wie sehen denn deine Deskriptoren aus? Stimmt den die Adresse in [esp + 4]? Stimmt die Adresse deiner GDT mit dem was qemu beim dump anzeigt überein? Hast du ein [bits 32] vor deinem Assemblercode? Wo genau geht es denn überhaupt in die Hose (beim lgdt, bei dem 0x10 Deskriptor oder beim Jump mit dem 0x08)? Gut zu wissen wäre auch welche Exception qemu als erstes auslöst (Kommandozeilenoption "-d int" iirc, danach ins qemu log schauen). Du kannst auch mal mit dem bochs-Debugger versuchen weiterzukommen. bochs an sich hat auch teilweise bessere Fehlermeldungen, was solche Sachen angeht (evtl. das Logging für CPU0 überall auf 'report' setzen in dem Textmodusinterface von bochs).
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

errorM

  • Beiträge: 2
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 03. October 2008, 17:02 »
Der Triple Fault wird bei der Ausführung das lgdt-Befehls gemeldet. Ich bin mir aber zu 99% sicher, dass der Fehler nicht im Assembler-Part liegt.
Die GDT-Einträge und der Zeiger sind bei mir Klassenelemente, aber das sollte keine Rolle spielen, da sie ja trotzdem als zusammenhängende Speicherbereiche stehen.

Die Funktion, die einen GDT-Eintrag setzt, sieht folgendermaßen aus:
inline void GDT::set_entry(byte numb,u_dword base,u_dword size,byte access,byte granularity)
{
//move bits...
this->entries[numb].base_1 = (base & 0xFFFF);
this->entries[numb].base_2 = (base >> 16) & 0xFF;
this->entries[numb].base_3 = (base >> 24) & 0xFF;

this->entries[numb].size_1 = (size & 0xFFFF);
this->entries[numb].size_2 = (size >> 16) & 0x0F;

this->entries[numb].size_2 |= granularity & 0xF0;
this->entries[numb].access = access;
return;
}
Der Setup-Code ist der hier:
void GDT::init(void)
{
this->set_entry(0,0,0,0,0);//Null entry
this->set_entry(1,0,0xFFFFFFFF,0x9A,0xCF);//kernel code segment
this->set_entry(2,0,0xFFFFFFFF,0x92,0xCF);//kernel data segment
this->set_entry(3,0,0xFFFFFFFF,0xFA,0xCF);//user code segment
this->set_entry(4,0,0xFFFFFFFF,0xF2,0xCF);//user data segment
return;
}

Der Konstruktor der Klasse:
GDT::GDT(void)
{
//set pointer
this->pointer.limit = (sizeof(gdt_entry_t) * 5) - 1;
this->pointer.base = (u_dword)&entries;

this->init();
setup_gdt((u_dword)&this->pointer);
}

 

Einloggen